w6c+selfhost: cgen N_DOT N_INDEX-lhs branch (closes #8)
cstage cmd/w6c/cgen.c gained the missing N_DOT N_INDEX-lhs branch. Covers both [N]*Struct and [N]Struct via fldloadop. wwstage already handled [N]*Struct since 7c75dd2; refactored to mirror cstage exactly and added [N]Struct. The spill workaround in dotchainresolve stays (Pike rule); task #14 retires it as a follow-up. Wwstage cgassign N_DOT(N_INDEX,...) silent store-drop discovered in scope, filed as task #16.
This commit is contained in:
@@ -7984,11 +7984,14 @@ export fn dotchainresolve(c: *cgen, n: *node, out: *dotchain) bool = {
|
||||
for (i >= 0) {
|
||||
let csi: *structinfo = structlookup(c, curstruct);
|
||||
if (csi == nil) { return false; };
|
||||
// Materialise the *node first; wwstage's cgen mis-emits the
|
||||
// chained shape `stk[i].str` directly (task #8 — loses BX
|
||||
// between the index load and the field deref), so always
|
||||
// spill to an intermediate local before reading the str
|
||||
// field. The cstage emits the same pattern for byte-identity.
|
||||
// Spill `stk[i]` to a *node local before reading its `.str`.
|
||||
// Task #8 closed the cgen bug behind this — cstage's N_DOT
|
||||
// had no N_INDEX-lhs branch and fell through, returning the
|
||||
// (AX, BX) cgindex shape as if it were the field. The fix
|
||||
// lives in cmd/w6c/cgen.c N_DOT and the mirror in this
|
||||
// module's cgenexpr.ww cgdot. The spill stays for now (Pike
|
||||
// rule — workaround retirement is task #14), so cstage
|
||||
// compiling this source emits byte-identical asm to wwstage.
|
||||
stepnd = stk[i];
|
||||
if (stepnd == nil) { return false; };
|
||||
stepnm = stepnd.str;
|
||||
@@ -9501,13 +9504,15 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// `xs[i].field` — slice/array/ptr-of-struct element field access.
|
||||
// Without this the cgen falls through to the module-qualified
|
||||
// SB fallback below and emits `MOVQ <fld>(SB), AX` (linker
|
||||
// reports `undefined reference to <fld>`). cgexpr(c, lhs)
|
||||
// dispatches to cgindex which leaves the element value in AX
|
||||
// — for a []*T element that's the *T pointer, so we just chain
|
||||
// the field load through (AX).
|
||||
// `arr[i].field` — element-then-field through a `[N]*S` / `[N]S`
|
||||
// (and slice/`*[N]S`) base. Without this the cgen falls through
|
||||
// to the module-qualified SB fallback below and emits
|
||||
// `MOVQ <fld>(SB), AX` (linker: `undefined reference to <fld>`).
|
||||
// One branch covers both shapes: compute `&arr[i]` into BX, then
|
||||
// either deref (`*Struct` element) or move-to-AX (value `Struct`
|
||||
// element), so the leaf load is `(field.offset)(AX)` either way.
|
||||
// Bypasses cgindex deliberately — cgindex's final MOVQ would
|
||||
// truncate a value-struct element to 8 bytes.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_INDEX) {
|
||||
let idxbase: *node = lhs.lhs;
|
||||
@@ -9516,52 +9521,85 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
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; };
|
||||
if (tk == nkind.N_TARRAY) { elemt = tn.lhs; baseisarray = true; };
|
||||
if (tk == nkind.N_TPTR) { elemt = tn.lhs; };
|
||||
if (elemt != nil) { if (elemt.kind == nkind.N_TPTR) {
|
||||
let inner: *node = elemt.lhs;
|
||||
if (inner != nil) { if (inner.kind == nkind.N_TNAME) {
|
||||
let sname: str = inner.str;
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
cgexpr(c, lhs); // AX = *Struct
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((fi.foff + 8): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", X0\n");
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
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, fld)) {
|
||||
let esz: i32 = elemsizeofc(c, tn);
|
||||
cgexpr(c, lhs.rhs); // idx → AX
|
||||
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), AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((fi.foff + 8): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", X0\n");
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};};
|
||||
};};
|
||||
};
|
||||
};
|
||||
};};
|
||||
};};
|
||||
};
|
||||
|
||||
@@ -1451,13 +1451,15 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// `xs[i].field` — slice/array/ptr-of-struct element field access.
|
||||
// Without this the cgen falls through to the module-qualified
|
||||
// SB fallback below and emits `MOVQ <fld>(SB), AX` (linker
|
||||
// reports `undefined reference to <fld>`). cgexpr(c, lhs)
|
||||
// dispatches to cgindex which leaves the element value in AX
|
||||
// — for a []*T element that's the *T pointer, so we just chain
|
||||
// the field load through (AX).
|
||||
// `arr[i].field` — element-then-field through a `[N]*S` / `[N]S`
|
||||
// (and slice/`*[N]S`) base. Without this the cgen falls through
|
||||
// to the module-qualified SB fallback below and emits
|
||||
// `MOVQ <fld>(SB), AX` (linker: `undefined reference to <fld>`).
|
||||
// One branch covers both shapes: compute `&arr[i]` into BX, then
|
||||
// either deref (`*Struct` element) or move-to-AX (value `Struct`
|
||||
// element), so the leaf load is `(field.offset)(AX)` either way.
|
||||
// Bypasses cgindex deliberately — cgindex's final MOVQ would
|
||||
// truncate a value-struct element to 8 bytes.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_INDEX) {
|
||||
let idxbase: *node = lhs.lhs;
|
||||
@@ -1466,52 +1468,85 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
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; };
|
||||
if (tk == nkind.N_TARRAY) { elemt = tn.lhs; baseisarray = true; };
|
||||
if (tk == nkind.N_TPTR) { elemt = tn.lhs; };
|
||||
if (elemt != nil) { if (elemt.kind == nkind.N_TPTR) {
|
||||
let inner: *node = elemt.lhs;
|
||||
if (inner != nil) { if (inner.kind == nkind.N_TNAME) {
|
||||
let sname: str = inner.str;
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
cgexpr(c, lhs); // AX = *Struct
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((fi.foff + 8): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", X0\n");
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
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, fld)) {
|
||||
let esz: i32 = elemsizeofc(c, tn);
|
||||
cgexpr(c, lhs.rhs); // idx → AX
|
||||
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), AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((fi.foff + 8): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", X0\n");
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};};
|
||||
};};
|
||||
};
|
||||
};
|
||||
};};
|
||||
};};
|
||||
};
|
||||
|
||||
@@ -2414,11 +2414,14 @@ export fn dotchainresolve(c: *cgen, n: *node, out: *dotchain) bool = {
|
||||
for (i >= 0) {
|
||||
let csi: *structinfo = structlookup(c, curstruct);
|
||||
if (csi == nil) { return false; };
|
||||
// Materialise the *node first; wwstage's cgen mis-emits the
|
||||
// chained shape `stk[i].str` directly (task #8 — loses BX
|
||||
// between the index load and the field deref), so always
|
||||
// spill to an intermediate local before reading the str
|
||||
// field. The cstage emits the same pattern for byte-identity.
|
||||
// Spill `stk[i]` to a *node local before reading its `.str`.
|
||||
// Task #8 closed the cgen bug behind this — cstage's N_DOT
|
||||
// had no N_INDEX-lhs branch and fell through, returning the
|
||||
// (AX, BX) cgindex shape as if it were the field. The fix
|
||||
// lives in cmd/w6c/cgen.c N_DOT and the mirror in this
|
||||
// module's cgenexpr.ww cgdot. The spill stays for now (Pike
|
||||
// rule — workaround retirement is task #14), so cstage
|
||||
// compiling this source emits byte-identical asm to wwstage.
|
||||
stepnd = stk[i];
|
||||
if (stepnd == nil) { return false; };
|
||||
stepnm = stepnd.str;
|
||||
|
||||
@@ -7984,11 +7984,14 @@ export fn dotchainresolve(c: *cgen, n: *node, out: *dotchain) bool = {
|
||||
for (i >= 0) {
|
||||
let csi: *structinfo = structlookup(c, curstruct);
|
||||
if (csi == nil) { return false; };
|
||||
// Materialise the *node first; wwstage's cgen mis-emits the
|
||||
// chained shape `stk[i].str` directly (task #8 — loses BX
|
||||
// between the index load and the field deref), so always
|
||||
// spill to an intermediate local before reading the str
|
||||
// field. The cstage emits the same pattern for byte-identity.
|
||||
// Spill `stk[i]` to a *node local before reading its `.str`.
|
||||
// Task #8 closed the cgen bug behind this — cstage's N_DOT
|
||||
// had no N_INDEX-lhs branch and fell through, returning the
|
||||
// (AX, BX) cgindex shape as if it were the field. The fix
|
||||
// lives in cmd/w6c/cgen.c N_DOT and the mirror in this
|
||||
// module's cgenexpr.ww cgdot. The spill stays for now (Pike
|
||||
// rule — workaround retirement is task #14), so cstage
|
||||
// compiling this source emits byte-identical asm to wwstage.
|
||||
stepnd = stk[i];
|
||||
if (stepnd == nil) { return false; };
|
||||
stepnm = stepnd.str;
|
||||
@@ -9501,13 +9504,15 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// `xs[i].field` — slice/array/ptr-of-struct element field access.
|
||||
// Without this the cgen falls through to the module-qualified
|
||||
// SB fallback below and emits `MOVQ <fld>(SB), AX` (linker
|
||||
// reports `undefined reference to <fld>`). cgexpr(c, lhs)
|
||||
// dispatches to cgindex which leaves the element value in AX
|
||||
// — for a []*T element that's the *T pointer, so we just chain
|
||||
// the field load through (AX).
|
||||
// `arr[i].field` — element-then-field through a `[N]*S` / `[N]S`
|
||||
// (and slice/`*[N]S`) base. Without this the cgen falls through
|
||||
// to the module-qualified SB fallback below and emits
|
||||
// `MOVQ <fld>(SB), AX` (linker: `undefined reference to <fld>`).
|
||||
// One branch covers both shapes: compute `&arr[i]` into BX, then
|
||||
// either deref (`*Struct` element) or move-to-AX (value `Struct`
|
||||
// element), so the leaf load is `(field.offset)(AX)` either way.
|
||||
// Bypasses cgindex deliberately — cgindex's final MOVQ would
|
||||
// truncate a value-struct element to 8 bytes.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_INDEX) {
|
||||
let idxbase: *node = lhs.lhs;
|
||||
@@ -9516,52 +9521,85 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
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; };
|
||||
if (tk == nkind.N_TARRAY) { elemt = tn.lhs; baseisarray = true; };
|
||||
if (tk == nkind.N_TPTR) { elemt = tn.lhs; };
|
||||
if (elemt != nil) { if (elemt.kind == nkind.N_TPTR) {
|
||||
let inner: *node = elemt.lhs;
|
||||
if (inner != nil) { if (inner.kind == nkind.N_TNAME) {
|
||||
let sname: str = inner.str;
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
cgexpr(c, lhs); // AX = *Struct
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((fi.foff + 8): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", X0\n");
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
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, fld)) {
|
||||
let esz: i32 = elemsizeofc(c, tn);
|
||||
cgexpr(c, lhs.rhs); // idx → AX
|
||||
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), AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((fi.foff + 8): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
if (isfloattype(c, fi.tnode)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, fi.tnode)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", X0\n");
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};};
|
||||
};};
|
||||
};
|
||||
};
|
||||
};};
|
||||
};};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user