wcc/ww: widen of a module-global struct ident copies the full payload

Widening a global struct into a tagged slot copied word0 only; copy
the full payload from g(SB). Both-wrong pair: cstage zero-fills the
payload (filed task #43); rows pin ww-runtime-correct with the
documented cstage residual. Review item #50.
This commit is contained in:
2026-06-12 09:16:52 +09:00
parent 4b8c8fd9ed
commit 32848194d7
5 changed files with 339 additions and 0 deletions

View File

@@ -21820,6 +21820,60 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
emitline("(BP)\n");
return;
}; };
// #50 (#263 ww-runtime-correct): a module-GLOBAL struct ident source.
// rhsstructpayload below is local/literal-only, so a global struct value
// fell to the scalar word0 arm — payload truncated. Land g(SB) in SI and
// byte-copy the struct words into slot+8; cstage zero-fills the payload
// (cstage half #43). Local/literal sources keep the existing arms (byte-id).
if (src.kind == nkind.N_IDENT) {
if (localfindnode(c, src.str) == nil) {
let gtn: *node = letvartnode(c, src.str);
if (gtn != nil) { if (gtn.kind == nkind.N_TNAME) {
let gsi: *structinfo = structlookupchain(c, gtn);
if (gsi != nil) {
emitline("\tXORQ\tAX, AX\n");
let gz: i32 = 0;
for (gz < slot_sz) {
emitline("\tMOVQ\tAX, ");
emitoff((slot_off + gz): i64);
emitline("(BP)\n");
gz += 8;
};
let gtag: i32 = taggedvariantindext(c, dt, src);
if (gtag < 0) { gtag = 0; };
if (aggargsrcaddr(c, src, "SI")) {
let gtot: i32 = gsi.totsize;
let gk: i32 = 0;
for (gk + 8 <= gtot) {
emitline("\tMOVQ\t");
emitoff(gk: i64);
emitline("(SI), AX\n");
emitline("\tMOVQ\tAX, ");
emitoff((slot_off + 8 + gk): i64);
emitline("(BP)\n");
gk += 8;
};
if (gk < gtot) {
let gtail: i32 = gtot - gk;
let glop: str = "MOVQ";
if (gtail == 4) { glop = "MOVL"; }
else { if (gtail == 1) { glop = "MOVB"; }; };
emitline("\t"); emitline(glop); emitline("\t");
emitoff(gk: i64); emitline("(SI), AX\n");
emitline("\t"); emitline(glop); emitline("\tAX, ");
emitoff((slot_off + 8 + gk): i64); emitline("(BP)\n");
};
emitline("\tMOVQ\t$");
emitint(gtag: i64);
emitline(", ");
emitoff(slot_off: i64);
emitline("(BP)\n");
return;
};
};
}; };
};
};
// Struct payload (literal or ident).
let sname: str = rhsstructpayload(c, src);
if (sname.len > 0) {

View File

@@ -4400,6 +4400,60 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
emitline("(BP)\n");
return;
}; };
// #50 (#263 ww-runtime-correct): a module-GLOBAL struct ident source.
// rhsstructpayload below is local/literal-only, so a global struct value
// fell to the scalar word0 arm — payload truncated. Land g(SB) in SI and
// byte-copy the struct words into slot+8; cstage zero-fills the payload
// (cstage half #43). Local/literal sources keep the existing arms (byte-id).
if (src.kind == nkind.N_IDENT) {
if (localfindnode(c, src.str) == nil) {
let gtn: *node = letvartnode(c, src.str);
if (gtn != nil) { if (gtn.kind == nkind.N_TNAME) {
let gsi: *structinfo = structlookupchain(c, gtn);
if (gsi != nil) {
emitline("\tXORQ\tAX, AX\n");
let gz: i32 = 0;
for (gz < slot_sz) {
emitline("\tMOVQ\tAX, ");
emitoff((slot_off + gz): i64);
emitline("(BP)\n");
gz += 8;
};
let gtag: i32 = taggedvariantindext(c, dt, src);
if (gtag < 0) { gtag = 0; };
if (aggargsrcaddr(c, src, "SI")) {
let gtot: i32 = gsi.totsize;
let gk: i32 = 0;
for (gk + 8 <= gtot) {
emitline("\tMOVQ\t");
emitoff(gk: i64);
emitline("(SI), AX\n");
emitline("\tMOVQ\tAX, ");
emitoff((slot_off + 8 + gk): i64);
emitline("(BP)\n");
gk += 8;
};
if (gk < gtot) {
let gtail: i32 = gtot - gk;
let glop: str = "MOVQ";
if (gtail == 4) { glop = "MOVL"; }
else { if (gtail == 1) { glop = "MOVB"; }; };
emitline("\t"); emitline(glop); emitline("\t");
emitoff(gk: i64); emitline("(SI), AX\n");
emitline("\t"); emitline(glop); emitline("\tAX, ");
emitoff((slot_off + 8 + gk): i64); emitline("(BP)\n");
};
emitline("\tMOVQ\t$");
emitint(gtag: i64);
emitline(", ");
emitoff(slot_off: i64);
emitline("(BP)\n");
return;
};
};
}; };
};
};
// Struct payload (literal or ident).
let sname: str = rhsstructpayload(c, src);
if (sname.len > 0) {

View File

@@ -21820,6 +21820,60 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
emitline("(BP)\n");
return;
}; };
// #50 (#263 ww-runtime-correct): a module-GLOBAL struct ident source.
// rhsstructpayload below is local/literal-only, so a global struct value
// fell to the scalar word0 arm — payload truncated. Land g(SB) in SI and
// byte-copy the struct words into slot+8; cstage zero-fills the payload
// (cstage half #43). Local/literal sources keep the existing arms (byte-id).
if (src.kind == nkind.N_IDENT) {
if (localfindnode(c, src.str) == nil) {
let gtn: *node = letvartnode(c, src.str);
if (gtn != nil) { if (gtn.kind == nkind.N_TNAME) {
let gsi: *structinfo = structlookupchain(c, gtn);
if (gsi != nil) {
emitline("\tXORQ\tAX, AX\n");
let gz: i32 = 0;
for (gz < slot_sz) {
emitline("\tMOVQ\tAX, ");
emitoff((slot_off + gz): i64);
emitline("(BP)\n");
gz += 8;
};
let gtag: i32 = taggedvariantindext(c, dt, src);
if (gtag < 0) { gtag = 0; };
if (aggargsrcaddr(c, src, "SI")) {
let gtot: i32 = gsi.totsize;
let gk: i32 = 0;
for (gk + 8 <= gtot) {
emitline("\tMOVQ\t");
emitoff(gk: i64);
emitline("(SI), AX\n");
emitline("\tMOVQ\tAX, ");
emitoff((slot_off + 8 + gk): i64);
emitline("(BP)\n");
gk += 8;
};
if (gk < gtot) {
let gtail: i32 = gtot - gk;
let glop: str = "MOVQ";
if (gtail == 4) { glop = "MOVL"; }
else { if (gtail == 1) { glop = "MOVB"; }; };
emitline("\t"); emitline(glop); emitline("\t");
emitoff(gk: i64); emitline("(SI), AX\n");
emitline("\t"); emitline(glop); emitline("\tAX, ");
emitoff((slot_off + 8 + gk): i64); emitline("(BP)\n");
};
emitline("\tMOVQ\t$");
emitint(gtag: i64);
emitline(", ");
emitoff(slot_off: i64);
emitline("(BP)\n");
return;
};
};
}; };
};
};
// Struct payload (literal or ident).
let sname: str = rhsstructpayload(c, src);
if (sname.len > 0) {