w6c+selfhost: cgen N_DOT slice-field through *T root in call args (closes #29)

This commit is contained in:
2026-05-14 23:29:35 +09:00
parent 9706513e59
commit 6402d8deb7
7 changed files with 857 additions and 24 deletions

View File

@@ -1202,6 +1202,21 @@ fn cgdot(c: *cgen, n: *node) void = {
emitdispreg(fi.foff: i64, "BX");
emitline(", AX\n");
emitline("\tMOVQ\tCX, BX\n");
} else { if (isslicetype(c, fi.tnode)) {
// slice field via *struct: load
// (ptr, len, cap) into (AX, BX, CX).
// BX holds the *struct pointer, so
// load .len LAST so the earlier
// reads still index off the base.
emitline("\tMOVQ\t");
emitdispreg(fi.foff: i64, "BX");
emitline(", AX\n");
emitline("\tMOVQ\t");
emitdispreg((fi.foff + 16): i64, "BX");
emitline(", CX\n");
emitline("\tMOVQ\t");
emitdispreg((fi.foff + 8): i64, "BX");
emitline(", BX\n");
} else { if (isfloattype(c, fi.tnode)) {
// f64/f32 via *struct: route through X0.
// MOVQ into AX leaves the SSE reg stale
@@ -1222,7 +1237,7 @@ fn cgdot(c: *cgen, n: *node) void = {
emitline("\t");
emitdispreg(fi.foff: i64, "BX");
emitline(", AX\n");
}; };
}; }; };
return;
};
fi = fi.finext;
@@ -1248,6 +1263,19 @@ fn cgdot(c: *cgen, n: *node) void = {
emitline("\tMOVQ\t");
emitoff((lc.off + fi.foff + 8): i64);
emitline("(BP), BX\n");
} else { if (isslicetype(c, fi.tnode)) {
// slice field: load (ptr, len, cap)
// into (AX, BX, CX). Base is BP so
// no aliasing — order doesn't matter.
emitline("\tMOVQ\t");
emitoff((lc.off + fi.foff): i64);
emitline("(BP), AX\n");
emitline("\tMOVQ\t");
emitoff((lc.off + fi.foff + 8): i64);
emitline("(BP), BX\n");
emitline("\tMOVQ\t");
emitoff((lc.off + fi.foff + 16): i64);
emitline("(BP), CX\n");
} else { if (isfloattype(c, fi.tnode)) {
// f64/f32 field: route through X0.
let mov: str = "MOVSD";
@@ -1264,7 +1292,7 @@ fn cgdot(c: *cgen, n: *node) void = {
emitline("\t");
emitoff((lc.off + fi.foff): i64);
emitline("(BP), AX\n");
}; };
}; }; };
return;
};
fi = fi.finext;
@@ -1673,6 +1701,45 @@ fn cgdot(c: *cgen, n: *node) void = {
};
return;
};
if (isslicetype(c, leaffi.tnode)) {
// Slice leaf: load all three header words into
// (AX=ptr, BX=len, CX=cap). For the viacx path
// (global or `*T` root) CX is the base; load
// .cap LAST so the base survives the earlier
// reads. For BP-rooted locals the registers
// don't alias so order is free.
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");
emitline("\tMOVQ\t");
emitdispreg((totaloff + 8): i64, "CX");
emitline(", BX\n");
emitline("\tMOVQ\t");
emitdispreg((totaloff + 16): i64, "CX");
emitline(", CX\n");
} else {
emitline("\tMOVQ\t");
emitoff((rootoff + totaloff): i64);
emitline("(BP), AX\n");
emitline("\tMOVQ\t");
emitoff((rootoff + totaloff + 8): i64);
emitline("(BP), BX\n");
emitline("\tMOVQ\t");
emitoff((rootoff + totaloff + 16): i64);
emitline("(BP), CX\n");
};
return;
};
if (isfloattype(c, leaffi.tnode)) {
let mov: str = "MOVSD";
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
@@ -1767,6 +1834,22 @@ fn cgdot(c: *cgen, n: *node) void = {
emitline(", AX\n");
return;
};
// slice field: load (ptr, len, cap)
// into (AX, BX, CX). AX is the *struct
// base, so load .ptr (which targets
// AX) LAST.
if (isslicetype(c, fi.tnode)) {
emitline("\tMOVQ\t");
emitdispreg((fi.foff + 8): i64, "AX");
emitline(", BX\n");
emitline("\tMOVQ\t");
emitdispreg((fi.foff + 16): i64, "AX");
emitline(", CX\n");
emitline("\tMOVQ\t");
emitdispreg(fi.foff: i64, "AX");
emitline(", AX\n");
return;
};
// f64/f32 chained field: route through X0.
if (isfloattype(c, fi.tnode)) {
let mov: str = "MOVSD";