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:
2026-05-14 00:36:34 +09:00
parent f2b47087a2
commit f26c86f5b7
4 changed files with 152 additions and 18 deletions

View File

@@ -13910,10 +13910,37 @@ fn cgfnparams(c: *cgen, params: *node) void = {
emitoff((off + 16): i64);
emitline("(BP)\n");
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 {
localaddstack(c, nm, tn, 16 + stkcursor*8);
stkcursor += 3;
};
};};
p = p.next;
continue;
};
@@ -14180,15 +14207,13 @@ fn cgfn(c: *cgen, fn_: *node) void = {
frame += sz;
if (isf) { fargi += 1; }
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;
// cgfnparams stitches the tail from positive BP
// offsets into a single local slot, so we still
// reserve the full size. Symmetric across tagged,
// slice and str (cgendecl.ww:440/491/537). Variadic
// `T...` is deliberately omitted (task #12) — the
// cgfnparams variadic branch doesn't stitch yet, so
// it falls through to the pure-stack accounting.
// slice, str and variadic `T...`
// (cgendecl.ww:467/518/564/394).
frame += sz;
argi = 6;
} else {

View File

@@ -391,10 +391,37 @@ fn cgfnparams(c: *cgen, params: *node) void = {
emitoff((off + 16): i64);
emitline("(BP)\n");
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 {
localaddstack(c, nm, tn, 16 + stkcursor*8);
stkcursor += 3;
};
};};
p = p.next;
continue;
};
@@ -661,15 +688,13 @@ fn cgfn(c: *cgen, fn_: *node) void = {
frame += sz;
if (isf) { fargi += 1; }
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;
// cgfnparams stitches the tail from positive BP
// offsets into a single local slot, so we still
// reserve the full size. Symmetric across tagged,
// slice and str (cgendecl.ww:440/491/537). Variadic
// `T...` is deliberately omitted (task #12) — the
// cgfnparams variadic branch doesn't stitch yet, so
// it falls through to the pure-stack accounting.
// slice, str and variadic `T...`
// (cgendecl.ww:467/518/564/394).
frame += sz;
argi = 6;
} else {

View File

@@ -13910,10 +13910,37 @@ fn cgfnparams(c: *cgen, params: *node) void = {
emitoff((off + 16): i64);
emitline("(BP)\n");
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 {
localaddstack(c, nm, tn, 16 + stkcursor*8);
stkcursor += 3;
};
};};
p = p.next;
continue;
};
@@ -14180,15 +14207,13 @@ fn cgfn(c: *cgen, fn_: *node) void = {
frame += sz;
if (isf) { fargi += 1; }
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;
// cgfnparams stitches the tail from positive BP
// offsets into a single local slot, so we still
// reserve the full size. Symmetric across tagged,
// slice and str (cgendecl.ww:440/491/537). Variadic
// `T...` is deliberately omitted (task #12) — the
// cgfnparams variadic branch doesn't stitch yet, so
// it falls through to the pure-stack accounting.
// slice, str and variadic `T...`
// (cgendecl.ww:467/518/564/394).
frame += sz;
argi = 6;
} else {