w6c+selfhost: cgassign N_DOT N_INDEX-lhs branch (closes #16)
Symmetric write-side counterpart of #8, bundled across both stages. cstage [N]Struct write was broken (1986 gated on TY_PTR); wwstage had no N_DOT(N_INDEX) write branch at all. New branch covers both [N]*Struct and [N]Struct via viaptr flag, uses fldstoreop for scalar/sub-word, MOVSS/MOVSD for float, two-MOVQ for str rhs. Compound (PLUSEQ etc.) wired for integer scalar.
This commit is contained in:
@@ -11289,6 +11289,216 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// `arr[i].field = v`: N_DOT lhs whose lhs is N_INDEX. Symmetric
|
||||
// write-side of the cgdot N_INDEX-lhs branch added for task #8.
|
||||
// Compute &arr[i] inline (LEAQ for `[N]Struct`, MOVQ for
|
||||
// `[N]*Struct` / `[]Struct` / `*Struct`), deref once when the
|
||||
// element is `*Struct`, then store rhs at field.offset(addr).
|
||||
// Without this both shapes silently drop the store — there is no
|
||||
// existing wwstage branch for N_DOT(N_INDEX,...) lhs at all (the
|
||||
// N_INDEX-lhs branch above handles bare `arr[i] = v`, not the
|
||||
// field write).
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_DOT && lhs.lhs != nil
|
||||
&& lhs.lhs.kind == nkind.N_INDEX) {
|
||||
let idxbase: *node = lhs.lhs.lhs;
|
||||
let idx: *node = lhs.lhs.rhs;
|
||||
let fld2: str = lhs.str;
|
||||
if (idxbase != nil) { if (idxbase.kind == nkind.N_IDENT) {
|
||||
if (idx != nil) {
|
||||
let lc: *local = localfindnode(c, idxbase.str);
|
||||
if (lc != nil) { if (lc.tnode != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let elemt: *node = nil;
|
||||
let baseisarray: bool = false;
|
||||
let tk: nkind = tn.kind;
|
||||
if (tk == nkind.N_TSLICE) { elemt = tn.lhs; };
|
||||
if (tk == nkind.N_TARRAY) { elemt = tn.lhs; baseisarray = true; };
|
||||
if (tk == nkind.N_TPTR) { elemt = tn.lhs; };
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
let viaptr: bool = false;
|
||||
if (elemt != nil) {
|
||||
if (elemt.kind == nkind.N_TPTR) {
|
||||
let inner: *node = elemt.lhs;
|
||||
if (inner != nil) { if (inner.kind == nkind.N_TNAME) {
|
||||
sname = inner.str;
|
||||
viaptr = true;
|
||||
};};
|
||||
} else { if (elemt.kind == nkind.N_TNAME) {
|
||||
sname = elemt.str;
|
||||
};};
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld2)) {
|
||||
let esz: i32 = elemsizeofc(c, tn);
|
||||
// f64/f32: rhs in X0. Spill to stack,
|
||||
// compute &arr[i] in BX (deref if *T),
|
||||
// then reload X0 and MOVSD/MOVSS.
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, (SP)\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t(SP), X0\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// str rhs: AX=ptr, BX=len. Stash both,
|
||||
// compute addr in CX so the pop pair
|
||||
// restores AX/BX intact.
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, CX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(CX), CX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((fi.foff + 8): i64, "CX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// scalar plain `=`
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
let sop: str = fieldstoreop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// compound: rhs→push; compute struct
|
||||
// addr→BX (deref if *T); push addr;
|
||||
// load old field→AX; pop addr→BX,
|
||||
// rhs→CX; combine; store. Float/str
|
||||
// compound not wired.
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline(", AX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) { emitline("\tSUBQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_STAREQ) { emitline("\tIMULQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_AMPEQ) { emitline("\tANDQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_PIPEEQ) { emitline("\tORQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_CARETEQ) { emitline("\tXORQ\tCX, AX\n"); };
|
||||
let sop2: str = fieldstoreop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(sop2);
|
||||
emitline("\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
};
|
||||
};};
|
||||
};
|
||||
};};
|
||||
};
|
||||
};
|
||||
// Struct/ptr-to-struct field assignment: `s.f = expr;` or
|
||||
// `p.f = expr;`. Only plain `=` is wired (compound on field
|
||||
// is rare and not yet needed by our fixtures).
|
||||
|
||||
@@ -3246,6 +3246,216 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// `arr[i].field = v`: N_DOT lhs whose lhs is N_INDEX. Symmetric
|
||||
// write-side of the cgdot N_INDEX-lhs branch added for task #8.
|
||||
// Compute &arr[i] inline (LEAQ for `[N]Struct`, MOVQ for
|
||||
// `[N]*Struct` / `[]Struct` / `*Struct`), deref once when the
|
||||
// element is `*Struct`, then store rhs at field.offset(addr).
|
||||
// Without this both shapes silently drop the store — there is no
|
||||
// existing wwstage branch for N_DOT(N_INDEX,...) lhs at all (the
|
||||
// N_INDEX-lhs branch above handles bare `arr[i] = v`, not the
|
||||
// field write).
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_DOT && lhs.lhs != nil
|
||||
&& lhs.lhs.kind == nkind.N_INDEX) {
|
||||
let idxbase: *node = lhs.lhs.lhs;
|
||||
let idx: *node = lhs.lhs.rhs;
|
||||
let fld2: str = lhs.str;
|
||||
if (idxbase != nil) { if (idxbase.kind == nkind.N_IDENT) {
|
||||
if (idx != nil) {
|
||||
let lc: *local = localfindnode(c, idxbase.str);
|
||||
if (lc != nil) { if (lc.tnode != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let elemt: *node = nil;
|
||||
let baseisarray: bool = false;
|
||||
let tk: nkind = tn.kind;
|
||||
if (tk == nkind.N_TSLICE) { elemt = tn.lhs; };
|
||||
if (tk == nkind.N_TARRAY) { elemt = tn.lhs; baseisarray = true; };
|
||||
if (tk == nkind.N_TPTR) { elemt = tn.lhs; };
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
let viaptr: bool = false;
|
||||
if (elemt != nil) {
|
||||
if (elemt.kind == nkind.N_TPTR) {
|
||||
let inner: *node = elemt.lhs;
|
||||
if (inner != nil) { if (inner.kind == nkind.N_TNAME) {
|
||||
sname = inner.str;
|
||||
viaptr = true;
|
||||
};};
|
||||
} else { if (elemt.kind == nkind.N_TNAME) {
|
||||
sname = elemt.str;
|
||||
};};
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld2)) {
|
||||
let esz: i32 = elemsizeofc(c, tn);
|
||||
// f64/f32: rhs in X0. Spill to stack,
|
||||
// compute &arr[i] in BX (deref if *T),
|
||||
// then reload X0 and MOVSD/MOVSS.
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, (SP)\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t(SP), X0\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// str rhs: AX=ptr, BX=len. Stash both,
|
||||
// compute addr in CX so the pop pair
|
||||
// restores AX/BX intact.
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, CX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(CX), CX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((fi.foff + 8): i64, "CX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// scalar plain `=`
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
let sop: str = fieldstoreop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// compound: rhs→push; compute struct
|
||||
// addr→BX (deref if *T); push addr;
|
||||
// load old field→AX; pop addr→BX,
|
||||
// rhs→CX; combine; store. Float/str
|
||||
// compound not wired.
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline(", AX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) { emitline("\tSUBQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_STAREQ) { emitline("\tIMULQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_AMPEQ) { emitline("\tANDQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_PIPEEQ) { emitline("\tORQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_CARETEQ) { emitline("\tXORQ\tCX, AX\n"); };
|
||||
let sop2: str = fieldstoreop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(sop2);
|
||||
emitline("\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
};
|
||||
};};
|
||||
};
|
||||
};};
|
||||
};
|
||||
};
|
||||
// Struct/ptr-to-struct field assignment: `s.f = expr;` or
|
||||
// `p.f = expr;`. Only plain `=` is wired (compound on field
|
||||
// is rare and not yet needed by our fixtures).
|
||||
|
||||
@@ -11289,6 +11289,216 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// `arr[i].field = v`: N_DOT lhs whose lhs is N_INDEX. Symmetric
|
||||
// write-side of the cgdot N_INDEX-lhs branch added for task #8.
|
||||
// Compute &arr[i] inline (LEAQ for `[N]Struct`, MOVQ for
|
||||
// `[N]*Struct` / `[]Struct` / `*Struct`), deref once when the
|
||||
// element is `*Struct`, then store rhs at field.offset(addr).
|
||||
// Without this both shapes silently drop the store — there is no
|
||||
// existing wwstage branch for N_DOT(N_INDEX,...) lhs at all (the
|
||||
// N_INDEX-lhs branch above handles bare `arr[i] = v`, not the
|
||||
// field write).
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_DOT && lhs.lhs != nil
|
||||
&& lhs.lhs.kind == nkind.N_INDEX) {
|
||||
let idxbase: *node = lhs.lhs.lhs;
|
||||
let idx: *node = lhs.lhs.rhs;
|
||||
let fld2: str = lhs.str;
|
||||
if (idxbase != nil) { if (idxbase.kind == nkind.N_IDENT) {
|
||||
if (idx != nil) {
|
||||
let lc: *local = localfindnode(c, idxbase.str);
|
||||
if (lc != nil) { if (lc.tnode != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let elemt: *node = nil;
|
||||
let baseisarray: bool = false;
|
||||
let tk: nkind = tn.kind;
|
||||
if (tk == nkind.N_TSLICE) { elemt = tn.lhs; };
|
||||
if (tk == nkind.N_TARRAY) { elemt = tn.lhs; baseisarray = true; };
|
||||
if (tk == nkind.N_TPTR) { elemt = tn.lhs; };
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
let viaptr: bool = false;
|
||||
if (elemt != nil) {
|
||||
if (elemt.kind == nkind.N_TPTR) {
|
||||
let inner: *node = elemt.lhs;
|
||||
if (inner != nil) { if (inner.kind == nkind.N_TNAME) {
|
||||
sname = inner.str;
|
||||
viaptr = true;
|
||||
};};
|
||||
} else { if (elemt.kind == nkind.N_TNAME) {
|
||||
sname = elemt.str;
|
||||
};};
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld2)) {
|
||||
let esz: i32 = elemsizeofc(c, tn);
|
||||
// f64/f32: rhs in X0. Spill to stack,
|
||||
// compute &arr[i] in BX (deref if *T),
|
||||
// then reload X0 and MOVSD/MOVSS.
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, (SP)\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t(SP), X0\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// str rhs: AX=ptr, BX=len. Stash both,
|
||||
// compute addr in CX so the pop pair
|
||||
// restores AX/BX intact.
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, CX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(CX), CX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((fi.foff + 8): i64, "CX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// scalar plain `=`
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
let sop: str = fieldstoreop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// compound: rhs→push; compute struct
|
||||
// addr→BX (deref if *T); push addr;
|
||||
// load old field→AX; pop addr→BX,
|
||||
// rhs→CX; combine; store. Float/str
|
||||
// compound not wired.
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline(", AX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) { emitline("\tSUBQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_STAREQ) { emitline("\tIMULQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_AMPEQ) { emitline("\tANDQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_PIPEEQ) { emitline("\tORQ\tCX, AX\n"); };
|
||||
if (n.op == tkind.TK_CARETEQ) { emitline("\tXORQ\tCX, AX\n"); };
|
||||
let sop2: str = fieldstoreop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(sop2);
|
||||
emitline("\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
};
|
||||
};};
|
||||
};
|
||||
};};
|
||||
};
|
||||
};
|
||||
// Struct/ptr-to-struct field assignment: `s.f = expr;` or
|
||||
// `p.f = expr;`. Only plain `=` is wired (compound on field
|
||||
// is rare and not yet needed by our fixtures).
|
||||
|
||||
Reference in New Issue
Block a user