selfhost+test: strlit-inline str-def value-load shape (#12)
Class A silent miscompile. wwstage cgenexpr.ww cgident's bare-ident deflookup→true branch and cgdot's module-qualified leaf branch emitted `MOVQ <mod>.<name>(SB), AX` for a `def MSG: str = "..."` value reference — a load from a SB symbol that emit_data never writes. Str defs are not laid out at SB; they live as interned strlits the .ptr/.len fold (post-#4c) and value-load consume. Cstage already strlit-inlines via Sdef walks #1 (case N_IDENT non-local) and #2 (case N_DOT untyped-lhs); wwstage now matches the (LEAQ _S_<n>(SB), MOVQ $<len>, BX) emit shape per rule 10. Surfaced by reviewer-def during #4c R3 while attempting option (B) for the cstage Sdef walks #1/#2 prefer-pass — both walks' cs-vs-ws byte-id sentinel rows could not pass while wwstage emitted the bogus DATAW shape. Filed as #12 and deferred until the wwstage emit shape was fixed. Unblocks #11 + #13 (cstage prefer-pass graduations). Latent: no in-tree corpus referenced a str def as a value (only as .ptr/.len via cgdot field-fold) prior to lib/strings c3 — same corpus-coverage-blind shape as the #4a-#4e graduations. 746_strdef_inline pins both sites with 2 rows: bare ident + mod-qualified. Each row asserts `LEAQ _S_` + `MOVQ $<strlit_len>,` inside the caller TEXT before RET, anti-checks the pre-fix `<mod>.<name>(SB)` symbol-load, and cs-vs-ws byte-id per row. 120/120 ok. ww2 == ww3 == ww4 byte-id holds.
This commit is contained in:
@@ -552,7 +552,26 @@ fn cgident(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
// Top-level `def` constant — load from its DATA symbol.
|
||||
// Str defs (rhs N_STRLIT) aren't laid out at a SB symbol; the
|
||||
// MOVQ symname(SB) fallback below would emit a bogus reference
|
||||
// (e.g. `alpha.MSG(SB)`, never DATAW-defined). Strlit-inline
|
||||
// the (LEAQ ptr, MOVQ $len) pair instead, mirroring cstage
|
||||
// Sdef walk #1 N_IDENT bare-load (cmd/w6c/cgen.c). Filed #12.
|
||||
if (deflookup(c, nm)) {
|
||||
let drhs: *node = deflookuprhs(c, nm);
|
||||
if (drhs != nil) {
|
||||
if (drhs.kind == nkind.N_STRLIT) {
|
||||
let bytes: str = drhs.str;
|
||||
let lab: str = internstrlit(c, bytes);
|
||||
emitline("\tLEAQ\t");
|
||||
os.write(1, lab.ptr, lab.len: u64);
|
||||
emitline("(SB), AX\n");
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(bytes.len: i64);
|
||||
emitline(", BX\n");
|
||||
return;
|
||||
};
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB), AX\n");
|
||||
@@ -1721,6 +1740,25 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
emitline("(SB), AX\n");
|
||||
return;
|
||||
};
|
||||
// `mod.MSG` where MSG is `def MSG: str = "..."` —
|
||||
// strlit-inline matches cstage Sdef walk #2 in
|
||||
// cmd/w6c/cgen.c N_DOT mod-qualified. Without this
|
||||
// the MOVQ leaf(SB) fallback emits a bogus ref
|
||||
// (`alpha.MSG(SB)`, never DATAW-defined). Filed #12.
|
||||
let drhs: *node = deflookuprhs(c, fld);
|
||||
if (drhs != nil) {
|
||||
if (drhs.kind == nkind.N_STRLIT) {
|
||||
let bytes: str = drhs.str;
|
||||
let lab: str = internstrlit(c, bytes);
|
||||
emitline("\tLEAQ\t");
|
||||
os.write(1, lab.ptr, lab.len: u64);
|
||||
emitline("(SB), AX\n");
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(bytes.len: i64);
|
||||
emitline(", BX\n");
|
||||
return;
|
||||
};
|
||||
};
|
||||
let mqop: str = localloadop(c, letvartnode(c, fld));
|
||||
if (streq(mqop, "MOVQ")) {
|
||||
emitline("\tMOVQ\t");
|
||||
|
||||
Reference in New Issue
Block a user