diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index d7d6e484..f558ae62 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -5283,6 +5283,34 @@ fn cgdot(c: *cgen, n: *node) void = { }; }; }; + // `def NAME: str = "..."` field access — inline the literal. + // Sdef-backed strs aren't laid out in memory, so falling + // through to the SB-load fallback below would mis-emit + // `MOVQ (SB), AX` (looking up the field name as a + // symbol). Mirrors cmd/w6c/cgen.c N_DOT off==0 / Sdef branch. + if (lhs != nil) { + if (lhs.kind == N_IDENT) { + let drhs: *node = deflookuprhs(c, lhs.str); + if (drhs != nil) { + if (drhs.kind == N_STRLIT) { + let bytes: str = drhs.str; + if (streq(fld, "ptr")) { + let lab: str = internstrlit(c, bytes); + emitline("\tLEAQ\t"); + os.write(1, lab.ptr, lab.len: u64); + emitline("(SB), AX\n"); + return; + }; + if (streq(fld, "len")) { + emitline("\tMOVQ\t$"); + emitint(bytes.len: i64); + emitline(", AX\n"); + return; + }; + }; + }; + }; + }; // Module-qualified value reference: `mod.name` where `mod` // is N_IDENT bound as SK_USE and the leaf isn't a local. // Treat as a SB symbol — `MOVQ leaf(SB), AX`. Same fallback @@ -7511,6 +7539,7 @@ fn fnretlookup(c: *cgen, name: str) *node = { type defent = struct { dname: str, + drhs: *node, dnext: *defent, }; @@ -7521,6 +7550,7 @@ fn collectdefs(c: *cgen, file: *node) void = { if (d.kind == N_DEF) { let e: *defent = amalloc(c.a, 32u64): *defent; e.dname = d.str; + e.drhs = d.rhs; e.dnext = c.defs; c.defs = e; }; @@ -7538,6 +7568,19 @@ fn deflookup(c: *cgen, name: str) bool = { return false; }; +// Returns the rhs init node for a top-level `def`, or nil if `name` +// doesn't name a def. Used by cgdot to inline `.ptr`/`.len` on +// `def NAME: str = "..."` — those aren't laid out in memory. +fn deflookuprhs(c: *cgen, name: str) *node = { + let e: *defent = c.defs; + for (e != nil) { + let dn: str = e.dname; + if (streq(dn, name)) { return e.drhs; }; + e = e.dnext; + }; + return nil; +}; + // ---- module-private symbol map -------------------------------------- // // Non-exported top-level decls live in their originating module's diff --git a/selfhost/cmd/wcc/cgen.ww b/selfhost/cmd/wcc/cgen.ww index 1459eadb..03ea7ecf 100644 --- a/selfhost/cmd/wcc/cgen.ww +++ b/selfhost/cmd/wcc/cgen.ww @@ -553,6 +553,7 @@ fn fnretlookup(c: *cgen, name: str) *node = { type defent = struct { dname: str, + drhs: *node, dnext: *defent, }; @@ -563,6 +564,7 @@ fn collectdefs(c: *cgen, file: *node) void = { if (d.kind == N_DEF) { let e: *defent = amalloc(c.a, 32u64): *defent; e.dname = d.str; + e.drhs = d.rhs; e.dnext = c.defs; c.defs = e; }; @@ -580,6 +582,19 @@ fn deflookup(c: *cgen, name: str) bool = { return false; }; +// Returns the rhs init node for a top-level `def`, or nil if `name` +// doesn't name a def. Used by cgdot to inline `.ptr`/`.len` on +// `def NAME: str = "..."` — those aren't laid out in memory. +fn deflookuprhs(c: *cgen, name: str) *node = { + let e: *defent = c.defs; + for (e != nil) { + let dn: str = e.dname; + if (streq(dn, name)) { return e.drhs; }; + e = e.dnext; + }; + return nil; +}; + // ---- module-private symbol map -------------------------------------- // // Non-exported top-level decls live in their originating module's diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index bfaf6286..91731083 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -499,6 +499,34 @@ fn cgdot(c: *cgen, n: *node) void = { }; }; }; + // `def NAME: str = "..."` field access — inline the literal. + // Sdef-backed strs aren't laid out in memory, so falling + // through to the SB-load fallback below would mis-emit + // `MOVQ (SB), AX` (looking up the field name as a + // symbol). Mirrors cmd/w6c/cgen.c N_DOT off==0 / Sdef branch. + if (lhs != nil) { + if (lhs.kind == N_IDENT) { + let drhs: *node = deflookuprhs(c, lhs.str); + if (drhs != nil) { + if (drhs.kind == N_STRLIT) { + let bytes: str = drhs.str; + if (streq(fld, "ptr")) { + let lab: str = internstrlit(c, bytes); + emitline("\tLEAQ\t"); + os.write(1, lab.ptr, lab.len: u64); + emitline("(SB), AX\n"); + return; + }; + if (streq(fld, "len")) { + emitline("\tMOVQ\t$"); + emitint(bytes.len: i64); + emitline(", AX\n"); + return; + }; + }; + }; + }; + }; // Module-qualified value reference: `mod.name` where `mod` // is N_IDENT bound as SK_USE and the leaf isn't a local. // Treat as a SB symbol — `MOVQ leaf(SB), AX`. Same fallback diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 1bf42340..2aa928df 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -5283,6 +5283,34 @@ fn cgdot(c: *cgen, n: *node) void = { }; }; }; + // `def NAME: str = "..."` field access — inline the literal. + // Sdef-backed strs aren't laid out in memory, so falling + // through to the SB-load fallback below would mis-emit + // `MOVQ (SB), AX` (looking up the field name as a + // symbol). Mirrors cmd/w6c/cgen.c N_DOT off==0 / Sdef branch. + if (lhs != nil) { + if (lhs.kind == N_IDENT) { + let drhs: *node = deflookuprhs(c, lhs.str); + if (drhs != nil) { + if (drhs.kind == N_STRLIT) { + let bytes: str = drhs.str; + if (streq(fld, "ptr")) { + let lab: str = internstrlit(c, bytes); + emitline("\tLEAQ\t"); + os.write(1, lab.ptr, lab.len: u64); + emitline("(SB), AX\n"); + return; + }; + if (streq(fld, "len")) { + emitline("\tMOVQ\t$"); + emitint(bytes.len: i64); + emitline(", AX\n"); + return; + }; + }; + }; + }; + }; // Module-qualified value reference: `mod.name` where `mod` // is N_IDENT bound as SK_USE and the leaf isn't a local. // Treat as a SB symbol — `MOVQ leaf(SB), AX`. Same fallback @@ -7511,6 +7539,7 @@ fn fnretlookup(c: *cgen, name: str) *node = { type defent = struct { dname: str, + drhs: *node, dnext: *defent, }; @@ -7521,6 +7550,7 @@ fn collectdefs(c: *cgen, file: *node) void = { if (d.kind == N_DEF) { let e: *defent = amalloc(c.a, 32u64): *defent; e.dname = d.str; + e.drhs = d.rhs; e.dnext = c.defs; c.defs = e; }; @@ -7538,6 +7568,19 @@ fn deflookup(c: *cgen, name: str) bool = { return false; }; +// Returns the rhs init node for a top-level `def`, or nil if `name` +// doesn't name a def. Used by cgdot to inline `.ptr`/`.len` on +// `def NAME: str = "..."` — those aren't laid out in memory. +fn deflookuprhs(c: *cgen, name: str) *node = { + let e: *defent = c.defs; + for (e != nil) { + let dn: str = e.dname; + if (streq(dn, name)) { return e.drhs; }; + e = e.dnext; + }; + return nil; +}; + // ---- module-private symbol map -------------------------------------- // // Non-exported top-level decls live in their originating module's