selfhost: cgfnparams variadic T... straddle stitch (closes #12)
Last reg/stack-straddle gap closed — variadic T... now stitches at idx=5/regs_left=1/nw=3. Four classes (tagged/slice/str/variadic) at cgendecl.ww 467/518/564/394 are now structurally symmetric. cgfn pre-scan predicate widened to (istg || issl || isst || isvar). cstage unchanged — type-promoted T... → []T already hits the slice partial-fit branch.
This commit is contained in:
@@ -13910,10 +13910,37 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
emitoff((off + 16): i64);
|
emitoff((off + 16): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
idx += 1;
|
idx += 1;
|
||||||
|
} else { if (idx < 6) {
|
||||||
|
// Partial-fit stitch — variadic `T...` is a slice
|
||||||
|
// at the ABI boundary (the call site synthesises a
|
||||||
|
// 24B descriptor and pushes ptr/len/cap), so this
|
||||||
|
// mirrors the slice branch at cgendecl.ww:518.
|
||||||
|
let off: i32 = localadd(c, nm, 24, tn);
|
||||||
|
let regs_left: i32 = 6 - idx;
|
||||||
|
let w: i32 = 0;
|
||||||
|
for (w < regs_left) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(argregname(idx));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + w*8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
idx += 1;
|
||||||
|
w += 1;
|
||||||
|
};
|
||||||
|
for (w < 3) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((16 + stkcursor*8): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((off + w*8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
stkcursor += 1;
|
||||||
|
w += 1;
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
localaddstack(c, nm, tn, 16 + stkcursor*8);
|
localaddstack(c, nm, tn, 16 + stkcursor*8);
|
||||||
stkcursor += 3;
|
stkcursor += 3;
|
||||||
};
|
};};
|
||||||
p = p.next;
|
p = p.next;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -14180,15 +14207,13 @@ fn cgfn(c: *cgen, fn_: *node) void = {
|
|||||||
frame += sz;
|
frame += sz;
|
||||||
if (isf) { fargi += 1; }
|
if (isf) { fargi += 1; }
|
||||||
else { argi += eb; };
|
else { argi += eb; };
|
||||||
} else { if (eb > 1 && regs_left > 0 && (istg || issl || isst)) {
|
} else { if (eb > 1 && regs_left > 0 && (istg || issl || isst || isvar)) {
|
||||||
// Multi-word param straddles the reg/stack boundary;
|
// Multi-word param straddles the reg/stack boundary;
|
||||||
// cgfnparams stitches the tail from positive BP
|
// cgfnparams stitches the tail from positive BP
|
||||||
// offsets into a single local slot, so we still
|
// offsets into a single local slot, so we still
|
||||||
// reserve the full size. Symmetric across tagged,
|
// reserve the full size. Symmetric across tagged,
|
||||||
// slice and str (cgendecl.ww:440/491/537). Variadic
|
// slice, str and variadic `T...`
|
||||||
// `T...` is deliberately omitted (task #12) — the
|
// (cgendecl.ww:467/518/564/394).
|
||||||
// cgfnparams variadic branch doesn't stitch yet, so
|
|
||||||
// it falls through to the pure-stack accounting.
|
|
||||||
frame += sz;
|
frame += sz;
|
||||||
argi = 6;
|
argi = 6;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -391,10 +391,37 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
emitoff((off + 16): i64);
|
emitoff((off + 16): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
idx += 1;
|
idx += 1;
|
||||||
|
} else { if (idx < 6) {
|
||||||
|
// Partial-fit stitch — variadic `T...` is a slice
|
||||||
|
// at the ABI boundary (the call site synthesises a
|
||||||
|
// 24B descriptor and pushes ptr/len/cap), so this
|
||||||
|
// mirrors the slice branch at cgendecl.ww:518.
|
||||||
|
let off: i32 = localadd(c, nm, 24, tn);
|
||||||
|
let regs_left: i32 = 6 - idx;
|
||||||
|
let w: i32 = 0;
|
||||||
|
for (w < regs_left) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(argregname(idx));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + w*8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
idx += 1;
|
||||||
|
w += 1;
|
||||||
|
};
|
||||||
|
for (w < 3) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((16 + stkcursor*8): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((off + w*8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
stkcursor += 1;
|
||||||
|
w += 1;
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
localaddstack(c, nm, tn, 16 + stkcursor*8);
|
localaddstack(c, nm, tn, 16 + stkcursor*8);
|
||||||
stkcursor += 3;
|
stkcursor += 3;
|
||||||
};
|
};};
|
||||||
p = p.next;
|
p = p.next;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -661,15 +688,13 @@ fn cgfn(c: *cgen, fn_: *node) void = {
|
|||||||
frame += sz;
|
frame += sz;
|
||||||
if (isf) { fargi += 1; }
|
if (isf) { fargi += 1; }
|
||||||
else { argi += eb; };
|
else { argi += eb; };
|
||||||
} else { if (eb > 1 && regs_left > 0 && (istg || issl || isst)) {
|
} else { if (eb > 1 && regs_left > 0 && (istg || issl || isst || isvar)) {
|
||||||
// Multi-word param straddles the reg/stack boundary;
|
// Multi-word param straddles the reg/stack boundary;
|
||||||
// cgfnparams stitches the tail from positive BP
|
// cgfnparams stitches the tail from positive BP
|
||||||
// offsets into a single local slot, so we still
|
// offsets into a single local slot, so we still
|
||||||
// reserve the full size. Symmetric across tagged,
|
// reserve the full size. Symmetric across tagged,
|
||||||
// slice and str (cgendecl.ww:440/491/537). Variadic
|
// slice, str and variadic `T...`
|
||||||
// `T...` is deliberately omitted (task #12) — the
|
// (cgendecl.ww:467/518/564/394).
|
||||||
// cgfnparams variadic branch doesn't stitch yet, so
|
|
||||||
// it falls through to the pure-stack accounting.
|
|
||||||
frame += sz;
|
frame += sz;
|
||||||
argi = 6;
|
argi = 6;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -13910,10 +13910,37 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
emitoff((off + 16): i64);
|
emitoff((off + 16): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
idx += 1;
|
idx += 1;
|
||||||
|
} else { if (idx < 6) {
|
||||||
|
// Partial-fit stitch — variadic `T...` is a slice
|
||||||
|
// at the ABI boundary (the call site synthesises a
|
||||||
|
// 24B descriptor and pushes ptr/len/cap), so this
|
||||||
|
// mirrors the slice branch at cgendecl.ww:518.
|
||||||
|
let off: i32 = localadd(c, nm, 24, tn);
|
||||||
|
let regs_left: i32 = 6 - idx;
|
||||||
|
let w: i32 = 0;
|
||||||
|
for (w < regs_left) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(argregname(idx));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + w*8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
idx += 1;
|
||||||
|
w += 1;
|
||||||
|
};
|
||||||
|
for (w < 3) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((16 + stkcursor*8): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((off + w*8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
stkcursor += 1;
|
||||||
|
w += 1;
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
localaddstack(c, nm, tn, 16 + stkcursor*8);
|
localaddstack(c, nm, tn, 16 + stkcursor*8);
|
||||||
stkcursor += 3;
|
stkcursor += 3;
|
||||||
};
|
};};
|
||||||
p = p.next;
|
p = p.next;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -14180,15 +14207,13 @@ fn cgfn(c: *cgen, fn_: *node) void = {
|
|||||||
frame += sz;
|
frame += sz;
|
||||||
if (isf) { fargi += 1; }
|
if (isf) { fargi += 1; }
|
||||||
else { argi += eb; };
|
else { argi += eb; };
|
||||||
} else { if (eb > 1 && regs_left > 0 && (istg || issl || isst)) {
|
} else { if (eb > 1 && regs_left > 0 && (istg || issl || isst || isvar)) {
|
||||||
// Multi-word param straddles the reg/stack boundary;
|
// Multi-word param straddles the reg/stack boundary;
|
||||||
// cgfnparams stitches the tail from positive BP
|
// cgfnparams stitches the tail from positive BP
|
||||||
// offsets into a single local slot, so we still
|
// offsets into a single local slot, so we still
|
||||||
// reserve the full size. Symmetric across tagged,
|
// reserve the full size. Symmetric across tagged,
|
||||||
// slice and str (cgendecl.ww:440/491/537). Variadic
|
// slice, str and variadic `T...`
|
||||||
// `T...` is deliberately omitted (task #12) — the
|
// (cgendecl.ww:467/518/564/394).
|
||||||
// cgfnparams variadic branch doesn't stitch yet, so
|
|
||||||
// it falls through to the pure-stack accounting.
|
|
||||||
frame += sz;
|
frame += sz;
|
||||||
argi = 6;
|
argi = 6;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -209,6 +209,65 @@ static const struct row rows[] = {
|
|||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
"};\n",
|
"};\n",
|
||||||
42 },
|
42 },
|
||||||
|
/* Variadic `T...` fully in regs: 3 i64 + 1 variadic. idx=3
|
||||||
|
* entering the synthesised slice (regs_left=3, nw=3) — DI/SI/DX
|
||||||
|
* carry a/b/c, CX/R8/R9 carry ptr/len/cap. Full-reg-fit regression:
|
||||||
|
* pins that the stitch addition doesn't shadow the `idx+3 <= 6`
|
||||||
|
* branch. */
|
||||||
|
{ "variadic_full_in_reg",
|
||||||
|
"fn vs(a: i64, b: i64, c: i64, xs: i64...) i64 = {\n"
|
||||||
|
" let i: i32 = 0;\n"
|
||||||
|
" let acc: i64 = a + b + c;\n"
|
||||||
|
" for (i < xs.len: i32) { acc = acc + xs[i]; i = i + 1; };\n"
|
||||||
|
" return acc + (xs.cap: i64);\n"
|
||||||
|
"};\n"
|
||||||
|
"fn main() i32 = {\n"
|
||||||
|
" let r: i64 = vs(1i64, 2i64, 3i64,\n"
|
||||||
|
" 10i64, 20i64, 30i64);\n"
|
||||||
|
" if (r == 69i64) { return 42; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n",
|
||||||
|
42 },
|
||||||
|
/* Variadic `T...` at the reg/stack straddle: 5 i64 + 1 variadic.
|
||||||
|
* idx=5 entering the synthesised slice (regs_left=1, nw=3) — ptr
|
||||||
|
* lands in R9, len and cap spill to +16/+24(BP). The variadic
|
||||||
|
* branch in cgfnparams must stitch identically to the slice branch
|
||||||
|
* (task #12). The body sums the fixed args, the variadic
|
||||||
|
* elements, and adds cap to pin the third header word. */
|
||||||
|
{ "variadic_straddle",
|
||||||
|
"fn vs(a: i64, b: i64, c: i64, d: i64, e: i64, xs: i64...) i64 = {\n"
|
||||||
|
" let i: i32 = 0;\n"
|
||||||
|
" let acc: i64 = a + b + c + d + e;\n"
|
||||||
|
" for (i < xs.len: i32) { acc = acc + xs[i]; i = i + 1; };\n"
|
||||||
|
" return acc + (xs.cap: i64);\n"
|
||||||
|
"};\n"
|
||||||
|
"fn main() i32 = {\n"
|
||||||
|
" let r: i64 = vs(1i64, 2i64, 3i64, 4i64, 5i64,\n"
|
||||||
|
" 10i64, 20i64, 30i64);\n"
|
||||||
|
" if (r == 78i64) { return 42; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n",
|
||||||
|
42 },
|
||||||
|
/* Variadic `T...` past the register window: 6 i64 saturate argi,
|
||||||
|
* the synthesised slice (3 eightbytes) goes wholly to the stack
|
||||||
|
* via localaddstack. Pure-stack regression check — pins that the
|
||||||
|
* new stitch code doesn't bleed into the existing pure-stack
|
||||||
|
* branch (regs_left=0, nw=3). */
|
||||||
|
{ "variadic_purestack",
|
||||||
|
"fn vs(a: i64, b: i64, c: i64, d: i64, e: i64, f: i64,\n"
|
||||||
|
" xs: i64...) i64 = {\n"
|
||||||
|
" let i: i32 = 0;\n"
|
||||||
|
" let acc: i64 = a + b + c + d + e + f;\n"
|
||||||
|
" for (i < xs.len: i32) { acc = acc + xs[i]; i = i + 1; };\n"
|
||||||
|
" return acc + (xs.cap: i64);\n"
|
||||||
|
"};\n"
|
||||||
|
"fn main() i32 = {\n"
|
||||||
|
" let r: i64 = vs(1i64, 2i64, 3i64, 4i64, 5i64, 6i64,\n"
|
||||||
|
" 10i64, 20i64, 30i64);\n"
|
||||||
|
" if (r == 84i64) { return 42; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n",
|
||||||
|
42 },
|
||||||
/* str past the register window: 6 ints saturate argi, the str
|
/* str past the register window: 6 ints saturate argi, the str
|
||||||
* (2 eightbytes) goes wholly to the stack via localaddstack.
|
* (2 eightbytes) goes wholly to the stack via localaddstack.
|
||||||
* Both .ptr and .len must round-trip. */
|
* Both .ptr and .len must round-trip. */
|
||||||
|
|||||||
Reference in New Issue
Block a user