wcc: converge DOT-recv, structlit-fill, and bare-let zero-init onto structabisize

Three wwstage cgen sites still used the unrounded structnaturalsize where cstage
rounds via lu->size (check.c:760), pre-existing gate-blind cs!=ww latents
flagged in #169's reviewer notes: cgenexpr DOT register-RECV for obj.f = mk()
(~5175/5393/5628/6164); cgstructlitfill's TK_ELLIPSIS zero-fill branch
(cgenutil); and cglet bare 'let z: T;' zero-init of a maxalign<8 struct
(cgenstmt). Each produced MOVQ-vs-MOVL or wider-write divergence vs cstage on
the trailing word of a sub-eightbyte tail.

Converge all three onto the maxalign-rounded structabisize the #169 work
established at the register-ABI sites (cite cstage cgen.c:7720 RECV twin +
cgen.c:2085 cg_structlit_fill). cgstructlitfill's signature drops the external
totsize parameter in favor of one internal source; the field-walk path is
untouched, only the ELLIPSIS zero-fill uses the ABI size. cglet's slot
allocation stays on the frame size; only the zero-fill extent uses ABI.

Gate-blind (the bootstrap exercises none of these shapes); covered by 5 new
rows in probe 698 with cs==ww .s byte-cmp and a pre-fix-rebuild proving the
exact MOVQ-vs-MOVL discrimination. 990-997 byte-id hold.
This commit is contained in:
2026-05-28 13:02:47 +09:00
parent d92c199d25
commit 39f9267bc9
6 changed files with 210 additions and 117 deletions

View File

@@ -5148,11 +5148,13 @@ fn cgassign(c: *cgen, n: *node) void = {
// N_IDENT: word-copy from rhs slot.
// N_CALL: cgexpr → AX/DX/CX per #4's cgreturn
// ABI; load *struct ptr into BX after the
// call, sized stores per natural struct size.
// call, sized stores per the ABI size.
// N_STRUCTLIT: field-walk; reload BX before
// each store so cgexpr can clobber AX/BX.
// si.totsize is slot-padded; use
// structnaturalsize for the type-size query.
// register RECV reads AX/DX/CX at 8-byte
// granularity — size via structabisize (cstage
// SSoT lu->size, check.c:760; cgen.c:7720
// sz=lu->size at the receive twin).
if (n.op == tkind.TK_ASSIGN
&& n.rhs != nil
&& n.rhs.kind == nkind.N_CALL
@@ -5161,7 +5163,7 @@ fn cgassign(c: *cgen, n: *node) void = {
&& primsize(fi.tnode.str) == 0) {
let ssi: *structinfo = structlookup(c, fi.tnode.str);
if (ssi != nil) {
let ssz: i32 = structnaturalsize(ssi);
let ssz: i32 = structabisize(ssi);
if (ssz <= 24) {
let tlm: i32 = ssz - (ssz / 8) * 8;
if (tlm == 0 || tlm == 1
@@ -5216,9 +5218,8 @@ fn cgassign(c: *cgen, n: *node) void = {
&& primsize(fi.tnode.str) == 0) {
let ssi: *structinfo = structlookup(c, fi.tnode.str);
if (ssi != nil) {
let ssz: i32 = structnaturalsize(ssi);
cgstructlitfill(c, ssi, n.rhs, 1, lc.off, "",
fi.foff, ssz);
fi.foff);
return;
};
};
@@ -5379,7 +5380,7 @@ fn cgassign(c: *cgen, n: *node) void = {
&& primsize(fi.tnode.str) == 0) {
let ssi: *structinfo = structlookup(c, fi.tnode.str);
if (ssi != nil) {
let ssz: i32 = structnaturalsize(ssi);
let ssz: i32 = structabisize(ssi);
if (ssz <= 24) {
let tlm: i32 = ssz - (ssz / 8) * 8;
if (tlm == 0 || tlm == 1
@@ -5430,9 +5431,8 @@ fn cgassign(c: *cgen, n: *node) void = {
&& primsize(fi.tnode.str) == 0) {
let ssi: *structinfo = structlookup(c, fi.tnode.str);
if (ssi != nil) {
let ssz: i32 = structnaturalsize(ssi);
cgstructlitfill(c, ssi, n.rhs, 0, 0, "",
lc.off + fi.foff, ssz);
lc.off + fi.foff);
return;
};
};
@@ -5614,7 +5614,7 @@ fn cgassign(c: *cgen, n: *node) void = {
&& primsize(fi.tnode.str) == 0) {
let ssi: *structinfo = structlookup(c, fi.tnode.str);
if (ssi != nil) {
let ssz: i32 = structnaturalsize(ssi);
let ssz: i32 = structabisize(ssi);
if (ssz <= 24) {
let tlm: i32 = ssz - (ssz / 8) * 8;
if (tlm == 0 || tlm == 1
@@ -5669,9 +5669,8 @@ fn cgassign(c: *cgen, n: *node) void = {
&& primsize(fi.tnode.str) == 0) {
let ssi: *structinfo = structlookup(c, fi.tnode.str);
if (ssi != nil) {
let ssz: i32 = structnaturalsize(ssi);
cgstructlitfill(c, ssi, n.rhs, 2, 0, bn,
fi.foff, ssz);
fi.foff);
return;
};
};
@@ -6148,9 +6147,10 @@ fn cgassign(c: *cgen, n: *node) void = {
&& leafstruct) {
let lsi: *structinfo = structlookup(c, leafname);
if (lsi != nil) {
// si.totsize is slot-padded (rounded to 8);
// receive ABI needs the TYPE's natural size.
let lsz: i32 = structnaturalsize(lsi);
// register RECV reads AX/DX/CX at 8-byte
// granularity — size via structabisize
// (cstage SSoT lu->size, check.c:760).
let lsz: i32 = structabisize(lsi);
if (lsz <= 24) {
let tlm: i32 = lsz - (lsz / 8) * 8;
if (tlm == 0 || tlm == 1
@@ -6231,9 +6231,6 @@ fn cgassign(c: *cgen, n: *node) void = {
&& leafstruct) {
let lsi: *structinfo = structlookup(c, leafname);
if (lsi != nil) {
// si.totsize is slot-padded (rounded to 8);
// receive ABI needs the TYPE's natural size.
let lsz: i32 = structnaturalsize(lsi);
let dmode: i32 = 0;
let ddisp: i32 = rootoff + totaloff;
if (ptrroot) {
@@ -6246,7 +6243,7 @@ fn cgassign(c: *cgen, n: *node) void = {
};
cgstructlitfill(c, lsi, n.rhs,
dmode, rootoff, rootname,
ddisp, lsz);
ddisp);
return;
};
};