w6c+selfhost: cgen *T-rooted chained N_DOT (closes #22)
Spine walker now accepts *T root at the last hop (cur->lhs->kind == N_IDENT, pu->kind == TY_PTR), substitutes pointee struct, emits MOVQ off(BP), CX before offset arithmetic. Symmetric in N_DOT and N_ASSIGN. Distinct gate from existing mid-chain *T-field branch (cgen.c:4615) — no shadow. Unblocks task #18 (bufio writer first-field embed). Pre-existing *T-field mid-chain path unchanged.
This commit is contained in:
@@ -7934,10 +7934,11 @@ fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz:
|
||||
export fn dotchainresolve(c: *cgen, n: *node,
|
||||
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||
outleaffi: **fieldinfo, outslicedelta: *i32,
|
||||
outisglobal: *bool) bool = {
|
||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
||||
*outrootname = "";
|
||||
*outrootoff = 0;
|
||||
*outisglobal = false;
|
||||
*outptrroot = false;
|
||||
*outtotaloff = 0;
|
||||
*outleaffi = nil;
|
||||
*outslicedelta = -1;
|
||||
@@ -7965,6 +7966,20 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
||||
rootstruct = lc.tnode.str;
|
||||
*outrootoff = lc.off;
|
||||
};
|
||||
// `*T` root (param/local): dereference at emit time;
|
||||
// pointee struct supplies the field layout. Callers
|
||||
// that opt in via *outptrroot emit a MOVQ load of the
|
||||
// slot before indexing.
|
||||
if (lc.tnode.kind == nkind.N_TPTR) {
|
||||
let pe: *node = lc.tnode.lhs;
|
||||
if (pe != nil) {
|
||||
if (pe.kind == nkind.N_TNAME) {
|
||||
rootstruct = pe.str;
|
||||
*outrootoff = lc.off;
|
||||
*outptrroot = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (rootstruct.len == 0) {
|
||||
@@ -9648,15 +9663,27 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
if (pok) {
|
||||
// `*T` root: load the pointer slot once into CX,
|
||||
// then index every leaf at total_off off CX. Same
|
||||
// emit shape as the global path (LEAQ → CX) — only
|
||||
// the loader instruction differs.
|
||||
let viacx: bool = isglobal || ptrroot;
|
||||
if (slicedelta >= 0) {
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((totaloff + slicedelta): i64, "CX");
|
||||
emitline(", AX\n");
|
||||
@@ -9668,10 +9695,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(totaloff: i64, "CX");
|
||||
emitline(", AX\n");
|
||||
@@ -9691,10 +9724,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
if (isfloattype(c, leaffi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
@@ -9710,10 +9749,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, leaffi);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
@@ -10005,9 +10050,16 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal,
|
||||
&ptrroot);
|
||||
// `&` through a `*T`-rooted chain is a
|
||||
// separate shape (would need MOVQ + LEAQ
|
||||
// disp(CX), AX). Not exercised by current
|
||||
// callers — skip and fall through.
|
||||
if (ptrroot) { pok = false; };
|
||||
if (pok) {
|
||||
let extra: i32 = 0;
|
||||
if (slicedelta >= 0) { extra = slicedelta; };
|
||||
@@ -11957,16 +12009,27 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
if (yok) {
|
||||
// `*T` root and global share the CX-based emit:
|
||||
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
||||
// intact, then stores at total_off off CX.
|
||||
let viacx: bool = isglobal || ptrroot;
|
||||
if (slicedelta >= 0) {
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg((totaloff + slicedelta): i64, "CX");
|
||||
emitline("\n");
|
||||
@@ -11979,10 +12042,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(totaloff: i64, "CX");
|
||||
emitline("\n");
|
||||
@@ -12003,10 +12072,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
@@ -12023,10 +12098,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
let sop: str = fieldstoreop(c, leaffi);
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
|
||||
@@ -1615,15 +1615,27 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
if (pok) {
|
||||
// `*T` root: load the pointer slot once into CX,
|
||||
// then index every leaf at total_off off CX. Same
|
||||
// emit shape as the global path (LEAQ → CX) — only
|
||||
// the loader instruction differs.
|
||||
let viacx: bool = isglobal || ptrroot;
|
||||
if (slicedelta >= 0) {
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((totaloff + slicedelta): i64, "CX");
|
||||
emitline(", AX\n");
|
||||
@@ -1635,10 +1647,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(totaloff: i64, "CX");
|
||||
emitline(", AX\n");
|
||||
@@ -1658,10 +1676,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
if (isfloattype(c, leaffi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
@@ -1677,10 +1701,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, leaffi);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
@@ -1972,9 +2002,16 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal,
|
||||
&ptrroot);
|
||||
// `&` through a `*T`-rooted chain is a
|
||||
// separate shape (would need MOVQ + LEAQ
|
||||
// disp(CX), AX). Not exercised by current
|
||||
// callers — skip and fall through.
|
||||
if (ptrroot) { pok = false; };
|
||||
if (pok) {
|
||||
let extra: i32 = 0;
|
||||
if (slicedelta >= 0) { extra = slicedelta; };
|
||||
@@ -3924,16 +3961,27 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
if (yok) {
|
||||
// `*T` root and global share the CX-based emit:
|
||||
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
||||
// intact, then stores at total_off off CX.
|
||||
let viacx: bool = isglobal || ptrroot;
|
||||
if (slicedelta >= 0) {
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg((totaloff + slicedelta): i64, "CX");
|
||||
emitline("\n");
|
||||
@@ -3946,10 +3994,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(totaloff: i64, "CX");
|
||||
emitline("\n");
|
||||
@@ -3970,10 +4024,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
@@ -3990,10 +4050,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
let sop: str = fieldstoreop(c, leaffi);
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
|
||||
@@ -2364,10 +2364,11 @@ fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz:
|
||||
export fn dotchainresolve(c: *cgen, n: *node,
|
||||
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||
outleaffi: **fieldinfo, outslicedelta: *i32,
|
||||
outisglobal: *bool) bool = {
|
||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
||||
*outrootname = "";
|
||||
*outrootoff = 0;
|
||||
*outisglobal = false;
|
||||
*outptrroot = false;
|
||||
*outtotaloff = 0;
|
||||
*outleaffi = nil;
|
||||
*outslicedelta = -1;
|
||||
@@ -2395,6 +2396,20 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
||||
rootstruct = lc.tnode.str;
|
||||
*outrootoff = lc.off;
|
||||
};
|
||||
// `*T` root (param/local): dereference at emit time;
|
||||
// pointee struct supplies the field layout. Callers
|
||||
// that opt in via *outptrroot emit a MOVQ load of the
|
||||
// slot before indexing.
|
||||
if (lc.tnode.kind == nkind.N_TPTR) {
|
||||
let pe: *node = lc.tnode.lhs;
|
||||
if (pe != nil) {
|
||||
if (pe.kind == nkind.N_TNAME) {
|
||||
rootstruct = pe.str;
|
||||
*outrootoff = lc.off;
|
||||
*outptrroot = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (rootstruct.len == 0) {
|
||||
|
||||
@@ -7934,10 +7934,11 @@ fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz:
|
||||
export fn dotchainresolve(c: *cgen, n: *node,
|
||||
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||
outleaffi: **fieldinfo, outslicedelta: *i32,
|
||||
outisglobal: *bool) bool = {
|
||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
||||
*outrootname = "";
|
||||
*outrootoff = 0;
|
||||
*outisglobal = false;
|
||||
*outptrroot = false;
|
||||
*outtotaloff = 0;
|
||||
*outleaffi = nil;
|
||||
*outslicedelta = -1;
|
||||
@@ -7965,6 +7966,20 @@ export fn dotchainresolve(c: *cgen, n: *node,
|
||||
rootstruct = lc.tnode.str;
|
||||
*outrootoff = lc.off;
|
||||
};
|
||||
// `*T` root (param/local): dereference at emit time;
|
||||
// pointee struct supplies the field layout. Callers
|
||||
// that opt in via *outptrroot emit a MOVQ load of the
|
||||
// slot before indexing.
|
||||
if (lc.tnode.kind == nkind.N_TPTR) {
|
||||
let pe: *node = lc.tnode.lhs;
|
||||
if (pe != nil) {
|
||||
if (pe.kind == nkind.N_TNAME) {
|
||||
rootstruct = pe.str;
|
||||
*outrootoff = lc.off;
|
||||
*outptrroot = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (rootstruct.len == 0) {
|
||||
@@ -9648,15 +9663,27 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
if (pok) {
|
||||
// `*T` root: load the pointer slot once into CX,
|
||||
// then index every leaf at total_off off CX. Same
|
||||
// emit shape as the global path (LEAQ → CX) — only
|
||||
// the loader instruction differs.
|
||||
let viacx: bool = isglobal || ptrroot;
|
||||
if (slicedelta >= 0) {
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((totaloff + slicedelta): i64, "CX");
|
||||
emitline(", AX\n");
|
||||
@@ -9668,10 +9695,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(totaloff: i64, "CX");
|
||||
emitline(", AX\n");
|
||||
@@ -9691,10 +9724,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
if (isfloattype(c, leaffi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
@@ -9710,10 +9749,16 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, leaffi);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
@@ -10005,9 +10050,16 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal,
|
||||
&ptrroot);
|
||||
// `&` through a `*T`-rooted chain is a
|
||||
// separate shape (would need MOVQ + LEAQ
|
||||
// disp(CX), AX). Not exercised by current
|
||||
// callers — skip and fall through.
|
||||
if (ptrroot) { pok = false; };
|
||||
if (pok) {
|
||||
let extra: i32 = 0;
|
||||
if (slicedelta >= 0) { extra = slicedelta; };
|
||||
@@ -11957,16 +12009,27 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let leaffi: *fieldinfo = 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);
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
if (yok) {
|
||||
// `*T` root and global share the CX-based emit:
|
||||
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
||||
// intact, then stores at total_off off CX.
|
||||
let viacx: bool = isglobal || ptrroot;
|
||||
if (slicedelta >= 0) {
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg((totaloff + slicedelta): i64, "CX");
|
||||
emitline("\n");
|
||||
@@ -11979,10 +12042,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(totaloff: i64, "CX");
|
||||
emitline("\n");
|
||||
@@ -12003,10 +12072,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
@@ -12023,10 +12098,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
let sop: str = fieldstoreop(c, leaffi);
|
||||
cgexpr(c, n.rhs);
|
||||
if (isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(rootoff: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, rootname);
|
||||
emitline("(SB), CX\n");
|
||||
};
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
|
||||
Reference in New Issue
Block a user