selfhost/cmd/wcc: route remaining wwstage size dispatch through SSoT
Followup to 8e93b31 (#43). Audit caught dispatch-gate sites the
sweep missed:
- cgen.ww letpreintern's `sz == 16` str-let detector — would
desync from emitletdataw's matching `sz == primtypesize("str"):
i32` strlit-init branch under #1.
- cgenstmt.ww cglet str-init MOVQ-BX gate and slice-init MOVQ-BX/CX
gate (and the belt-and-suspenders N_TSLICE shape check at l.607).
- cgenexpr.ww cgindex str-element loads (3 sites: globalarr,
baselocal, generic fallback) and the matching cgassign N_INDEX
str-element write pair (BX spill + post-index store).
All gates now read `primtypesize("str"): i32` / `tyslicesize(): i32`,
so #1's ty_str.size bump propagates through the same two-place edit
the original commit advertised. Combined files (w6c/wwdump) updated
in lockstep.
131/131 + 994 + 995 byte-identity green; smoke.combined.ww (lib-only
consumer) emits the same asm pre vs post, confirming the change is
SSoT routing only (no behaviour shift).
This commit is contained in:
@@ -13426,7 +13426,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
if (esz == 16) {
|
||||
// #43: str element-stride routes through primtypesize so the
|
||||
// 16-vs-24 dispatch tracks ty_str.size for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(BX), CX\n");
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
emitline("\tMOVQ\tCX, BX\n");
|
||||
@@ -13465,9 +13467,10 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
// str element (16B): load (ptr, len) into (AX, BX) so
|
||||
// str element (16B today): load (ptr, len) into (AX, BX) so
|
||||
// the value flows through the str-rhs convention.
|
||||
if (esz == 16) {
|
||||
// #43: route via primtypesize so the stride tracks #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(BX), CX\n");
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
emitline("\tMOVQ\tCX, BX\n");
|
||||
@@ -13497,7 +13500,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
if (esz == 16) {
|
||||
// #43: str element-stride routes through primtypesize so the
|
||||
// 16-vs-24 dispatch tracks ty_str.size for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(AX), BX\n");
|
||||
emitline("\tMOVQ\t(AX), AX\n");
|
||||
return;
|
||||
@@ -16391,7 +16396,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
cgexpr(c, n.rhs); // value → AX
|
||||
if (esz == 16) { emitline("\tPUSHQ\tBX\n"); };
|
||||
// #43: spill BX (str.len) before computing
|
||||
// the index so the post-index store can pop
|
||||
// it; the stride gate tracks ty_str.size.
|
||||
if (esz == primtypesize("str"): i32) { emitline("\tPUSHQ\tBX\n"); };
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx); // idx → AX
|
||||
if (esz > 1) {
|
||||
@@ -16429,7 +16437,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tAX\n"); // scaled idx
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
emitline("\tPOPQ\tAX\n"); // value
|
||||
if (esz == 16) {
|
||||
// #43: str-element write — pop the saved
|
||||
// .len and store both halves. Stride gate
|
||||
// routes through primtypesize for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\tAX, (BX)\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tCX, 8(BX)\n");
|
||||
@@ -19001,8 +19012,13 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
}; };
|
||||
let shapeok: bool = false;
|
||||
// #43: route the slice-shape size guard through SSoT.
|
||||
// The N_TSLICE kind gate already discriminates here, so
|
||||
// this is belt-and-suspenders, but the literal would
|
||||
// silently miss after #1 if check.ww's astsize ever
|
||||
// drifted from this dispatch.
|
||||
if (scall != nil && tn != nil
|
||||
&& tn.kind == nkind.N_TSLICE && sz == 24) {
|
||||
&& tn.kind == nkind.N_TSLICE && sz == tyslicesize(): i32) {
|
||||
let callee: *node = scall.lhs;
|
||||
let a0: *node = scall.list;
|
||||
let a1: *node = nil;
|
||||
@@ -19417,13 +19433,20 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
// str init: cgexpr also leaves len in BX; store both.
|
||||
if (sz == 16) {
|
||||
// #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) {
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
// slice init: ptr/len/cap in AX/BX/CX.
|
||||
if (sz == 24) {
|
||||
// #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) {
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -21678,7 +21701,10 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
for (d != nil) {
|
||||
if (d.kind == nkind.N_LET) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
if (sz == 16) {
|
||||
// #43: route the str-let gate through primtypesize so
|
||||
// #1 doesn't desync this with emitletdataw's matching
|
||||
// `sz == primtypesize("str"): i32` strlit-init branch.
|
||||
if (sz == primtypesize("str"): i32) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
|
||||
@@ -1199,7 +1199,10 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
for (d != nil) {
|
||||
if (d.kind == nkind.N_LET) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
if (sz == 16) {
|
||||
// #43: route the str-let gate through primtypesize so
|
||||
// #1 doesn't desync this with emitletdataw's matching
|
||||
// `sz == primtypesize("str"): i32` strlit-init branch.
|
||||
if (sz == primtypesize("str"): i32) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
|
||||
@@ -799,7 +799,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
if (esz == 16) {
|
||||
// #43: str element-stride routes through primtypesize so the
|
||||
// 16-vs-24 dispatch tracks ty_str.size for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(BX), CX\n");
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
emitline("\tMOVQ\tCX, BX\n");
|
||||
@@ -838,9 +840,10 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
// str element (16B): load (ptr, len) into (AX, BX) so
|
||||
// str element (16B today): load (ptr, len) into (AX, BX) so
|
||||
// the value flows through the str-rhs convention.
|
||||
if (esz == 16) {
|
||||
// #43: route via primtypesize so the stride tracks #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(BX), CX\n");
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
emitline("\tMOVQ\tCX, BX\n");
|
||||
@@ -870,7 +873,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
if (esz == 16) {
|
||||
// #43: str element-stride routes through primtypesize so the
|
||||
// 16-vs-24 dispatch tracks ty_str.size for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(AX), BX\n");
|
||||
emitline("\tMOVQ\t(AX), AX\n");
|
||||
return;
|
||||
@@ -3764,7 +3769,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
cgexpr(c, n.rhs); // value → AX
|
||||
if (esz == 16) { emitline("\tPUSHQ\tBX\n"); };
|
||||
// #43: spill BX (str.len) before computing
|
||||
// the index so the post-index store can pop
|
||||
// it; the stride gate tracks ty_str.size.
|
||||
if (esz == primtypesize("str"): i32) { emitline("\tPUSHQ\tBX\n"); };
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx); // idx → AX
|
||||
if (esz > 1) {
|
||||
@@ -3802,7 +3810,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tAX\n"); // scaled idx
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
emitline("\tPOPQ\tAX\n"); // value
|
||||
if (esz == 16) {
|
||||
// #43: str-element write — pop the saved
|
||||
// .len and store both halves. Stride gate
|
||||
// routes through primtypesize for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\tAX, (BX)\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tCX, 8(BX)\n");
|
||||
|
||||
@@ -603,8 +603,13 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
}; };
|
||||
let shapeok: bool = false;
|
||||
// #43: route the slice-shape size guard through SSoT.
|
||||
// The N_TSLICE kind gate already discriminates here, so
|
||||
// this is belt-and-suspenders, but the literal would
|
||||
// silently miss after #1 if check.ww's astsize ever
|
||||
// drifted from this dispatch.
|
||||
if (scall != nil && tn != nil
|
||||
&& tn.kind == nkind.N_TSLICE && sz == 24) {
|
||||
&& tn.kind == nkind.N_TSLICE && sz == tyslicesize(): i32) {
|
||||
let callee: *node = scall.lhs;
|
||||
let a0: *node = scall.list;
|
||||
let a1: *node = nil;
|
||||
@@ -1019,13 +1024,20 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
// str init: cgexpr also leaves len in BX; store both.
|
||||
if (sz == 16) {
|
||||
// #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) {
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
// slice init: ptr/len/cap in AX/BX/CX.
|
||||
if (sz == 24) {
|
||||
// #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) {
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
|
||||
@@ -13426,7 +13426,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
if (esz == 16) {
|
||||
// #43: str element-stride routes through primtypesize so the
|
||||
// 16-vs-24 dispatch tracks ty_str.size for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(BX), CX\n");
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
emitline("\tMOVQ\tCX, BX\n");
|
||||
@@ -13465,9 +13467,10 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
// str element (16B): load (ptr, len) into (AX, BX) so
|
||||
// str element (16B today): load (ptr, len) into (AX, BX) so
|
||||
// the value flows through the str-rhs convention.
|
||||
if (esz == 16) {
|
||||
// #43: route via primtypesize so the stride tracks #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(BX), CX\n");
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
emitline("\tMOVQ\tCX, BX\n");
|
||||
@@ -13497,7 +13500,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
return;
|
||||
};
|
||||
if (esz == 16) {
|
||||
// #43: str element-stride routes through primtypesize so the
|
||||
// 16-vs-24 dispatch tracks ty_str.size for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\t8(AX), BX\n");
|
||||
emitline("\tMOVQ\t(AX), AX\n");
|
||||
return;
|
||||
@@ -16391,7 +16396,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
cgexpr(c, n.rhs); // value → AX
|
||||
if (esz == 16) { emitline("\tPUSHQ\tBX\n"); };
|
||||
// #43: spill BX (str.len) before computing
|
||||
// the index so the post-index store can pop
|
||||
// it; the stride gate tracks ty_str.size.
|
||||
if (esz == primtypesize("str"): i32) { emitline("\tPUSHQ\tBX\n"); };
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx); // idx → AX
|
||||
if (esz > 1) {
|
||||
@@ -16429,7 +16437,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tAX\n"); // scaled idx
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
emitline("\tPOPQ\tAX\n"); // value
|
||||
if (esz == 16) {
|
||||
// #43: str-element write — pop the saved
|
||||
// .len and store both halves. Stride gate
|
||||
// routes through primtypesize for #1.
|
||||
if (esz == primtypesize("str"): i32) {
|
||||
emitline("\tMOVQ\tAX, (BX)\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tCX, 8(BX)\n");
|
||||
@@ -19001,8 +19012,13 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
}; };
|
||||
let shapeok: bool = false;
|
||||
// #43: route the slice-shape size guard through SSoT.
|
||||
// The N_TSLICE kind gate already discriminates here, so
|
||||
// this is belt-and-suspenders, but the literal would
|
||||
// silently miss after #1 if check.ww's astsize ever
|
||||
// drifted from this dispatch.
|
||||
if (scall != nil && tn != nil
|
||||
&& tn.kind == nkind.N_TSLICE && sz == 24) {
|
||||
&& tn.kind == nkind.N_TSLICE && sz == tyslicesize(): i32) {
|
||||
let callee: *node = scall.lhs;
|
||||
let a0: *node = scall.list;
|
||||
let a1: *node = nil;
|
||||
@@ -19417,13 +19433,20 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
// str init: cgexpr also leaves len in BX; store both.
|
||||
if (sz == 16) {
|
||||
// #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) {
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
// slice init: ptr/len/cap in AX/BX/CX.
|
||||
if (sz == 24) {
|
||||
// #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) {
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -21678,7 +21701,10 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
for (d != nil) {
|
||||
if (d.kind == nkind.N_LET) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
if (sz == 16) {
|
||||
// #43: route the str-let gate through primtypesize so
|
||||
// #1 doesn't desync this with emitletdataw's matching
|
||||
// `sz == primtypesize("str"): i32` strlit-init branch.
|
||||
if (sz == primtypesize("str"): i32) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
|
||||
Reference in New Issue
Block a user