diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 6b5ae535..5d03920d 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -4364,8 +4364,12 @@ cgexpr(Cg *c, Node *n, Local *locals) dname, nvar * esz, cg_frame); } 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, - slname, 24, cg_frame); + slname, (int)vsu->size, cg_frame); if (nvar > 0) { int v_is_tagged = velem && 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 s1_is_str = u1 && u1->kind == TY_STR; if (l0 && l1 && (s0_is_str ^ s1_is_str)) { - int sz0 = s0_is_str ? 16 : 8; - int sz1 = s1_is_str ? 16 : 8; + /* #60: route str-slot width through ty_str->size so #1 + * 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 off1 = localoff(c, locals, l1->str, sz1, frame); if (s0_is_str) { @@ -7554,9 +7560,12 @@ cgfn(Cg *c, FILE *out, Node *fn) (is_tagged ? tagged_eb : 1))); int regs_left = isf ? (8 - fargi) : (6 - argi); 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_tagged ? tagged_sz : 8))); + (is_tagged ? tagged_sz : 8)); int off = localoff(c, &locals, p->str, sz, &frame); if (slice || is_str || is_struct || is_tagged) { 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 * value. Mirrors the SysV greedy reg fill the caller * 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_tagged ? tagged_sz : 8))); + (is_tagged ? tagged_sz : 8)); int off = localoff(c, &locals, p->str, sz, &frame); extern int cg_stack_arg_cursor; int k = 0; diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index f83e4bea..2bd57849 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -15708,7 +15708,10 @@ fn cgcall(c: *cgen, n: *node) void = { if (nvar > 0) { 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)); let aa2: *node = n.list; let kk3: i32 = 0; @@ -19433,20 +19436,19 @@ fn cglet(c: *cgen, n: *node) void = { emitoff(off: i64); emitline("(BP)\n"); // str init: cgexpr also leaves len in BX; store both. - // #43: route through primtypesize so #1's str-size bump - // surfaces this site (today sz==16 picks str; once str=24, - // the in-flight str ABI (#34) must propagate cap and the - // dispatch needs reshaping by kind, not raw size). - if (sz == primtypesize("str"): i32) { + // #60: gate by kind too — under #1's str=24 bump, sizeof(str) + // and sizeof(slice) collide, so a bare `sz ==` check fires + // both branches for one let. Mirrors cstage cgen.c:6439's + // `type_isstr(lt) && sz == ty_str->size` shape. + if (isstrtype(c, tn) && sz == primtypesize("str"): i32) { emitline("\tMOVQ\tBX, "); emitoff((off + 8): i64); emitline("(BP)\n"); }; - // slice init: ptr/len/cap in AX/BX/CX. - // #43: same routing — bare `sz == 24` would collide with a - // 24B str slot under #1; the kind disambiguation lives at - // the caller (cglet's tn.kind == N_TSLICE shape check). - if (sz == tyslicesize(): i32) { + // slice init: ptr/len/cap in AX/BX/CX. Same kind+size gate as + // the str arm — without the kind check this fires on a str let + // once sz==24 (#60). + if (isslicetype(c, tn) && sz == tyslicesize(): i32) { emitline("\tMOVQ\tBX, "); emitoff((off + 8): i64); emitline("(BP)\n"); @@ -20271,7 +20273,11 @@ fn cgfnparams(c: *cgen, params: *node) void = { };}; } else { if (isstrtype(c, p.lhs)) { 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(argregname(idx)); emitline(", "); @@ -20289,7 +20295,8 @@ fn cgfnparams(c: *cgen, params: *node) void = { // 440-469. Only idx=5 hits this (nw=2, // regs_left=1): ptr lands in R9, len at // +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 w: i32 = 0; for (w < regs_left) { diff --git a/selfhost/cmd/wcc/cgendecl.ww b/selfhost/cmd/wcc/cgendecl.ww index 84a25d83..3150528d 100644 --- a/selfhost/cmd/wcc/cgendecl.ww +++ b/selfhost/cmd/wcc/cgendecl.ww @@ -222,7 +222,11 @@ fn cgfnparams(c: *cgen, params: *node) void = { };}; } else { if (isstrtype(c, p.lhs)) { 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(argregname(idx)); emitline(", "); @@ -240,7 +244,8 @@ fn cgfnparams(c: *cgen, params: *node) void = { // 440-469. Only idx=5 hits this (nw=2, // regs_left=1): ptr lands in R9, len at // +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 w: i32 = 0; for (w < regs_left) { diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index b1ba8aaa..af0a94a6 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -3081,7 +3081,10 @@ fn cgcall(c: *cgen, n: *node) void = { if (nvar > 0) { 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)); let aa2: *node = n.list; let kk3: i32 = 0; diff --git a/selfhost/cmd/wcc/cgenstmt.ww b/selfhost/cmd/wcc/cgenstmt.ww index 3c207542..4fc7b412 100644 --- a/selfhost/cmd/wcc/cgenstmt.ww +++ b/selfhost/cmd/wcc/cgenstmt.ww @@ -1024,20 +1024,19 @@ fn cglet(c: *cgen, n: *node) void = { emitoff(off: i64); emitline("(BP)\n"); // str init: cgexpr also leaves len in BX; store both. - // #43: route through primtypesize so #1's str-size bump - // surfaces this site (today sz==16 picks str; once str=24, - // the in-flight str ABI (#34) must propagate cap and the - // dispatch needs reshaping by kind, not raw size). - if (sz == primtypesize("str"): i32) { + // #60: gate by kind too — under #1's str=24 bump, sizeof(str) + // and sizeof(slice) collide, so a bare `sz ==` check fires + // both branches for one let. Mirrors cstage cgen.c:6439's + // `type_isstr(lt) && sz == ty_str->size` shape. + if (isstrtype(c, tn) && sz == primtypesize("str"): i32) { emitline("\tMOVQ\tBX, "); emitoff((off + 8): i64); emitline("(BP)\n"); }; - // slice init: ptr/len/cap in AX/BX/CX. - // #43: same routing — bare `sz == 24` would collide with a - // 24B str slot under #1; the kind disambiguation lives at - // the caller (cglet's tn.kind == N_TSLICE shape check). - if (sz == tyslicesize(): i32) { + // slice init: ptr/len/cap in AX/BX/CX. Same kind+size gate as + // the str arm — without the kind check this fires on a str let + // once sz==24 (#60). + if (isslicetype(c, tn) && sz == tyslicesize(): i32) { emitline("\tMOVQ\tBX, "); emitoff((off + 8): i64); emitline("(BP)\n"); diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 88f6afcc..3ab6431d 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -15708,7 +15708,10 @@ fn cgcall(c: *cgen, n: *node) void = { if (nvar > 0) { 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)); let aa2: *node = n.list; let kk3: i32 = 0; @@ -19433,20 +19436,19 @@ fn cglet(c: *cgen, n: *node) void = { emitoff(off: i64); emitline("(BP)\n"); // str init: cgexpr also leaves len in BX; store both. - // #43: route through primtypesize so #1's str-size bump - // surfaces this site (today sz==16 picks str; once str=24, - // the in-flight str ABI (#34) must propagate cap and the - // dispatch needs reshaping by kind, not raw size). - if (sz == primtypesize("str"): i32) { + // #60: gate by kind too — under #1's str=24 bump, sizeof(str) + // and sizeof(slice) collide, so a bare `sz ==` check fires + // both branches for one let. Mirrors cstage cgen.c:6439's + // `type_isstr(lt) && sz == ty_str->size` shape. + if (isstrtype(c, tn) && sz == primtypesize("str"): i32) { emitline("\tMOVQ\tBX, "); emitoff((off + 8): i64); emitline("(BP)\n"); }; - // slice init: ptr/len/cap in AX/BX/CX. - // #43: same routing — bare `sz == 24` would collide with a - // 24B str slot under #1; the kind disambiguation lives at - // the caller (cglet's tn.kind == N_TSLICE shape check). - if (sz == tyslicesize(): i32) { + // slice init: ptr/len/cap in AX/BX/CX. Same kind+size gate as + // the str arm — without the kind check this fires on a str let + // once sz==24 (#60). + if (isslicetype(c, tn) && sz == tyslicesize(): i32) { emitline("\tMOVQ\tBX, "); emitoff((off + 8): i64); emitline("(BP)\n"); @@ -20271,7 +20273,11 @@ fn cgfnparams(c: *cgen, params: *node) void = { };}; } else { if (isstrtype(c, p.lhs)) { 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(argregname(idx)); emitline(", "); @@ -20289,7 +20295,8 @@ fn cgfnparams(c: *cgen, params: *node) void = { // 440-469. Only idx=5 hits this (nw=2, // regs_left=1): ptr lands in R9, len at // +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 w: i32 = 0; for (w < regs_left) {