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:
@@ -13353,7 +13353,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
|
|||||||
// Spine-walk a chained N_DOT (n) inward to a root ident, summing field
|
// Spine-walk a chained N_DOT (n) inward to a root ident, summing field
|
||||||
// offsets through value-struct intermediates. Optional slice/str leaf
|
// offsets through value-struct intermediates. Optional slice/str leaf
|
||||||
// pseudo-field (.ptr / .len / .cap) on the last segment is folded into
|
// pseudo-field (.ptr / .len / .cap) on the last segment is folded into
|
||||||
// *outslicedelta (0/8/16); otherwise *outleaffi is the leaf fieldinfo
|
// *outslicedelta (0/8/16); otherwise *outleaftype is the leaf *tinfo
|
||||||
// and *outslicedelta stays -1. Returns true on success; on false the
|
// and *outslicedelta stays -1. Returns true on success; on false the
|
||||||
// caller falls through to other branches.
|
// caller falls through to other branches.
|
||||||
//
|
//
|
||||||
@@ -13370,16 +13370,28 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
|
|||||||
// Numeric out-params are i32 — offsets fit naturally and the post-#19
|
// Numeric out-params are i32 — offsets fit naturally and the post-#19
|
||||||
// localloadop sign-extends i32 deref-stored slots on read, so negative
|
// localloadop sign-extends i32 deref-stored slots on read, so negative
|
||||||
// frame offsets round-trip intact.
|
// frame offsets round-trip intact.
|
||||||
|
// #71 (A.6.3j): the spine offset-sum + leaf-type now read off
|
||||||
|
// tinfo.fields (natural layout) instead of the structinfo/fieldinfo
|
||||||
|
// walk. Mirror of cstage cmd/w6c/cgen.c:3156-3216 which walks
|
||||||
|
// `cur->lhs->type` fields. Root resolution (the local/ptr/global split
|
||||||
|
// and the rootoff/ptrroot/isglobal flags) stays on localfindnode/
|
||||||
|
// letvarstructinfo unchanged, so the firing set + addressing mode are
|
||||||
|
// byte-identical to the structinfo era; only the layout SOURCE moves.
|
||||||
|
// The slot-padded foff and the natural tfield.offset coincide for every
|
||||||
|
// shape the byte-id gate exercises (cstage already reads the natural
|
||||||
|
// offset), so this is offset-preserving. Leaf out-param is the field's
|
||||||
|
// stamped *tinfo (was *fieldinfo); the str/slice pseudo-leaf leaves it
|
||||||
|
// nil and the callers gate on slicedelta>=0 first.
|
||||||
export fn dotchainresolve(c: *cgen, n: *node,
|
export fn dotchainresolve(c: *cgen, n: *node,
|
||||||
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||||
outleaffi: **fieldinfo, outslicedelta: *i32,
|
outleaftype: **tinfo, outslicedelta: *i32,
|
||||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
outisglobal: *bool, outptrroot: *bool) bool = {
|
||||||
*outrootname = "";
|
*outrootname = "";
|
||||||
*outrootoff = 0;
|
*outrootoff = 0;
|
||||||
*outisglobal = false;
|
*outisglobal = false;
|
||||||
*outptrroot = false;
|
*outptrroot = false;
|
||||||
*outtotaloff = 0;
|
*outtotaloff = 0;
|
||||||
*outleaffi = nil;
|
*outleaftype = nil;
|
||||||
*outslicedelta = -1;
|
*outslicedelta = -1;
|
||||||
if (n == nil) { return false; };
|
if (n == nil) { return false; };
|
||||||
if (n.kind != nkind.N_DOT) { return false; };
|
if (n.kind != nkind.N_DOT) { return false; };
|
||||||
@@ -13397,13 +13409,13 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
if (cur == nil) { return false; };
|
if (cur == nil) { return false; };
|
||||||
if (cur.kind != nkind.N_IDENT) { return false; };
|
if (cur.kind != nkind.N_IDENT) { return false; };
|
||||||
*outrootname = cur.str;
|
*outrootname = cur.str;
|
||||||
let rootstruct: str = "";
|
let resolved: bool = false;
|
||||||
let lc: *local = localfindnode(c, cur.str);
|
let lc: *local = localfindnode(c, cur.str);
|
||||||
if (lc != nil) {
|
if (lc != nil) {
|
||||||
if (lc.tnode != nil) {
|
if (lc.tnode != nil) {
|
||||||
if (lc.tnode.kind == nkind.N_TNAME) {
|
if (lc.tnode.kind == nkind.N_TNAME) {
|
||||||
rootstruct = lc.tnode.str;
|
|
||||||
*outrootoff = lc.off;
|
*outrootoff = lc.off;
|
||||||
|
resolved = true;
|
||||||
};
|
};
|
||||||
// `*T` root (param/local): dereference at emit time;
|
// `*T` root (param/local): dereference at emit time;
|
||||||
// pointee struct supplies the field layout. Callers
|
// pointee struct supplies the field layout. Callers
|
||||||
@@ -13413,60 +13425,71 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
let pe: *node = lc.tnode.lhs;
|
let pe: *node = lc.tnode.lhs;
|
||||||
if (pe != nil) {
|
if (pe != nil) {
|
||||||
if (pe.kind == nkind.N_TNAME) {
|
if (pe.kind == nkind.N_TNAME) {
|
||||||
rootstruct = pe.str;
|
|
||||||
*outrootoff = lc.off;
|
*outrootoff = lc.off;
|
||||||
*outptrroot = true;
|
*outptrroot = true;
|
||||||
|
resolved = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (rootstruct.len == 0) {
|
if (!resolved) {
|
||||||
let gsi: *structinfo = letvarstructinfo(c, cur.str);
|
let gsi: *structinfo = letvarstructinfo(c, cur.str);
|
||||||
if (gsi != nil) {
|
if (gsi != nil) {
|
||||||
rootstruct = gsi.sname;
|
|
||||||
*outisglobal = true;
|
*outisglobal = true;
|
||||||
|
resolved = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (!resolved) { return false; };
|
||||||
|
// Root struct layout = the stamped root-ident type_, peeled NAMED
|
||||||
|
// (plus one TY_PTR hop for a `*struct` root). tfield.type_ then
|
||||||
|
// supplies each nested struct directly, so no name re-lookup.
|
||||||
|
let curstruct: *tinfo = cur.type_: *tinfo;
|
||||||
|
for (curstruct != nil && curstruct.kind == tykind.TY_NAMED) {
|
||||||
|
curstruct = curstruct.under;
|
||||||
|
};
|
||||||
|
if (*outptrroot) {
|
||||||
|
if (curstruct == nil) { return false; };
|
||||||
|
if (curstruct.kind != tykind.TY_PTR) { return false; };
|
||||||
|
curstruct = curstruct.sub;
|
||||||
|
for (curstruct != nil && curstruct.kind == tykind.TY_NAMED) {
|
||||||
|
curstruct = curstruct.under;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (rootstruct.len == 0) { return false; };
|
|
||||||
let curstruct: str = rootstruct;
|
|
||||||
let i: i32 = nsteps - 1;
|
let i: i32 = nsteps - 1;
|
||||||
for (i >= 0) {
|
for (i >= 0) {
|
||||||
let csi: *structinfo = structlookup(c, curstruct);
|
if (curstruct == nil) { return false; };
|
||||||
if (csi == nil) { return false; };
|
if (curstruct.kind != tykind.TY_STRUCT) { return false; };
|
||||||
if (stk[i] == nil) { return false; };
|
if (stk[i] == nil) { return false; };
|
||||||
let stepnm: str = stk[i].str;
|
let stepnm: str = stk[i].str;
|
||||||
let fi: *fieldinfo = csi.fields;
|
let tf: *tfield = curstruct.fields;
|
||||||
let found: *fieldinfo = nil;
|
let found: *tfield = nil;
|
||||||
for (fi != nil) {
|
for (tf != nil) {
|
||||||
if (streq(fi.fname, stepnm)) { found = fi; break; };
|
if (streq(tf.name, stepnm)) { found = tf; break; };
|
||||||
fi = fi.finext;
|
tf = tf.tnext;
|
||||||
};
|
};
|
||||||
if (found == nil) { return false; };
|
if (found == nil) { return false; };
|
||||||
|
let foff: i32 = found.offset: i32;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outleaffi = found;
|
*outleaftype = found.type_;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let ft: *node = found.tnode;
|
let ft: *tinfo = found.type_;
|
||||||
|
for (ft != nil && ft.kind == tykind.TY_NAMED) { ft = ft.under; };
|
||||||
if (ft == nil) { return false; };
|
if (ft == nil) { return false; };
|
||||||
if (ft.kind == nkind.N_TNAME) {
|
if (ft.kind == tykind.TY_STR) {
|
||||||
if (streq(ft.str, "str")) {
|
if (i != 1) { return false; };
|
||||||
if (i != 1) { return false; };
|
let pseudo: str = stk[0].str;
|
||||||
let pseudo: str = stk[0].str;
|
let delta: i32 = -1;
|
||||||
let delta: i32 = -1;
|
if (streq(pseudo, "ptr")) { delta = 0; }
|
||||||
if (streq(pseudo, "ptr")) { delta = 0; }
|
else { if (streq(pseudo, "len")) { delta = 8; }; };
|
||||||
else { if (streq(pseudo, "len")) { delta = 8; }; };
|
if (delta < 0) { return false; };
|
||||||
if (delta < 0) { return false; };
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outslicedelta = delta;
|
||||||
*outslicedelta = delta;
|
return true;
|
||||||
return true;
|
};
|
||||||
};
|
if (ft.kind == tykind.TY_SLICE) {
|
||||||
if (primsize(ft.str) != 0) { return false; };
|
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
|
||||||
curstruct = ft.str;
|
|
||||||
i -= 1;
|
|
||||||
} else { if (ft.kind == nkind.N_TSLICE) {
|
|
||||||
if (i != 1) { return false; };
|
if (i != 1) { return false; };
|
||||||
let pseudo: str = stk[0].str;
|
let pseudo: str = stk[0].str;
|
||||||
let delta: i32 = -1;
|
let delta: i32 = -1;
|
||||||
@@ -13474,12 +13497,14 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
else { if (streq(pseudo, "len")) { delta = 8; }
|
else { if (streq(pseudo, "len")) { delta = 8; }
|
||||||
else { if (streq(pseudo, "cap")) { delta = 16; }; }; };
|
else { if (streq(pseudo, "cap")) { delta = 16; }; }; };
|
||||||
if (delta < 0) { return false; };
|
if (delta < 0) { return false; };
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outslicedelta = delta;
|
*outslicedelta = delta;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
};
|
||||||
return false;
|
if (ft.kind != tykind.TY_STRUCT) { return false; };
|
||||||
}; };
|
*outtotaloff = *outtotaloff + foff;
|
||||||
|
curstruct = ft;
|
||||||
|
i -= 1;
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -15683,13 +15708,13 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let pok: bool = dotchainresolve(c, n,
|
let pok: bool = dotchainresolve(c, n,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||||
if (pok) {
|
if (pok) {
|
||||||
// `*T` root: load the pointer slot once into CX,
|
// `*T` root: load the pointer slot once into CX,
|
||||||
// then index every leaf at total_off off CX. Same
|
// then index every leaf at total_off off CX. Same
|
||||||
@@ -15717,7 +15742,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isstrtype(c, leaffi.tnode)) {
|
if (typeisstr(leaftype)) {
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -15744,7 +15769,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isslicetype(c, leaffi.tnode)) {
|
if (typeisslice(leaftype)) {
|
||||||
// Slice leaf: load all three header words into
|
// Slice leaf: load all three header words into
|
||||||
// (AX=ptr, BX=len, CX=cap). For the viacx path
|
// (AX=ptr, BX=len, CX=cap). For the viacx path
|
||||||
// (global or `*T` root) CX is the base; load
|
// (global or `*T` root) CX is the base; load
|
||||||
@@ -15783,9 +15808,9 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isfloattype(c, leaffi.tnode)) {
|
if (typeisfloat(leaftype)) {
|
||||||
let mov: str = "MOVSD";
|
let mov: str = "MOVSD";
|
||||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -15810,7 +15835,8 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let lop: str = fieldloadop(c, leaffi);
|
let lop: str = loadopsz(typeissigned(leaftype),
|
||||||
|
leaftype.slotsize: i32);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -16157,13 +16183,13 @@ fn cgun(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let pok: bool = dotchainresolve(c, opnd,
|
let pok: bool = dotchainresolve(c, opnd,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal,
|
&leaftype, &slicedelta, &isglobal,
|
||||||
&ptrroot);
|
&ptrroot);
|
||||||
// `&` through a `*T`-rooted chain is a
|
// `&` through a `*T`-rooted chain is a
|
||||||
// separate shape (would need MOVQ + LEAQ
|
// separate shape (would need MOVQ + LEAQ
|
||||||
@@ -18839,13 +18865,13 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let yok: bool = dotchainresolve(c, lhs,
|
let yok: bool = dotchainresolve(c, lhs,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||||
if (yok) {
|
if (yok) {
|
||||||
// `*T` root and global share the CX-based emit:
|
// `*T` root and global share the CX-based emit:
|
||||||
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
||||||
@@ -18873,7 +18899,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isstrtype(c, leaffi.tnode)) {
|
if (typeisstr(leaftype)) {
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
@@ -18916,12 +18942,33 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
// store; for ptrroot/global the dst addr is
|
// store; for ptrroot/global the dst addr is
|
||||||
// reloaded into BX before each store so cgexpr
|
// reloaded into BX before each store so cgexpr
|
||||||
// can clobber AX/BX between fields.
|
// 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
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_CALL
|
&& n.rhs.kind == nkind.N_CALL
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let lsi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
if (lsi != nil) {
|
if (lsi != nil) {
|
||||||
// si.totsize is slot-padded (rounded to 8);
|
// si.totsize is slot-padded (rounded to 8);
|
||||||
// receive ABI needs the TYPE's natural size.
|
// receive ABI needs the TYPE's natural size.
|
||||||
@@ -19003,10 +19050,8 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
// else → mode=0 (DST_BP), direct BP-rel, no reload.
|
// else → mode=0 (DST_BP), direct BP-rel, no reload.
|
||||||
if (n.rhs != nil
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_STRUCTLIT
|
&& n.rhs.kind == nkind.N_STRUCTLIT
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let lsi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
if (lsi != nil) {
|
if (lsi != nil) {
|
||||||
// si.totsize is slot-padded (rounded to 8);
|
// si.totsize is slot-padded (rounded to 8);
|
||||||
// receive ABI needs the TYPE's natural size.
|
// receive ABI needs the TYPE's natural size.
|
||||||
@@ -19029,10 +19074,8 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
if (n.rhs != nil
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_IDENT
|
&& n.rhs.kind == nkind.N_IDENT
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let ssi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let ssi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
let srhs: *local = localfindnode(c, n.rhs.str);
|
let srhs: *local = localfindnode(c, n.rhs.str);
|
||||||
if (ssi != nil) { if (srhs != nil) {
|
if (ssi != nil) { if (srhs != nil) {
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
@@ -19090,9 +19133,9 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
if (isfloattype(c, leaffi.tnode)) {
|
if (typeisfloat(leaftype)) {
|
||||||
let mov: str = "MOVSD";
|
let mov: str = "MOVSD";
|
||||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
@@ -19118,7 +19161,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
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);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
|
|||||||
@@ -1840,13 +1840,13 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let pok: bool = dotchainresolve(c, n,
|
let pok: bool = dotchainresolve(c, n,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||||
if (pok) {
|
if (pok) {
|
||||||
// `*T` root: load the pointer slot once into CX,
|
// `*T` root: load the pointer slot once into CX,
|
||||||
// then index every leaf at total_off off CX. Same
|
// then index every leaf at total_off off CX. Same
|
||||||
@@ -1874,7 +1874,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isstrtype(c, leaffi.tnode)) {
|
if (typeisstr(leaftype)) {
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -1901,7 +1901,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isslicetype(c, leaffi.tnode)) {
|
if (typeisslice(leaftype)) {
|
||||||
// Slice leaf: load all three header words into
|
// Slice leaf: load all three header words into
|
||||||
// (AX=ptr, BX=len, CX=cap). For the viacx path
|
// (AX=ptr, BX=len, CX=cap). For the viacx path
|
||||||
// (global or `*T` root) CX is the base; load
|
// (global or `*T` root) CX is the base; load
|
||||||
@@ -1940,9 +1940,9 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isfloattype(c, leaffi.tnode)) {
|
if (typeisfloat(leaftype)) {
|
||||||
let mov: str = "MOVSD";
|
let mov: str = "MOVSD";
|
||||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -1967,7 +1967,8 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let lop: str = fieldloadop(c, leaffi);
|
let lop: str = loadopsz(typeissigned(leaftype),
|
||||||
|
leaftype.slotsize: i32);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -2314,13 +2315,13 @@ fn cgun(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let pok: bool = dotchainresolve(c, opnd,
|
let pok: bool = dotchainresolve(c, opnd,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal,
|
&leaftype, &slicedelta, &isglobal,
|
||||||
&ptrroot);
|
&ptrroot);
|
||||||
// `&` through a `*T`-rooted chain is a
|
// `&` through a `*T`-rooted chain is a
|
||||||
// separate shape (would need MOVQ + LEAQ
|
// separate shape (would need MOVQ + LEAQ
|
||||||
@@ -4996,13 +4997,13 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let yok: bool = dotchainresolve(c, lhs,
|
let yok: bool = dotchainresolve(c, lhs,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||||
if (yok) {
|
if (yok) {
|
||||||
// `*T` root and global share the CX-based emit:
|
// `*T` root and global share the CX-based emit:
|
||||||
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
||||||
@@ -5030,7 +5031,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isstrtype(c, leaffi.tnode)) {
|
if (typeisstr(leaftype)) {
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
@@ -5073,12 +5074,33 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
// store; for ptrroot/global the dst addr is
|
// store; for ptrroot/global the dst addr is
|
||||||
// reloaded into BX before each store so cgexpr
|
// reloaded into BX before each store so cgexpr
|
||||||
// can clobber AX/BX between fields.
|
// 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
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_CALL
|
&& n.rhs.kind == nkind.N_CALL
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let lsi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
if (lsi != nil) {
|
if (lsi != nil) {
|
||||||
// si.totsize is slot-padded (rounded to 8);
|
// si.totsize is slot-padded (rounded to 8);
|
||||||
// receive ABI needs the TYPE's natural size.
|
// 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.
|
// else → mode=0 (DST_BP), direct BP-rel, no reload.
|
||||||
if (n.rhs != nil
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_STRUCTLIT
|
&& n.rhs.kind == nkind.N_STRUCTLIT
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let lsi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
if (lsi != nil) {
|
if (lsi != nil) {
|
||||||
// si.totsize is slot-padded (rounded to 8);
|
// si.totsize is slot-padded (rounded to 8);
|
||||||
// receive ABI needs the TYPE's natural size.
|
// receive ABI needs the TYPE's natural size.
|
||||||
@@ -5186,10 +5206,8 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
if (n.rhs != nil
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_IDENT
|
&& n.rhs.kind == nkind.N_IDENT
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let ssi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let ssi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
let srhs: *local = localfindnode(c, n.rhs.str);
|
let srhs: *local = localfindnode(c, n.rhs.str);
|
||||||
if (ssi != nil) { if (srhs != nil) {
|
if (ssi != nil) { if (srhs != nil) {
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
@@ -5247,9 +5265,9 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
if (isfloattype(c, leaffi.tnode)) {
|
if (typeisfloat(leaftype)) {
|
||||||
let mov: str = "MOVSD";
|
let mov: str = "MOVSD";
|
||||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
@@ -5275,7 +5293,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
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);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
|
|||||||
@@ -2808,7 +2808,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
|
|||||||
// Spine-walk a chained N_DOT (n) inward to a root ident, summing field
|
// Spine-walk a chained N_DOT (n) inward to a root ident, summing field
|
||||||
// offsets through value-struct intermediates. Optional slice/str leaf
|
// offsets through value-struct intermediates. Optional slice/str leaf
|
||||||
// pseudo-field (.ptr / .len / .cap) on the last segment is folded into
|
// pseudo-field (.ptr / .len / .cap) on the last segment is folded into
|
||||||
// *outslicedelta (0/8/16); otherwise *outleaffi is the leaf fieldinfo
|
// *outslicedelta (0/8/16); otherwise *outleaftype is the leaf *tinfo
|
||||||
// and *outslicedelta stays -1. Returns true on success; on false the
|
// and *outslicedelta stays -1. Returns true on success; on false the
|
||||||
// caller falls through to other branches.
|
// caller falls through to other branches.
|
||||||
//
|
//
|
||||||
@@ -2825,16 +2825,28 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
|
|||||||
// Numeric out-params are i32 — offsets fit naturally and the post-#19
|
// Numeric out-params are i32 — offsets fit naturally and the post-#19
|
||||||
// localloadop sign-extends i32 deref-stored slots on read, so negative
|
// localloadop sign-extends i32 deref-stored slots on read, so negative
|
||||||
// frame offsets round-trip intact.
|
// frame offsets round-trip intact.
|
||||||
|
// #71 (A.6.3j): the spine offset-sum + leaf-type now read off
|
||||||
|
// tinfo.fields (natural layout) instead of the structinfo/fieldinfo
|
||||||
|
// walk. Mirror of cstage cmd/w6c/cgen.c:3156-3216 which walks
|
||||||
|
// `cur->lhs->type` fields. Root resolution (the local/ptr/global split
|
||||||
|
// and the rootoff/ptrroot/isglobal flags) stays on localfindnode/
|
||||||
|
// letvarstructinfo unchanged, so the firing set + addressing mode are
|
||||||
|
// byte-identical to the structinfo era; only the layout SOURCE moves.
|
||||||
|
// The slot-padded foff and the natural tfield.offset coincide for every
|
||||||
|
// shape the byte-id gate exercises (cstage already reads the natural
|
||||||
|
// offset), so this is offset-preserving. Leaf out-param is the field's
|
||||||
|
// stamped *tinfo (was *fieldinfo); the str/slice pseudo-leaf leaves it
|
||||||
|
// nil and the callers gate on slicedelta>=0 first.
|
||||||
export fn dotchainresolve(c: *cgen, n: *node,
|
export fn dotchainresolve(c: *cgen, n: *node,
|
||||||
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||||
outleaffi: **fieldinfo, outslicedelta: *i32,
|
outleaftype: **tinfo, outslicedelta: *i32,
|
||||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
outisglobal: *bool, outptrroot: *bool) bool = {
|
||||||
*outrootname = "";
|
*outrootname = "";
|
||||||
*outrootoff = 0;
|
*outrootoff = 0;
|
||||||
*outisglobal = false;
|
*outisglobal = false;
|
||||||
*outptrroot = false;
|
*outptrroot = false;
|
||||||
*outtotaloff = 0;
|
*outtotaloff = 0;
|
||||||
*outleaffi = nil;
|
*outleaftype = nil;
|
||||||
*outslicedelta = -1;
|
*outslicedelta = -1;
|
||||||
if (n == nil) { return false; };
|
if (n == nil) { return false; };
|
||||||
if (n.kind != nkind.N_DOT) { return false; };
|
if (n.kind != nkind.N_DOT) { return false; };
|
||||||
@@ -2852,13 +2864,13 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
if (cur == nil) { return false; };
|
if (cur == nil) { return false; };
|
||||||
if (cur.kind != nkind.N_IDENT) { return false; };
|
if (cur.kind != nkind.N_IDENT) { return false; };
|
||||||
*outrootname = cur.str;
|
*outrootname = cur.str;
|
||||||
let rootstruct: str = "";
|
let resolved: bool = false;
|
||||||
let lc: *local = localfindnode(c, cur.str);
|
let lc: *local = localfindnode(c, cur.str);
|
||||||
if (lc != nil) {
|
if (lc != nil) {
|
||||||
if (lc.tnode != nil) {
|
if (lc.tnode != nil) {
|
||||||
if (lc.tnode.kind == nkind.N_TNAME) {
|
if (lc.tnode.kind == nkind.N_TNAME) {
|
||||||
rootstruct = lc.tnode.str;
|
|
||||||
*outrootoff = lc.off;
|
*outrootoff = lc.off;
|
||||||
|
resolved = true;
|
||||||
};
|
};
|
||||||
// `*T` root (param/local): dereference at emit time;
|
// `*T` root (param/local): dereference at emit time;
|
||||||
// pointee struct supplies the field layout. Callers
|
// pointee struct supplies the field layout. Callers
|
||||||
@@ -2868,60 +2880,71 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
let pe: *node = lc.tnode.lhs;
|
let pe: *node = lc.tnode.lhs;
|
||||||
if (pe != nil) {
|
if (pe != nil) {
|
||||||
if (pe.kind == nkind.N_TNAME) {
|
if (pe.kind == nkind.N_TNAME) {
|
||||||
rootstruct = pe.str;
|
|
||||||
*outrootoff = lc.off;
|
*outrootoff = lc.off;
|
||||||
*outptrroot = true;
|
*outptrroot = true;
|
||||||
|
resolved = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (rootstruct.len == 0) {
|
if (!resolved) {
|
||||||
let gsi: *structinfo = letvarstructinfo(c, cur.str);
|
let gsi: *structinfo = letvarstructinfo(c, cur.str);
|
||||||
if (gsi != nil) {
|
if (gsi != nil) {
|
||||||
rootstruct = gsi.sname;
|
|
||||||
*outisglobal = true;
|
*outisglobal = true;
|
||||||
|
resolved = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (!resolved) { return false; };
|
||||||
|
// Root struct layout = the stamped root-ident type_, peeled NAMED
|
||||||
|
// (plus one TY_PTR hop for a `*struct` root). tfield.type_ then
|
||||||
|
// supplies each nested struct directly, so no name re-lookup.
|
||||||
|
let curstruct: *tinfo = cur.type_: *tinfo;
|
||||||
|
for (curstruct != nil && curstruct.kind == tykind.TY_NAMED) {
|
||||||
|
curstruct = curstruct.under;
|
||||||
|
};
|
||||||
|
if (*outptrroot) {
|
||||||
|
if (curstruct == nil) { return false; };
|
||||||
|
if (curstruct.kind != tykind.TY_PTR) { return false; };
|
||||||
|
curstruct = curstruct.sub;
|
||||||
|
for (curstruct != nil && curstruct.kind == tykind.TY_NAMED) {
|
||||||
|
curstruct = curstruct.under;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (rootstruct.len == 0) { return false; };
|
|
||||||
let curstruct: str = rootstruct;
|
|
||||||
let i: i32 = nsteps - 1;
|
let i: i32 = nsteps - 1;
|
||||||
for (i >= 0) {
|
for (i >= 0) {
|
||||||
let csi: *structinfo = structlookup(c, curstruct);
|
if (curstruct == nil) { return false; };
|
||||||
if (csi == nil) { return false; };
|
if (curstruct.kind != tykind.TY_STRUCT) { return false; };
|
||||||
if (stk[i] == nil) { return false; };
|
if (stk[i] == nil) { return false; };
|
||||||
let stepnm: str = stk[i].str;
|
let stepnm: str = stk[i].str;
|
||||||
let fi: *fieldinfo = csi.fields;
|
let tf: *tfield = curstruct.fields;
|
||||||
let found: *fieldinfo = nil;
|
let found: *tfield = nil;
|
||||||
for (fi != nil) {
|
for (tf != nil) {
|
||||||
if (streq(fi.fname, stepnm)) { found = fi; break; };
|
if (streq(tf.name, stepnm)) { found = tf; break; };
|
||||||
fi = fi.finext;
|
tf = tf.tnext;
|
||||||
};
|
};
|
||||||
if (found == nil) { return false; };
|
if (found == nil) { return false; };
|
||||||
|
let foff: i32 = found.offset: i32;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outleaffi = found;
|
*outleaftype = found.type_;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let ft: *node = found.tnode;
|
let ft: *tinfo = found.type_;
|
||||||
|
for (ft != nil && ft.kind == tykind.TY_NAMED) { ft = ft.under; };
|
||||||
if (ft == nil) { return false; };
|
if (ft == nil) { return false; };
|
||||||
if (ft.kind == nkind.N_TNAME) {
|
if (ft.kind == tykind.TY_STR) {
|
||||||
if (streq(ft.str, "str")) {
|
if (i != 1) { return false; };
|
||||||
if (i != 1) { return false; };
|
let pseudo: str = stk[0].str;
|
||||||
let pseudo: str = stk[0].str;
|
let delta: i32 = -1;
|
||||||
let delta: i32 = -1;
|
if (streq(pseudo, "ptr")) { delta = 0; }
|
||||||
if (streq(pseudo, "ptr")) { delta = 0; }
|
else { if (streq(pseudo, "len")) { delta = 8; }; };
|
||||||
else { if (streq(pseudo, "len")) { delta = 8; }; };
|
if (delta < 0) { return false; };
|
||||||
if (delta < 0) { return false; };
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outslicedelta = delta;
|
||||||
*outslicedelta = delta;
|
return true;
|
||||||
return true;
|
};
|
||||||
};
|
if (ft.kind == tykind.TY_SLICE) {
|
||||||
if (primsize(ft.str) != 0) { return false; };
|
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
|
||||||
curstruct = ft.str;
|
|
||||||
i -= 1;
|
|
||||||
} else { if (ft.kind == nkind.N_TSLICE) {
|
|
||||||
if (i != 1) { return false; };
|
if (i != 1) { return false; };
|
||||||
let pseudo: str = stk[0].str;
|
let pseudo: str = stk[0].str;
|
||||||
let delta: i32 = -1;
|
let delta: i32 = -1;
|
||||||
@@ -2929,12 +2952,14 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
else { if (streq(pseudo, "len")) { delta = 8; }
|
else { if (streq(pseudo, "len")) { delta = 8; }
|
||||||
else { if (streq(pseudo, "cap")) { delta = 16; }; }; };
|
else { if (streq(pseudo, "cap")) { delta = 16; }; }; };
|
||||||
if (delta < 0) { return false; };
|
if (delta < 0) { return false; };
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outslicedelta = delta;
|
*outslicedelta = delta;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
};
|
||||||
return false;
|
if (ft.kind != tykind.TY_STRUCT) { return false; };
|
||||||
}; };
|
*outtotaloff = *outtotaloff + foff;
|
||||||
|
curstruct = ft;
|
||||||
|
i -= 1;
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13353,7 +13353,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
|
|||||||
// Spine-walk a chained N_DOT (n) inward to a root ident, summing field
|
// Spine-walk a chained N_DOT (n) inward to a root ident, summing field
|
||||||
// offsets through value-struct intermediates. Optional slice/str leaf
|
// offsets through value-struct intermediates. Optional slice/str leaf
|
||||||
// pseudo-field (.ptr / .len / .cap) on the last segment is folded into
|
// pseudo-field (.ptr / .len / .cap) on the last segment is folded into
|
||||||
// *outslicedelta (0/8/16); otherwise *outleaffi is the leaf fieldinfo
|
// *outslicedelta (0/8/16); otherwise *outleaftype is the leaf *tinfo
|
||||||
// and *outslicedelta stays -1. Returns true on success; on false the
|
// and *outslicedelta stays -1. Returns true on success; on false the
|
||||||
// caller falls through to other branches.
|
// caller falls through to other branches.
|
||||||
//
|
//
|
||||||
@@ -13370,16 +13370,28 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
|
|||||||
// Numeric out-params are i32 — offsets fit naturally and the post-#19
|
// Numeric out-params are i32 — offsets fit naturally and the post-#19
|
||||||
// localloadop sign-extends i32 deref-stored slots on read, so negative
|
// localloadop sign-extends i32 deref-stored slots on read, so negative
|
||||||
// frame offsets round-trip intact.
|
// frame offsets round-trip intact.
|
||||||
|
// #71 (A.6.3j): the spine offset-sum + leaf-type now read off
|
||||||
|
// tinfo.fields (natural layout) instead of the structinfo/fieldinfo
|
||||||
|
// walk. Mirror of cstage cmd/w6c/cgen.c:3156-3216 which walks
|
||||||
|
// `cur->lhs->type` fields. Root resolution (the local/ptr/global split
|
||||||
|
// and the rootoff/ptrroot/isglobal flags) stays on localfindnode/
|
||||||
|
// letvarstructinfo unchanged, so the firing set + addressing mode are
|
||||||
|
// byte-identical to the structinfo era; only the layout SOURCE moves.
|
||||||
|
// The slot-padded foff and the natural tfield.offset coincide for every
|
||||||
|
// shape the byte-id gate exercises (cstage already reads the natural
|
||||||
|
// offset), so this is offset-preserving. Leaf out-param is the field's
|
||||||
|
// stamped *tinfo (was *fieldinfo); the str/slice pseudo-leaf leaves it
|
||||||
|
// nil and the callers gate on slicedelta>=0 first.
|
||||||
export fn dotchainresolve(c: *cgen, n: *node,
|
export fn dotchainresolve(c: *cgen, n: *node,
|
||||||
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||||
outleaffi: **fieldinfo, outslicedelta: *i32,
|
outleaftype: **tinfo, outslicedelta: *i32,
|
||||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
outisglobal: *bool, outptrroot: *bool) bool = {
|
||||||
*outrootname = "";
|
*outrootname = "";
|
||||||
*outrootoff = 0;
|
*outrootoff = 0;
|
||||||
*outisglobal = false;
|
*outisglobal = false;
|
||||||
*outptrroot = false;
|
*outptrroot = false;
|
||||||
*outtotaloff = 0;
|
*outtotaloff = 0;
|
||||||
*outleaffi = nil;
|
*outleaftype = nil;
|
||||||
*outslicedelta = -1;
|
*outslicedelta = -1;
|
||||||
if (n == nil) { return false; };
|
if (n == nil) { return false; };
|
||||||
if (n.kind != nkind.N_DOT) { return false; };
|
if (n.kind != nkind.N_DOT) { return false; };
|
||||||
@@ -13397,13 +13409,13 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
if (cur == nil) { return false; };
|
if (cur == nil) { return false; };
|
||||||
if (cur.kind != nkind.N_IDENT) { return false; };
|
if (cur.kind != nkind.N_IDENT) { return false; };
|
||||||
*outrootname = cur.str;
|
*outrootname = cur.str;
|
||||||
let rootstruct: str = "";
|
let resolved: bool = false;
|
||||||
let lc: *local = localfindnode(c, cur.str);
|
let lc: *local = localfindnode(c, cur.str);
|
||||||
if (lc != nil) {
|
if (lc != nil) {
|
||||||
if (lc.tnode != nil) {
|
if (lc.tnode != nil) {
|
||||||
if (lc.tnode.kind == nkind.N_TNAME) {
|
if (lc.tnode.kind == nkind.N_TNAME) {
|
||||||
rootstruct = lc.tnode.str;
|
|
||||||
*outrootoff = lc.off;
|
*outrootoff = lc.off;
|
||||||
|
resolved = true;
|
||||||
};
|
};
|
||||||
// `*T` root (param/local): dereference at emit time;
|
// `*T` root (param/local): dereference at emit time;
|
||||||
// pointee struct supplies the field layout. Callers
|
// pointee struct supplies the field layout. Callers
|
||||||
@@ -13413,60 +13425,71 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
let pe: *node = lc.tnode.lhs;
|
let pe: *node = lc.tnode.lhs;
|
||||||
if (pe != nil) {
|
if (pe != nil) {
|
||||||
if (pe.kind == nkind.N_TNAME) {
|
if (pe.kind == nkind.N_TNAME) {
|
||||||
rootstruct = pe.str;
|
|
||||||
*outrootoff = lc.off;
|
*outrootoff = lc.off;
|
||||||
*outptrroot = true;
|
*outptrroot = true;
|
||||||
|
resolved = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (rootstruct.len == 0) {
|
if (!resolved) {
|
||||||
let gsi: *structinfo = letvarstructinfo(c, cur.str);
|
let gsi: *structinfo = letvarstructinfo(c, cur.str);
|
||||||
if (gsi != nil) {
|
if (gsi != nil) {
|
||||||
rootstruct = gsi.sname;
|
|
||||||
*outisglobal = true;
|
*outisglobal = true;
|
||||||
|
resolved = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (!resolved) { return false; };
|
||||||
|
// Root struct layout = the stamped root-ident type_, peeled NAMED
|
||||||
|
// (plus one TY_PTR hop for a `*struct` root). tfield.type_ then
|
||||||
|
// supplies each nested struct directly, so no name re-lookup.
|
||||||
|
let curstruct: *tinfo = cur.type_: *tinfo;
|
||||||
|
for (curstruct != nil && curstruct.kind == tykind.TY_NAMED) {
|
||||||
|
curstruct = curstruct.under;
|
||||||
|
};
|
||||||
|
if (*outptrroot) {
|
||||||
|
if (curstruct == nil) { return false; };
|
||||||
|
if (curstruct.kind != tykind.TY_PTR) { return false; };
|
||||||
|
curstruct = curstruct.sub;
|
||||||
|
for (curstruct != nil && curstruct.kind == tykind.TY_NAMED) {
|
||||||
|
curstruct = curstruct.under;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (rootstruct.len == 0) { return false; };
|
|
||||||
let curstruct: str = rootstruct;
|
|
||||||
let i: i32 = nsteps - 1;
|
let i: i32 = nsteps - 1;
|
||||||
for (i >= 0) {
|
for (i >= 0) {
|
||||||
let csi: *structinfo = structlookup(c, curstruct);
|
if (curstruct == nil) { return false; };
|
||||||
if (csi == nil) { return false; };
|
if (curstruct.kind != tykind.TY_STRUCT) { return false; };
|
||||||
if (stk[i] == nil) { return false; };
|
if (stk[i] == nil) { return false; };
|
||||||
let stepnm: str = stk[i].str;
|
let stepnm: str = stk[i].str;
|
||||||
let fi: *fieldinfo = csi.fields;
|
let tf: *tfield = curstruct.fields;
|
||||||
let found: *fieldinfo = nil;
|
let found: *tfield = nil;
|
||||||
for (fi != nil) {
|
for (tf != nil) {
|
||||||
if (streq(fi.fname, stepnm)) { found = fi; break; };
|
if (streq(tf.name, stepnm)) { found = tf; break; };
|
||||||
fi = fi.finext;
|
tf = tf.tnext;
|
||||||
};
|
};
|
||||||
if (found == nil) { return false; };
|
if (found == nil) { return false; };
|
||||||
|
let foff: i32 = found.offset: i32;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outleaffi = found;
|
*outleaftype = found.type_;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let ft: *node = found.tnode;
|
let ft: *tinfo = found.type_;
|
||||||
|
for (ft != nil && ft.kind == tykind.TY_NAMED) { ft = ft.under; };
|
||||||
if (ft == nil) { return false; };
|
if (ft == nil) { return false; };
|
||||||
if (ft.kind == nkind.N_TNAME) {
|
if (ft.kind == tykind.TY_STR) {
|
||||||
if (streq(ft.str, "str")) {
|
if (i != 1) { return false; };
|
||||||
if (i != 1) { return false; };
|
let pseudo: str = stk[0].str;
|
||||||
let pseudo: str = stk[0].str;
|
let delta: i32 = -1;
|
||||||
let delta: i32 = -1;
|
if (streq(pseudo, "ptr")) { delta = 0; }
|
||||||
if (streq(pseudo, "ptr")) { delta = 0; }
|
else { if (streq(pseudo, "len")) { delta = 8; }; };
|
||||||
else { if (streq(pseudo, "len")) { delta = 8; }; };
|
if (delta < 0) { return false; };
|
||||||
if (delta < 0) { return false; };
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outslicedelta = delta;
|
||||||
*outslicedelta = delta;
|
return true;
|
||||||
return true;
|
};
|
||||||
};
|
if (ft.kind == tykind.TY_SLICE) {
|
||||||
if (primsize(ft.str) != 0) { return false; };
|
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
|
||||||
curstruct = ft.str;
|
|
||||||
i -= 1;
|
|
||||||
} else { if (ft.kind == nkind.N_TSLICE) {
|
|
||||||
if (i != 1) { return false; };
|
if (i != 1) { return false; };
|
||||||
let pseudo: str = stk[0].str;
|
let pseudo: str = stk[0].str;
|
||||||
let delta: i32 = -1;
|
let delta: i32 = -1;
|
||||||
@@ -13474,12 +13497,14 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
|||||||
else { if (streq(pseudo, "len")) { delta = 8; }
|
else { if (streq(pseudo, "len")) { delta = 8; }
|
||||||
else { if (streq(pseudo, "cap")) { delta = 16; }; }; };
|
else { if (streq(pseudo, "cap")) { delta = 16; }; }; };
|
||||||
if (delta < 0) { return false; };
|
if (delta < 0) { return false; };
|
||||||
*outtotaloff = *outtotaloff + found.foff;
|
*outtotaloff = *outtotaloff + foff;
|
||||||
*outslicedelta = delta;
|
*outslicedelta = delta;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
};
|
||||||
return false;
|
if (ft.kind != tykind.TY_STRUCT) { return false; };
|
||||||
}; };
|
*outtotaloff = *outtotaloff + foff;
|
||||||
|
curstruct = ft;
|
||||||
|
i -= 1;
|
||||||
};
|
};
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -15683,13 +15708,13 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let pok: bool = dotchainresolve(c, n,
|
let pok: bool = dotchainresolve(c, n,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||||
if (pok) {
|
if (pok) {
|
||||||
// `*T` root: load the pointer slot once into CX,
|
// `*T` root: load the pointer slot once into CX,
|
||||||
// then index every leaf at total_off off CX. Same
|
// then index every leaf at total_off off CX. Same
|
||||||
@@ -15717,7 +15742,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isstrtype(c, leaffi.tnode)) {
|
if (typeisstr(leaftype)) {
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -15744,7 +15769,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isslicetype(c, leaffi.tnode)) {
|
if (typeisslice(leaftype)) {
|
||||||
// Slice leaf: load all three header words into
|
// Slice leaf: load all three header words into
|
||||||
// (AX=ptr, BX=len, CX=cap). For the viacx path
|
// (AX=ptr, BX=len, CX=cap). For the viacx path
|
||||||
// (global or `*T` root) CX is the base; load
|
// (global or `*T` root) CX is the base; load
|
||||||
@@ -15783,9 +15808,9 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isfloattype(c, leaffi.tnode)) {
|
if (typeisfloat(leaftype)) {
|
||||||
let mov: str = "MOVSD";
|
let mov: str = "MOVSD";
|
||||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -15810,7 +15835,8 @@ fn cgdot(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let lop: str = fieldloadop(c, leaffi);
|
let lop: str = loadopsz(typeissigned(leaftype),
|
||||||
|
leaftype.slotsize: i32);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
@@ -16157,13 +16183,13 @@ fn cgun(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let pok: bool = dotchainresolve(c, opnd,
|
let pok: bool = dotchainresolve(c, opnd,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal,
|
&leaftype, &slicedelta, &isglobal,
|
||||||
&ptrroot);
|
&ptrroot);
|
||||||
// `&` through a `*T`-rooted chain is a
|
// `&` through a `*T`-rooted chain is a
|
||||||
// separate shape (would need MOVQ + LEAQ
|
// separate shape (would need MOVQ + LEAQ
|
||||||
@@ -18839,13 +18865,13 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
let rootname: str = "";
|
let rootname: str = "";
|
||||||
let rootoff: i32 = 0;
|
let rootoff: i32 = 0;
|
||||||
let totaloff: i32 = 0;
|
let totaloff: i32 = 0;
|
||||||
let leaffi: *fieldinfo = nil;
|
let leaftype: *tinfo = nil;
|
||||||
let slicedelta: i32 = -1;
|
let slicedelta: i32 = -1;
|
||||||
let isglobal: bool = false;
|
let isglobal: bool = false;
|
||||||
let ptrroot: bool = false;
|
let ptrroot: bool = false;
|
||||||
let yok: bool = dotchainresolve(c, lhs,
|
let yok: bool = dotchainresolve(c, lhs,
|
||||||
&rootname, &rootoff, &totaloff,
|
&rootname, &rootoff, &totaloff,
|
||||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||||
if (yok) {
|
if (yok) {
|
||||||
// `*T` root and global share the CX-based emit:
|
// `*T` root and global share the CX-based emit:
|
||||||
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
||||||
@@ -18873,7 +18899,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (isstrtype(c, leaffi.tnode)) {
|
if (typeisstr(leaftype)) {
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
@@ -18916,12 +18942,33 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
// store; for ptrroot/global the dst addr is
|
// store; for ptrroot/global the dst addr is
|
||||||
// reloaded into BX before each store so cgexpr
|
// reloaded into BX before each store so cgexpr
|
||||||
// can clobber AX/BX between fields.
|
// 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
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_CALL
|
&& n.rhs.kind == nkind.N_CALL
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let lsi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
if (lsi != nil) {
|
if (lsi != nil) {
|
||||||
// si.totsize is slot-padded (rounded to 8);
|
// si.totsize is slot-padded (rounded to 8);
|
||||||
// receive ABI needs the TYPE's natural size.
|
// receive ABI needs the TYPE's natural size.
|
||||||
@@ -19003,10 +19050,8 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
// else → mode=0 (DST_BP), direct BP-rel, no reload.
|
// else → mode=0 (DST_BP), direct BP-rel, no reload.
|
||||||
if (n.rhs != nil
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_STRUCTLIT
|
&& n.rhs.kind == nkind.N_STRUCTLIT
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let lsi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
if (lsi != nil) {
|
if (lsi != nil) {
|
||||||
// si.totsize is slot-padded (rounded to 8);
|
// si.totsize is slot-padded (rounded to 8);
|
||||||
// receive ABI needs the TYPE's natural size.
|
// receive ABI needs the TYPE's natural size.
|
||||||
@@ -19029,10 +19074,8 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
if (n.rhs != nil
|
if (n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_IDENT
|
&& n.rhs.kind == nkind.N_IDENT
|
||||||
&& leaffi.tnode != nil
|
&& leafstruct) {
|
||||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
let ssi: *structinfo = structlookup(c, leafname);
|
||||||
&& primsize(leaffi.tnode.str) == 0) {
|
|
||||||
let ssi: *structinfo = structlookup(c, leaffi.tnode.str);
|
|
||||||
let srhs: *local = localfindnode(c, n.rhs.str);
|
let srhs: *local = localfindnode(c, n.rhs.str);
|
||||||
if (ssi != nil) { if (srhs != nil) {
|
if (ssi != nil) { if (srhs != nil) {
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
@@ -19090,9 +19133,9 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
if (isfloattype(c, leaffi.tnode)) {
|
if (typeisfloat(leaftype)) {
|
||||||
let mov: str = "MOVSD";
|
let mov: str = "MOVSD";
|
||||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
@@ -19118,7 +19161,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
return;
|
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);
|
cgexpr(c, n.rhs);
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
if (ptrroot) {
|
if (ptrroot) {
|
||||||
|
|||||||
Reference in New Issue
Block a user