cmd/w6c+selfhost/wcc: route cgparam/MLET/spill sizes through SSoT
#43 (8e93b31+087c85c) routed many sizeof(str) / sizeof(slice) sites through primtypesize / tyslicesize / ty_*->size, but missed the cgparam regs-fit, cgparam stack-stitch, cgmlet mixed scalar+str receive, and vararg slice gather paths in both stages. A bare #1 bump (str→24B) on top of #43 reds ~60 tests because those paths still hardcoded 16/24. Cstage: - cgen.c:7360-7361 cgmlet: sz0/sz1 → (int)u0->size / (int)u1->size. - cgen.c:7557 cgparam regs-fit: slice|is_str → (int)pu->size. - cgen.c:7586 cgparam stack-stitch: same. - cgen.c:4368 cgcall vararg gather: localoff slice descriptor → (int)vsu->size (the cstage twin of cgenexpr.ww:3084). Wwstage: - cgendecl.ww:225, :243 cgfnparams: 16 → primtypesize("str"): i32. - cgenexpr.ww:3084 cgcall vararg gather: 24 → tyslicesize(): i32. Plus a latent-bug fix at cgenstmt.ww cglet :1031 / :1040: the str-init and slice-init arms dispatched on size only. Under #1's str→24, both arms would have fired on a str let (duplicate MOVQ BX,off+8 + bogus MOVQ CX,off+8). Added isstrtype / isslicetype kind gates mirroring cstage cgen.c:6439's `type_isstr(lt) && sz == ty_str->size`. Zero asm change today because the size constants implicitly disambiguate at 16 vs 24. Probe with temporary #1 bump (str.size=24) confirms 990_selfhost + 994_w6c_ww go green — the cgen-routing slice for #1 is now closed. Remaining red under bump is lib/ww/typ.ww's parallel SSoT seed + stringstest cap*16u64 strides + w6l_ww runtime SIGSEGV; all tracked separately. EIGHTBYTES register-count sites (cgen.c:7553-7554, cgendecl.ww:224 /:260) intentionally NOT touched — those are str ABI in-flight 3-reg work (task #34), not slot-width SSoT.
This commit is contained in:
@@ -4364,8 +4364,12 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
dname, nvar * esz, cg_frame);
|
dname, nvar * esz, cg_frame);
|
||||||
}
|
}
|
||||||
const char *slname = mklabel(c, "vararg_sl");
|
const char *slname = mklabel(c, "vararg_sl");
|
||||||
|
/* #60: route slice-descriptor width through
|
||||||
|
* vsu->size so a future slice-header bump
|
||||||
|
* propagates (mirrors wwstage cgcall vararg
|
||||||
|
* gather using tyslicesize()). */
|
||||||
int sloff = localoff(c, &locals,
|
int sloff = localoff(c, &locals,
|
||||||
slname, 24, cg_frame);
|
slname, (int)vsu->size, cg_frame);
|
||||||
if (nvar > 0) {
|
if (nvar > 0) {
|
||||||
int v_is_tagged = velem &&
|
int v_is_tagged = velem &&
|
||||||
tagged_arg_size(velem) > 0;
|
tagged_arg_size(velem) > 0;
|
||||||
@@ -7357,8 +7361,10 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
|||||||
int s0_is_str = u0 && u0->kind == TY_STR;
|
int s0_is_str = u0 && u0->kind == TY_STR;
|
||||||
int s1_is_str = u1 && u1->kind == TY_STR;
|
int s1_is_str = u1 && u1->kind == TY_STR;
|
||||||
if (l0 && l1 && (s0_is_str ^ s1_is_str)) {
|
if (l0 && l1 && (s0_is_str ^ s1_is_str)) {
|
||||||
int sz0 = s0_is_str ? 16 : 8;
|
/* #60: route str-slot width through ty_str->size so #1
|
||||||
int sz1 = s1_is_str ? 16 : 8;
|
* propagates here. Scalar side keeps the 8B slot. */
|
||||||
|
int sz0 = s0_is_str ? (int)u0->size : 8;
|
||||||
|
int sz1 = s1_is_str ? (int)u1->size : 8;
|
||||||
int off0 = localoff(c, locals, l0->str, sz0, frame);
|
int off0 = localoff(c, locals, l0->str, sz0, frame);
|
||||||
int off1 = localoff(c, locals, l1->str, sz1, frame);
|
int off1 = localoff(c, locals, l1->str, sz1, frame);
|
||||||
if (s0_is_str) {
|
if (s0_is_str) {
|
||||||
@@ -7554,9 +7560,12 @@ cgfn(Cg *c, FILE *out, Node *fn)
|
|||||||
(is_tagged ? tagged_eb : 1)));
|
(is_tagged ? tagged_eb : 1)));
|
||||||
int regs_left = isf ? (8 - fargi) : (6 - argi);
|
int regs_left = isf ? (8 - fargi) : (6 - argi);
|
||||||
if (regs_left >= eightbytes) {
|
if (regs_left >= eightbytes) {
|
||||||
int sz = slice ? 24 : (is_str ? 16 :
|
/* #60: route slice/str slot widths through Type.size SSoT
|
||||||
|
* so #1's ty_str.size bump propagates without retouching
|
||||||
|
* this site (or its stack-stitch mirror below). */
|
||||||
|
int sz = (slice || is_str) ? (int)pu->size :
|
||||||
(is_struct ? (int)pu->size :
|
(is_struct ? (int)pu->size :
|
||||||
(is_tagged ? tagged_sz : 8)));
|
(is_tagged ? tagged_sz : 8));
|
||||||
int off = localoff(c, &locals, p->str, sz, &frame);
|
int off = localoff(c, &locals, p->str, sz, &frame);
|
||||||
if (slice || is_str || is_struct || is_tagged) {
|
if (slice || is_str || is_struct || is_tagged) {
|
||||||
for (int k = 0; k < eightbytes; k++, argi++)
|
for (int k = 0; k < eightbytes; k++, argi++)
|
||||||
@@ -7583,9 +7592,10 @@ cgfn(Cg *c, FILE *out, Node *fn)
|
|||||||
* slot from both sources so the body sees a contiguous
|
* slot from both sources so the body sees a contiguous
|
||||||
* value. Mirrors the SysV greedy reg fill the caller
|
* value. Mirrors the SysV greedy reg fill the caller
|
||||||
* does. */
|
* does. */
|
||||||
int sz = slice ? 24 : (is_str ? 16 :
|
/* #60: same SSoT routing as the regs-fit arm above. */
|
||||||
|
int sz = (slice || is_str) ? (int)pu->size :
|
||||||
(is_struct ? (int)pu->size :
|
(is_struct ? (int)pu->size :
|
||||||
(is_tagged ? tagged_sz : 8)));
|
(is_tagged ? tagged_sz : 8));
|
||||||
int off = localoff(c, &locals, p->str, sz, &frame);
|
int off = localoff(c, &locals, p->str, sz, &frame);
|
||||||
extern int cg_stack_arg_cursor;
|
extern int cg_stack_arg_cursor;
|
||||||
int k = 0;
|
int k = 0;
|
||||||
|
|||||||
@@ -15708,7 +15708,10 @@ fn cgcall(c: *cgen, n: *node) void = {
|
|||||||
if (nvar > 0) {
|
if (nvar > 0) {
|
||||||
doff = localadd(c, dname, nvar * esz, nil);
|
doff = localadd(c, dname, nvar * esz, nil);
|
||||||
};
|
};
|
||||||
let soff: i32 = localadd(c, sname, 24,
|
// #60: vararg gather builds a {ptr,len,cap} slice
|
||||||
|
// descriptor — route through tyslicesize so #34's
|
||||||
|
// slice-header bump propagates here.
|
||||||
|
let soff: i32 = localadd(c, sname, tyslicesize(): i32,
|
||||||
slicewrap(c, varp.lhs));
|
slicewrap(c, varp.lhs));
|
||||||
let aa2: *node = n.list;
|
let aa2: *node = n.list;
|
||||||
let kk3: i32 = 0;
|
let kk3: i32 = 0;
|
||||||
@@ -19433,20 +19436,19 @@ fn cglet(c: *cgen, n: *node) void = {
|
|||||||
emitoff(off: i64);
|
emitoff(off: i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
// str init: cgexpr also leaves len in BX; store both.
|
// str init: cgexpr also leaves len in BX; store both.
|
||||||
// #43: route through primtypesize so #1's str-size bump
|
// #60: gate by kind too — under #1's str=24 bump, sizeof(str)
|
||||||
// surfaces this site (today sz==16 picks str; once str=24,
|
// and sizeof(slice) collide, so a bare `sz ==` check fires
|
||||||
// the in-flight str ABI (#34) must propagate cap and the
|
// both branches for one let. Mirrors cstage cgen.c:6439's
|
||||||
// dispatch needs reshaping by kind, not raw size).
|
// `type_isstr(lt) && sz == ty_str->size` shape.
|
||||||
if (sz == primtypesize("str"): i32) {
|
if (isstrtype(c, tn) && sz == primtypesize("str"): i32) {
|
||||||
emitline("\tMOVQ\tBX, ");
|
emitline("\tMOVQ\tBX, ");
|
||||||
emitoff((off + 8): i64);
|
emitoff((off + 8): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
};
|
};
|
||||||
// slice init: ptr/len/cap in AX/BX/CX.
|
// slice init: ptr/len/cap in AX/BX/CX. Same kind+size gate as
|
||||||
// #43: same routing — bare `sz == 24` would collide with a
|
// the str arm — without the kind check this fires on a str let
|
||||||
// 24B str slot under #1; the kind disambiguation lives at
|
// once sz==24 (#60).
|
||||||
// the caller (cglet's tn.kind == N_TSLICE shape check).
|
if (isslicetype(c, tn) && sz == tyslicesize(): i32) {
|
||||||
if (sz == tyslicesize(): i32) {
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
emitline("\tMOVQ\tBX, ");
|
||||||
emitoff((off + 8): i64);
|
emitoff((off + 8): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
@@ -20271,7 +20273,11 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
};};
|
};};
|
||||||
} else { if (isstrtype(c, p.lhs)) {
|
} else { if (isstrtype(c, p.lhs)) {
|
||||||
if (idx + 2 <= 6) {
|
if (idx + 2 <= 6) {
|
||||||
let off: i32 = localadd(c, nm, 16, p.lhs);
|
// #60: route str-param slot width through the
|
||||||
|
// primtypesize SSoT so #1's ty_str bump propagates
|
||||||
|
// here (parent #43 covered the reg-fill site only
|
||||||
|
// inside cgexpr).
|
||||||
|
let off: i32 = localadd(c, nm, primtypesize("str"): i32, p.lhs);
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
emitline(argregname(idx));
|
emitline(argregname(idx));
|
||||||
emitline(", ");
|
emitline(", ");
|
||||||
@@ -20289,7 +20295,8 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
// 440-469. Only idx=5 hits this (nw=2,
|
// 440-469. Only idx=5 hits this (nw=2,
|
||||||
// regs_left=1): ptr lands in R9, len at
|
// regs_left=1): ptr lands in R9, len at
|
||||||
// +16+stkcursor*8(BP).
|
// +16+stkcursor*8(BP).
|
||||||
let off: i32 = localadd(c, nm, 16, p.lhs);
|
// #60: same SSoT routing as the regs-fit arm above.
|
||||||
|
let off: i32 = localadd(c, nm, primtypesize("str"): i32, p.lhs);
|
||||||
let regs_left: i32 = 6 - idx;
|
let regs_left: i32 = 6 - idx;
|
||||||
let w: i32 = 0;
|
let w: i32 = 0;
|
||||||
for (w < regs_left) {
|
for (w < regs_left) {
|
||||||
|
|||||||
@@ -222,7 +222,11 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
};};
|
};};
|
||||||
} else { if (isstrtype(c, p.lhs)) {
|
} else { if (isstrtype(c, p.lhs)) {
|
||||||
if (idx + 2 <= 6) {
|
if (idx + 2 <= 6) {
|
||||||
let off: i32 = localadd(c, nm, 16, p.lhs);
|
// #60: route str-param slot width through the
|
||||||
|
// primtypesize SSoT so #1's ty_str bump propagates
|
||||||
|
// here (parent #43 covered the reg-fill site only
|
||||||
|
// inside cgexpr).
|
||||||
|
let off: i32 = localadd(c, nm, primtypesize("str"): i32, p.lhs);
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
emitline(argregname(idx));
|
emitline(argregname(idx));
|
||||||
emitline(", ");
|
emitline(", ");
|
||||||
@@ -240,7 +244,8 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
// 440-469. Only idx=5 hits this (nw=2,
|
// 440-469. Only idx=5 hits this (nw=2,
|
||||||
// regs_left=1): ptr lands in R9, len at
|
// regs_left=1): ptr lands in R9, len at
|
||||||
// +16+stkcursor*8(BP).
|
// +16+stkcursor*8(BP).
|
||||||
let off: i32 = localadd(c, nm, 16, p.lhs);
|
// #60: same SSoT routing as the regs-fit arm above.
|
||||||
|
let off: i32 = localadd(c, nm, primtypesize("str"): i32, p.lhs);
|
||||||
let regs_left: i32 = 6 - idx;
|
let regs_left: i32 = 6 - idx;
|
||||||
let w: i32 = 0;
|
let w: i32 = 0;
|
||||||
for (w < regs_left) {
|
for (w < regs_left) {
|
||||||
|
|||||||
@@ -3081,7 +3081,10 @@ fn cgcall(c: *cgen, n: *node) void = {
|
|||||||
if (nvar > 0) {
|
if (nvar > 0) {
|
||||||
doff = localadd(c, dname, nvar * esz, nil);
|
doff = localadd(c, dname, nvar * esz, nil);
|
||||||
};
|
};
|
||||||
let soff: i32 = localadd(c, sname, 24,
|
// #60: vararg gather builds a {ptr,len,cap} slice
|
||||||
|
// descriptor — route through tyslicesize so #34's
|
||||||
|
// slice-header bump propagates here.
|
||||||
|
let soff: i32 = localadd(c, sname, tyslicesize(): i32,
|
||||||
slicewrap(c, varp.lhs));
|
slicewrap(c, varp.lhs));
|
||||||
let aa2: *node = n.list;
|
let aa2: *node = n.list;
|
||||||
let kk3: i32 = 0;
|
let kk3: i32 = 0;
|
||||||
|
|||||||
@@ -1024,20 +1024,19 @@ fn cglet(c: *cgen, n: *node) void = {
|
|||||||
emitoff(off: i64);
|
emitoff(off: i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
// str init: cgexpr also leaves len in BX; store both.
|
// str init: cgexpr also leaves len in BX; store both.
|
||||||
// #43: route through primtypesize so #1's str-size bump
|
// #60: gate by kind too — under #1's str=24 bump, sizeof(str)
|
||||||
// surfaces this site (today sz==16 picks str; once str=24,
|
// and sizeof(slice) collide, so a bare `sz ==` check fires
|
||||||
// the in-flight str ABI (#34) must propagate cap and the
|
// both branches for one let. Mirrors cstage cgen.c:6439's
|
||||||
// dispatch needs reshaping by kind, not raw size).
|
// `type_isstr(lt) && sz == ty_str->size` shape.
|
||||||
if (sz == primtypesize("str"): i32) {
|
if (isstrtype(c, tn) && sz == primtypesize("str"): i32) {
|
||||||
emitline("\tMOVQ\tBX, ");
|
emitline("\tMOVQ\tBX, ");
|
||||||
emitoff((off + 8): i64);
|
emitoff((off + 8): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
};
|
};
|
||||||
// slice init: ptr/len/cap in AX/BX/CX.
|
// slice init: ptr/len/cap in AX/BX/CX. Same kind+size gate as
|
||||||
// #43: same routing — bare `sz == 24` would collide with a
|
// the str arm — without the kind check this fires on a str let
|
||||||
// 24B str slot under #1; the kind disambiguation lives at
|
// once sz==24 (#60).
|
||||||
// the caller (cglet's tn.kind == N_TSLICE shape check).
|
if (isslicetype(c, tn) && sz == tyslicesize(): i32) {
|
||||||
if (sz == tyslicesize(): i32) {
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
emitline("\tMOVQ\tBX, ");
|
||||||
emitoff((off + 8): i64);
|
emitoff((off + 8): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
|
|||||||
@@ -15708,7 +15708,10 @@ fn cgcall(c: *cgen, n: *node) void = {
|
|||||||
if (nvar > 0) {
|
if (nvar > 0) {
|
||||||
doff = localadd(c, dname, nvar * esz, nil);
|
doff = localadd(c, dname, nvar * esz, nil);
|
||||||
};
|
};
|
||||||
let soff: i32 = localadd(c, sname, 24,
|
// #60: vararg gather builds a {ptr,len,cap} slice
|
||||||
|
// descriptor — route through tyslicesize so #34's
|
||||||
|
// slice-header bump propagates here.
|
||||||
|
let soff: i32 = localadd(c, sname, tyslicesize(): i32,
|
||||||
slicewrap(c, varp.lhs));
|
slicewrap(c, varp.lhs));
|
||||||
let aa2: *node = n.list;
|
let aa2: *node = n.list;
|
||||||
let kk3: i32 = 0;
|
let kk3: i32 = 0;
|
||||||
@@ -19433,20 +19436,19 @@ fn cglet(c: *cgen, n: *node) void = {
|
|||||||
emitoff(off: i64);
|
emitoff(off: i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
// str init: cgexpr also leaves len in BX; store both.
|
// str init: cgexpr also leaves len in BX; store both.
|
||||||
// #43: route through primtypesize so #1's str-size bump
|
// #60: gate by kind too — under #1's str=24 bump, sizeof(str)
|
||||||
// surfaces this site (today sz==16 picks str; once str=24,
|
// and sizeof(slice) collide, so a bare `sz ==` check fires
|
||||||
// the in-flight str ABI (#34) must propagate cap and the
|
// both branches for one let. Mirrors cstage cgen.c:6439's
|
||||||
// dispatch needs reshaping by kind, not raw size).
|
// `type_isstr(lt) && sz == ty_str->size` shape.
|
||||||
if (sz == primtypesize("str"): i32) {
|
if (isstrtype(c, tn) && sz == primtypesize("str"): i32) {
|
||||||
emitline("\tMOVQ\tBX, ");
|
emitline("\tMOVQ\tBX, ");
|
||||||
emitoff((off + 8): i64);
|
emitoff((off + 8): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
};
|
};
|
||||||
// slice init: ptr/len/cap in AX/BX/CX.
|
// slice init: ptr/len/cap in AX/BX/CX. Same kind+size gate as
|
||||||
// #43: same routing — bare `sz == 24` would collide with a
|
// the str arm — without the kind check this fires on a str let
|
||||||
// 24B str slot under #1; the kind disambiguation lives at
|
// once sz==24 (#60).
|
||||||
// the caller (cglet's tn.kind == N_TSLICE shape check).
|
if (isslicetype(c, tn) && sz == tyslicesize(): i32) {
|
||||||
if (sz == tyslicesize(): i32) {
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
emitline("\tMOVQ\tBX, ");
|
||||||
emitoff((off + 8): i64);
|
emitoff((off + 8): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
@@ -20271,7 +20273,11 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
};};
|
};};
|
||||||
} else { if (isstrtype(c, p.lhs)) {
|
} else { if (isstrtype(c, p.lhs)) {
|
||||||
if (idx + 2 <= 6) {
|
if (idx + 2 <= 6) {
|
||||||
let off: i32 = localadd(c, nm, 16, p.lhs);
|
// #60: route str-param slot width through the
|
||||||
|
// primtypesize SSoT so #1's ty_str bump propagates
|
||||||
|
// here (parent #43 covered the reg-fill site only
|
||||||
|
// inside cgexpr).
|
||||||
|
let off: i32 = localadd(c, nm, primtypesize("str"): i32, p.lhs);
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
emitline(argregname(idx));
|
emitline(argregname(idx));
|
||||||
emitline(", ");
|
emitline(", ");
|
||||||
@@ -20289,7 +20295,8 @@ fn cgfnparams(c: *cgen, params: *node) void = {
|
|||||||
// 440-469. Only idx=5 hits this (nw=2,
|
// 440-469. Only idx=5 hits this (nw=2,
|
||||||
// regs_left=1): ptr lands in R9, len at
|
// regs_left=1): ptr lands in R9, len at
|
||||||
// +16+stkcursor*8(BP).
|
// +16+stkcursor*8(BP).
|
||||||
let off: i32 = localadd(c, nm, 16, p.lhs);
|
// #60: same SSoT routing as the regs-fit arm above.
|
||||||
|
let off: i32 = localadd(c, nm, primtypesize("str"): i32, p.lhs);
|
||||||
let regs_left: i32 = 6 - idx;
|
let regs_left: i32 = 6 - idx;
|
||||||
let w: i32 = 0;
|
let w: i32 = 0;
|
||||||
for (w < regs_left) {
|
for (w < regs_left) {
|
||||||
|
|||||||
Reference in New Issue
Block a user