w6c+cgen: emit module-level [N]str static-init data + relocations (fix #18)
A module-level `let xs: [N]str = ["a","b",...];` static init emitted no
.data: a str element carries a ptr->rodata relocation, not just bytes, so
it fell through the byte-only array-emit path and left the table symbol
undefined (w6l: undefined reference). Shared gap on both stages, not
rule-10.
emit_strarray_data / emitstrarraydata apply the scalar-str-global pattern
per element at offset idx*esz: a DATAW row of {0-ptr placeholder, LE len,
cap} plus a per-element DATAR sym+idx*esz,_S_n reloc. let_pre_intern /
letpreintern pre-intern each element strlit so the _S_ rodata rows precede
the DATAR references. Stride routes through etype->size (rule 13). Scoped
to the DATAW (`let`) directive: A_DATAR requires a DATAW holder, so
`def [N]str` and str-in-aggregate stay a filed follow-up.
919_strarray_static_run pins runtime (len-sum, element .ptr deref, var
index, empty slot, repeat suffix) + cs==ww byte-id. w6c + wwdump
combined.ww regenerated.
This commit is contained in:
@@ -1220,20 +1220,82 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == nkind.N_LET) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
// #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; };
|
||||
r = r.lhs;
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
r = r.lhs;
|
||||
};
|
||||
// #18: `let xs: [N]str = […];` — pre-intern each
|
||||
// element's strlit in element order (then repeat-fill)
|
||||
// so emitstrarraydata's DATAR rows find an _S_ rodata
|
||||
// row. Must match that helper's interning order exactly
|
||||
// to keep labels stable.
|
||||
let handled: bool = false;
|
||||
if (d.lhs != nil && r != nil) {
|
||||
if (d.lhs.kind == nkind.N_TARRAY
|
||||
&& r.kind == nkind.N_ARRLIT) {
|
||||
let au: *tinfo = d.lhs.type_: *tinfo;
|
||||
for (au != nil && au.kind == tykind.TY_NAMED) {
|
||||
au = au.under;
|
||||
};
|
||||
let eu: *tinfo = nil;
|
||||
if (au != nil) {
|
||||
if (au.kind == tykind.TY_ARRAY) {
|
||||
eu = au.sub;
|
||||
for (eu != nil && eu.kind == tykind.TY_NAMED) {
|
||||
eu = eu.under;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (eu != nil && eu.kind == tykind.TY_STR) {
|
||||
handled = true;
|
||||
let alen: i32 = au.alen: i32;
|
||||
let cnt: i32 = 0;
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let e: *node = r.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev == nil) { break; };
|
||||
if (ev.kind != nkind.N_STRLIT) { break; };
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
if (repeat && last_ev != nil) {
|
||||
if (last_ev.str.len > 0) {
|
||||
for (cnt < alen) {
|
||||
internstrlit(c, last_ev.str);
|
||||
cnt += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (r != nil) {
|
||||
if (r.kind == nkind.N_STRLIT) {
|
||||
if (r.str.len > 0) {
|
||||
internstrlit(c, r.str);
|
||||
};
|
||||
if (!handled) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
// #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) {
|
||||
if (r != nil) {
|
||||
if (r.kind == nkind.N_STRLIT) {
|
||||
if (r.str.len > 0) {
|
||||
internstrlit(c, r.str);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1775,6 +1837,126 @@ fn emitarraylitbytes(c: *cgen, arrt: *tinfo, rhs: *node,
|
||||
return true;
|
||||
};
|
||||
|
||||
// emitstrarraydata — module-level `let xs: [N]str = […];` static init
|
||||
// (#18). Mirror of cstage emit_strarray_data. A str element carries a
|
||||
// ptr→rodata relocation, not just bytes, so it can't ride
|
||||
// emitarraylitbytes (bytes-only); instead apply the scalar-str-global
|
||||
// pattern (DATAW header with a zero ptr placeholder + inline LE len,
|
||||
// then a per-element DATAR) at offset idx*esz. Each strlit was pre-
|
||||
// interned by letpreintern so its _S_ rodata row exists before this
|
||||
// row's DATAR references it. Scoped to DATAW (writable `let`): A_DATAR
|
||||
// requires a DATAW holder, so a read-only `def [N]str` can't carry the
|
||||
// relocs (#18 follow-up). Returns false when the element type isn't str.
|
||||
fn emitstrarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
arrt: *tinfo, rhs: *node) bool = {
|
||||
let au: *tinfo = arrt;
|
||||
for (au != nil && au.kind == tykind.TY_NAMED) { au = au.under; };
|
||||
if (au == nil) { return false; };
|
||||
if (au.kind != tykind.TY_ARRAY) { return false; };
|
||||
let eu: *tinfo = au.sub;
|
||||
for (eu != nil && eu.kind == tykind.TY_NAMED) { eu = eu.under; };
|
||||
if (eu == nil) { return false; };
|
||||
if (eu.kind != tykind.TY_STR) { return false; };
|
||||
if (!streq(directive, "DATAW")) { return false; };
|
||||
let esz: i32 = au.sub.size: i32;
|
||||
let alen: i32 = au.alen: i32;
|
||||
|
||||
let last_ev: *node = nil;
|
||||
let repeat: bool = false;
|
||||
let cnt: i32 = 0;
|
||||
let e: *node = rhs.list;
|
||||
for (e != nil && cnt < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) { repeat = true; break; };
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
||||
if (ev == nil) { return false; };
|
||||
if (ev.kind != nkind.N_STRLIT) { return false; };
|
||||
last_ev = ev;
|
||||
cnt += 1;
|
||||
e = e.next;
|
||||
};
|
||||
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline("(SB),\"");
|
||||
let idx: i32 = 0;
|
||||
e = rhs.list;
|
||||
for (e != nil && idx < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) { break; };
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
||||
let i: i32 = 0;
|
||||
for (i < 8) { emitdatawbyte(0u8); i += 1; };
|
||||
let v: u64 = ev.str.len: u64;
|
||||
i = 0;
|
||||
for (i < 8) {
|
||||
emitdatawbyte((v & 255u64): u8);
|
||||
v = v >> 8u64;
|
||||
i += 1;
|
||||
};
|
||||
i = 16;
|
||||
for (i < esz) { emitdatawbyte(0u8); i += 1; };
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
for (idx < alen) {
|
||||
let v: u64 = 0u64;
|
||||
if (repeat && last_ev != nil) { v = last_ev.str.len: u64; };
|
||||
let i: i32 = 0;
|
||||
for (i < 8) { emitdatawbyte(0u8); i += 1; };
|
||||
i = 0;
|
||||
for (i < 8) {
|
||||
emitdatawbyte((v & 255u64): u8);
|
||||
v = v >> 8u64;
|
||||
i += 1;
|
||||
};
|
||||
i = 16;
|
||||
for (i < esz) { emitdatawbyte(0u8); i += 1; };
|
||||
idx += 1;
|
||||
};
|
||||
emitline("\"\n");
|
||||
|
||||
idx = 0;
|
||||
e = rhs.list;
|
||||
for (e != nil && idx < alen) {
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) { break; };
|
||||
};
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
||||
if (ev.str.len > 0) {
|
||||
let lab: str = internstrlit(c, ev.str);
|
||||
emitline("DATAR ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline("+");
|
||||
emitint((idx * esz): i64);
|
||||
emitline("(SB),");
|
||||
emitbytes( lab.ptr, lab.len: u64);
|
||||
emitline("(SB)\n");
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
for (idx < alen) {
|
||||
if (repeat && last_ev != nil && last_ev.str.len > 0) {
|
||||
let lab: str = internstrlit(c, last_ev.str);
|
||||
emitline("DATAR ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline("+");
|
||||
emitint((idx * esz): i64);
|
||||
emitline("(SB),");
|
||||
emitbytes( lab.ptr, lab.len: u64);
|
||||
emitline("(SB)\n");
|
||||
};
|
||||
idx += 1;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
// emitarraydata — top-level wrapper. Two-pass validate-then-emit
|
||||
// avoids partial-byte corruption if the rhs shape can't reduce.
|
||||
// nil rhs is the "no-rhs zero-init" shape (e.g. `let buf: [N]u8;`
|
||||
@@ -1800,6 +1982,11 @@ fn emitarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
emitline("\"\n");
|
||||
return true;
|
||||
};
|
||||
// str-element arrays carry per-element ptr relocations — handled
|
||||
// by the dedicated DATAW+DATAR helper (#18).
|
||||
if (emitstrarraydata(c, directive, name, module, arrt, rhs)) {
|
||||
return true;
|
||||
};
|
||||
if (!emitarraylitbytes(c, arrt, rhs, 0)) { return false; };
|
||||
emitline(directive);
|
||||
emitline(" ");
|
||||
|
||||
Reference in New Issue
Block a user