wcc/cgen: #117 const slice-of-(str,*fn) DATA + &fn->DATAR reloc (both-stage)
This commit is contained in:
@@ -38944,6 +38944,49 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
// #87: tagged global with a str/slice-variant literal init —
|
||||
// pre-intern so emittaggeddata's DATAR (ptr@+8) finds its _S_
|
||||
// rodata row (the #48 tuple-arm pattern; cstage letpreintern twin).
|
||||
// #117: slice-of-tuple global — pre-intern each row's
|
||||
// str-element literals in row-then-element order so
|
||||
// emitslicedata's per-row DATAR patches find their _S_
|
||||
// rodata rows (cstage letpreintern twin). Bounded to
|
||||
// inline N_TTUPLE element types.
|
||||
if (!handled && r != nil && d.lhs != nil) {
|
||||
if (r.kind == nkind.N_ARRLIT
|
||||
&& d.lhs.kind == nkind.N_TSLICE) {
|
||||
let tupnode: *node = d.lhs.lhs;
|
||||
if (tupnode != nil && tupnode.kind == nkind.N_TTUPLE) {
|
||||
handled = true;
|
||||
let row: *node = r.list;
|
||||
for (row != nil) {
|
||||
let rw: *node = row;
|
||||
for (rw != nil && rw.kind == nkind.N_CAST) {
|
||||
rw = rw.lhs;
|
||||
};
|
||||
if (rw != nil && rw.kind == nkind.N_TUPLE) {
|
||||
let tp: *node = tupnode.list;
|
||||
let e: *node = rw.list;
|
||||
for (e != nil && tp != nil) {
|
||||
let et: *node = tp.lhs;
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev != nil) {
|
||||
if (ev.kind == nkind.N_STRLIT
|
||||
&& (isstrtype(c, et) || isslicetype(c, et))) {
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
};
|
||||
};
|
||||
e = e.next;
|
||||
tp = tp.next;
|
||||
};
|
||||
};
|
||||
row = row.next;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (!handled && r != nil && d.lhs != nil) {
|
||||
let tlt: *node = d.lhs;
|
||||
for (tlt != nil && tlt.kind == nkind.N_TNAME) {
|
||||
@@ -39684,7 +39727,7 @@ fn emitarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
// and slice-of-{str,slice,tagged} elements (per-element relocs / #17)
|
||||
// all loud-stop (rule 7, #10 follow-ups).
|
||||
fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
rhs: *node) void = {
|
||||
sltnode: *node, rhs: *node) void = {
|
||||
let su: *tinfo = slt;
|
||||
su = tichase(su);
|
||||
// Defensive, mirrors cstage emit_slice_data's
|
||||
@@ -39696,14 +39739,6 @@ fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
let etype: *tinfo = su.sub;
|
||||
let eu: *tinfo = etype;
|
||||
eu = tichase(eu);
|
||||
if (eu != nil) {
|
||||
if (eu.kind == tykind.TY_STR || eu.kind == tykind.TY_SLICE
|
||||
|| eu.kind == tykind.TY_TAGGED) {
|
||||
let m: str = "emitslicedata: slice-of-{str,slice,tagged} literal static-init unsupported (#10 follow-up, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
// Count elements; reject `...` (a slice literal has no target N).
|
||||
let k: i32 = 0;
|
||||
let e: *node = rhs.list;
|
||||
@@ -39718,23 +39753,84 @@ fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
k += 1;
|
||||
e = e.next;
|
||||
};
|
||||
let esz: i32 = etype.size: i32;
|
||||
// Synthesize [k]T to ride the emitarraylitbytes choke-point.
|
||||
let arrt: *tinfo = newtype(tykind.TY_ARRAY);
|
||||
arrt.sub = etype;
|
||||
arrt.alen = k: u64;
|
||||
arrt.size = (k * esz): u64;
|
||||
if (!emitarraylitbytes(c, arrt, rhs, 0)) {
|
||||
let m: str = "emitslicedata: slice-literal element not a foldable constant (#10, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
// #117 aggregate-element arm: a slice of inline (str,*fn)-style
|
||||
// TUPLE rows. The element type-AST node (sltnode.lhs = N_TTUPLE)
|
||||
// drives the per-element slot classification the node-based
|
||||
// emittuplerow helpers expect; cstage drives the same off the tuple
|
||||
// tinfo's params. Bounded to inline N_TTUPLE element types.
|
||||
let tupnode: *node = nil;
|
||||
if (sltnode != nil) { tupnode = sltnode.lhs; };
|
||||
let istuprow: bool = false;
|
||||
if (eu != nil && eu.kind == tykind.TY_TUPLE && tupnode != nil) {
|
||||
if (tupnode.kind == nkind.N_TTUPLE) { istuprow = true; };
|
||||
};
|
||||
if (istuprow) {
|
||||
let stride: i32 = etype.size: i32;
|
||||
// Validate every row before any bytes (two-pass, partial-row
|
||||
// safe).
|
||||
let e2: *node = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
let bad: bool = false;
|
||||
if (row == nil) { bad = true; }
|
||||
else if (row.kind != nkind.N_TUPLE) { bad = true; }
|
||||
else if (!tuplerowfoldable(c, tupnode, row)) { bad = true; };
|
||||
if (bad) {
|
||||
let m: str = "emitslicedata: tuple-row element not a foldable constant ((str,*fn) rows only; #117, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
e2 = e2.next;
|
||||
};
|
||||
// Backing: k rows, bytes (one DATAW) then per-row relocs.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
e2 = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
emittuplerowbytes(c, tupnode, row);
|
||||
e2 = e2.next;
|
||||
};
|
||||
emitline("\"\n");
|
||||
let rowoff: i32 = 0;
|
||||
e2 = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
emittuplerowrelocs(c, name, module, true, rowoff, tupnode, row);
|
||||
rowoff += stride;
|
||||
e2 = e2.next;
|
||||
};
|
||||
} else {
|
||||
if (eu != nil) {
|
||||
if (eu.kind == tykind.TY_STR || eu.kind == tykind.TY_SLICE
|
||||
|| eu.kind == tykind.TY_TAGGED) {
|
||||
let m: str = "emitslicedata: slice-of-{str,slice,tagged} literal static-init unsupported (#10 follow-up, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
let esz: i32 = etype.size: i32;
|
||||
// Synthesize [k]T to ride the emitarraylitbytes choke-point.
|
||||
let arrt: *tinfo = newtype(tykind.TY_ARRAY);
|
||||
arrt.sub = etype;
|
||||
arrt.alen = k: u64;
|
||||
arrt.size = (k * esz): u64;
|
||||
if (!emitarraylitbytes(c, arrt, rhs, 0)) {
|
||||
let m: str = "emitslicedata: slice-literal element not a foldable constant (#10, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// Writable backing data.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
emitarraylitbytes(c, arrt, rhs, 1);
|
||||
emitline("\"\n");
|
||||
};
|
||||
// Writable backing data.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
emitarraylitbytes(c, arrt, rhs, 1);
|
||||
emitline("\"\n");
|
||||
// 24B header: ptr placeholder + LE len + LE cap (both = k). Word
|
||||
// sizes from the type table (rule 13).
|
||||
emitline("DATAW ");
|
||||
@@ -39850,6 +39946,23 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
|
||||
return true;
|
||||
};
|
||||
|
||||
// nodefnptr — true if `ev` (casts already peeled by the caller) is the
|
||||
// address-of a top-level fn (`&f`). The detect-half of the FIRST &fn→DATAR
|
||||
// reloc machinery (#117 slice-row + #119 scalar-global); mirrors the
|
||||
// address-of-fn codegen arm (fnretlookup at the N_UN TK_AMP ident,
|
||||
// cgenexpr.ww). The reloc target symbol is emitted via emitfnname at the
|
||||
// call site (cstage node_fnptr_sym returns the mangled string directly).
|
||||
fn nodefnptr(c: *cgen, ev: *node) bool = {
|
||||
if (ev == nil) { return false; };
|
||||
if (ev.kind != nkind.N_UN) { return false; };
|
||||
if (ev.op != tkind.TK_AMP) { return false; };
|
||||
let opnd: *node = ev.lhs;
|
||||
if (opnd == nil) { return false; };
|
||||
if (opnd.kind != nkind.N_IDENT) { return false; };
|
||||
if (fnretlookup(c, opnd.str) == nil) { return false; };
|
||||
return true;
|
||||
};
|
||||
|
||||
// tuplerowfoldable — validate every cast-peeled element of `rhs` (an
|
||||
// N_TUPLE) reduces to a static row: an int literal (foldintliteral) or a
|
||||
// str literal in a str/slice slot. A tagged element slot has no
|
||||
@@ -39880,6 +39993,8 @@ fn tuplerowfoldable(c: *cgen, tt: *node, rhs: *node) bool = {
|
||||
let wide: bool = isstrtype(c, et) || isslicetype(c, et);
|
||||
if (wide) {
|
||||
if (ev.kind != nkind.N_STRLIT) { return false; };
|
||||
} else if (nodefnptr(c, ev)) {
|
||||
// #117: a `&fn` element folds to an 8B reloc slot.
|
||||
} else {
|
||||
let v: u64 = 0u64;
|
||||
if (!foldintliteral(ev, &v)) { return false; };
|
||||
@@ -39918,6 +40033,11 @@ fn emittuplerowbytes(c: *cgen, tt: *node, rhs: *node) void = {
|
||||
i = 16;
|
||||
let ssz: i32 = primtypesize("str"): i32;
|
||||
for (i < ssz) { emitdatawbyte(0u8); i += 1; };
|
||||
} else if (nodefnptr(c, ev)) {
|
||||
// #117: a `&fn` element is an 8B zero ptr placeholder;
|
||||
// the reloc is patched in emittuplerowrelocs.
|
||||
let i: i32 = 0;
|
||||
for (i < 8) { emitdatawbyte(0u8); i += 1; };
|
||||
} else {
|
||||
let v: u64 = 0u64;
|
||||
foldintliteral(ev, &v);
|
||||
@@ -39965,6 +40085,19 @@ fn emittuplerowrelocs(c: *cgen, name: str, module: str, backing: bool, rowoff: i
|
||||
};
|
||||
foff += (tyslicesize(): i32);
|
||||
} else {
|
||||
// #117: the `&fn` element's reloc — the FIRST &fn→DATAR
|
||||
// in the emitter; patches the 8B slot at holder+foff
|
||||
// with the fn's TEXT VA via emitfnname.
|
||||
if (nodefnptr(c, ev)) {
|
||||
emitline("DATAR ");
|
||||
emitsymnamehint(c, name, module);
|
||||
if (backing) { emitline(".d"); };
|
||||
emitline("+");
|
||||
emitint(foff: i64);
|
||||
emitline("(SB),");
|
||||
emitfnname(c, ev.lhs.str, c.curmod);
|
||||
emitline("(SB)\n");
|
||||
};
|
||||
// #22: slot stride via the accessor (tagged is
|
||||
// rejected upstream; non-wide is 8 today — keeps the
|
||||
// stride on the accessor scale).
|
||||
@@ -40220,7 +40353,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
// only/`...` shapes (rule 7).
|
||||
if (r != nil && r.kind == nkind.N_ARRLIT) {
|
||||
emitslicedata(c, nm, d.nmod,
|
||||
d.lhs.type_: *tinfo, r);
|
||||
d.lhs.type_: *tinfo, d.lhs, r);
|
||||
} else {
|
||||
// zero-init: accept no rhs or nil.
|
||||
// Any other rhs is skipped →
|
||||
|
||||
@@ -1390,6 +1390,49 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
// #87: tagged global with a str/slice-variant literal init —
|
||||
// pre-intern so emittaggeddata's DATAR (ptr@+8) finds its _S_
|
||||
// rodata row (the #48 tuple-arm pattern; cstage letpreintern twin).
|
||||
// #117: slice-of-tuple global — pre-intern each row's
|
||||
// str-element literals in row-then-element order so
|
||||
// emitslicedata's per-row DATAR patches find their _S_
|
||||
// rodata rows (cstage letpreintern twin). Bounded to
|
||||
// inline N_TTUPLE element types.
|
||||
if (!handled && r != nil && d.lhs != nil) {
|
||||
if (r.kind == nkind.N_ARRLIT
|
||||
&& d.lhs.kind == nkind.N_TSLICE) {
|
||||
let tupnode: *node = d.lhs.lhs;
|
||||
if (tupnode != nil && tupnode.kind == nkind.N_TTUPLE) {
|
||||
handled = true;
|
||||
let row: *node = r.list;
|
||||
for (row != nil) {
|
||||
let rw: *node = row;
|
||||
for (rw != nil && rw.kind == nkind.N_CAST) {
|
||||
rw = rw.lhs;
|
||||
};
|
||||
if (rw != nil && rw.kind == nkind.N_TUPLE) {
|
||||
let tp: *node = tupnode.list;
|
||||
let e: *node = rw.list;
|
||||
for (e != nil && tp != nil) {
|
||||
let et: *node = tp.lhs;
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev != nil) {
|
||||
if (ev.kind == nkind.N_STRLIT
|
||||
&& (isstrtype(c, et) || isslicetype(c, et))) {
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
};
|
||||
};
|
||||
e = e.next;
|
||||
tp = tp.next;
|
||||
};
|
||||
};
|
||||
row = row.next;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (!handled && r != nil && d.lhs != nil) {
|
||||
let tlt: *node = d.lhs;
|
||||
for (tlt != nil && tlt.kind == nkind.N_TNAME) {
|
||||
@@ -2130,7 +2173,7 @@ fn emitarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
// and slice-of-{str,slice,tagged} elements (per-element relocs / #17)
|
||||
// all loud-stop (rule 7, #10 follow-ups).
|
||||
fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
rhs: *node) void = {
|
||||
sltnode: *node, rhs: *node) void = {
|
||||
let su: *tinfo = slt;
|
||||
su = tichase(su);
|
||||
// Defensive, mirrors cstage emit_slice_data's
|
||||
@@ -2142,14 +2185,6 @@ fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
let etype: *tinfo = su.sub;
|
||||
let eu: *tinfo = etype;
|
||||
eu = tichase(eu);
|
||||
if (eu != nil) {
|
||||
if (eu.kind == tykind.TY_STR || eu.kind == tykind.TY_SLICE
|
||||
|| eu.kind == tykind.TY_TAGGED) {
|
||||
let m: str = "emitslicedata: slice-of-{str,slice,tagged} literal static-init unsupported (#10 follow-up, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
// Count elements; reject `...` (a slice literal has no target N).
|
||||
let k: i32 = 0;
|
||||
let e: *node = rhs.list;
|
||||
@@ -2164,23 +2199,84 @@ fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
k += 1;
|
||||
e = e.next;
|
||||
};
|
||||
let esz: i32 = etype.size: i32;
|
||||
// Synthesize [k]T to ride the emitarraylitbytes choke-point.
|
||||
let arrt: *tinfo = newtype(tykind.TY_ARRAY);
|
||||
arrt.sub = etype;
|
||||
arrt.alen = k: u64;
|
||||
arrt.size = (k * esz): u64;
|
||||
if (!emitarraylitbytes(c, arrt, rhs, 0)) {
|
||||
let m: str = "emitslicedata: slice-literal element not a foldable constant (#10, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
// #117 aggregate-element arm: a slice of inline (str,*fn)-style
|
||||
// TUPLE rows. The element type-AST node (sltnode.lhs = N_TTUPLE)
|
||||
// drives the per-element slot classification the node-based
|
||||
// emittuplerow helpers expect; cstage drives the same off the tuple
|
||||
// tinfo's params. Bounded to inline N_TTUPLE element types.
|
||||
let tupnode: *node = nil;
|
||||
if (sltnode != nil) { tupnode = sltnode.lhs; };
|
||||
let istuprow: bool = false;
|
||||
if (eu != nil && eu.kind == tykind.TY_TUPLE && tupnode != nil) {
|
||||
if (tupnode.kind == nkind.N_TTUPLE) { istuprow = true; };
|
||||
};
|
||||
if (istuprow) {
|
||||
let stride: i32 = etype.size: i32;
|
||||
// Validate every row before any bytes (two-pass, partial-row
|
||||
// safe).
|
||||
let e2: *node = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
let bad: bool = false;
|
||||
if (row == nil) { bad = true; }
|
||||
else if (row.kind != nkind.N_TUPLE) { bad = true; }
|
||||
else if (!tuplerowfoldable(c, tupnode, row)) { bad = true; };
|
||||
if (bad) {
|
||||
let m: str = "emitslicedata: tuple-row element not a foldable constant ((str,*fn) rows only; #117, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
e2 = e2.next;
|
||||
};
|
||||
// Backing: k rows, bytes (one DATAW) then per-row relocs.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
e2 = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
emittuplerowbytes(c, tupnode, row);
|
||||
e2 = e2.next;
|
||||
};
|
||||
emitline("\"\n");
|
||||
let rowoff: i32 = 0;
|
||||
e2 = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
emittuplerowrelocs(c, name, module, true, rowoff, tupnode, row);
|
||||
rowoff += stride;
|
||||
e2 = e2.next;
|
||||
};
|
||||
} else {
|
||||
if (eu != nil) {
|
||||
if (eu.kind == tykind.TY_STR || eu.kind == tykind.TY_SLICE
|
||||
|| eu.kind == tykind.TY_TAGGED) {
|
||||
let m: str = "emitslicedata: slice-of-{str,slice,tagged} literal static-init unsupported (#10 follow-up, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
let esz: i32 = etype.size: i32;
|
||||
// Synthesize [k]T to ride the emitarraylitbytes choke-point.
|
||||
let arrt: *tinfo = newtype(tykind.TY_ARRAY);
|
||||
arrt.sub = etype;
|
||||
arrt.alen = k: u64;
|
||||
arrt.size = (k * esz): u64;
|
||||
if (!emitarraylitbytes(c, arrt, rhs, 0)) {
|
||||
let m: str = "emitslicedata: slice-literal element not a foldable constant (#10, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// Writable backing data.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
emitarraylitbytes(c, arrt, rhs, 1);
|
||||
emitline("\"\n");
|
||||
};
|
||||
// Writable backing data.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
emitarraylitbytes(c, arrt, rhs, 1);
|
||||
emitline("\"\n");
|
||||
// 24B header: ptr placeholder + LE len + LE cap (both = k). Word
|
||||
// sizes from the type table (rule 13).
|
||||
emitline("DATAW ");
|
||||
@@ -2296,6 +2392,23 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
|
||||
return true;
|
||||
};
|
||||
|
||||
// nodefnptr — true if `ev` (casts already peeled by the caller) is the
|
||||
// address-of a top-level fn (`&f`). The detect-half of the FIRST &fn→DATAR
|
||||
// reloc machinery (#117 slice-row + #119 scalar-global); mirrors the
|
||||
// address-of-fn codegen arm (fnretlookup at the N_UN TK_AMP ident,
|
||||
// cgenexpr.ww). The reloc target symbol is emitted via emitfnname at the
|
||||
// call site (cstage node_fnptr_sym returns the mangled string directly).
|
||||
fn nodefnptr(c: *cgen, ev: *node) bool = {
|
||||
if (ev == nil) { return false; };
|
||||
if (ev.kind != nkind.N_UN) { return false; };
|
||||
if (ev.op != tkind.TK_AMP) { return false; };
|
||||
let opnd: *node = ev.lhs;
|
||||
if (opnd == nil) { return false; };
|
||||
if (opnd.kind != nkind.N_IDENT) { return false; };
|
||||
if (fnretlookup(c, opnd.str) == nil) { return false; };
|
||||
return true;
|
||||
};
|
||||
|
||||
// tuplerowfoldable — validate every cast-peeled element of `rhs` (an
|
||||
// N_TUPLE) reduces to a static row: an int literal (foldintliteral) or a
|
||||
// str literal in a str/slice slot. A tagged element slot has no
|
||||
@@ -2326,6 +2439,8 @@ fn tuplerowfoldable(c: *cgen, tt: *node, rhs: *node) bool = {
|
||||
let wide: bool = isstrtype(c, et) || isslicetype(c, et);
|
||||
if (wide) {
|
||||
if (ev.kind != nkind.N_STRLIT) { return false; };
|
||||
} else if (nodefnptr(c, ev)) {
|
||||
// #117: a `&fn` element folds to an 8B reloc slot.
|
||||
} else {
|
||||
let v: u64 = 0u64;
|
||||
if (!foldintliteral(ev, &v)) { return false; };
|
||||
@@ -2364,6 +2479,11 @@ fn emittuplerowbytes(c: *cgen, tt: *node, rhs: *node) void = {
|
||||
i = 16;
|
||||
let ssz: i32 = primtypesize("str"): i32;
|
||||
for (i < ssz) { emitdatawbyte(0u8); i += 1; };
|
||||
} else if (nodefnptr(c, ev)) {
|
||||
// #117: a `&fn` element is an 8B zero ptr placeholder;
|
||||
// the reloc is patched in emittuplerowrelocs.
|
||||
let i: i32 = 0;
|
||||
for (i < 8) { emitdatawbyte(0u8); i += 1; };
|
||||
} else {
|
||||
let v: u64 = 0u64;
|
||||
foldintliteral(ev, &v);
|
||||
@@ -2411,6 +2531,19 @@ fn emittuplerowrelocs(c: *cgen, name: str, module: str, backing: bool, rowoff: i
|
||||
};
|
||||
foff += (tyslicesize(): i32);
|
||||
} else {
|
||||
// #117: the `&fn` element's reloc — the FIRST &fn→DATAR
|
||||
// in the emitter; patches the 8B slot at holder+foff
|
||||
// with the fn's TEXT VA via emitfnname.
|
||||
if (nodefnptr(c, ev)) {
|
||||
emitline("DATAR ");
|
||||
emitsymnamehint(c, name, module);
|
||||
if (backing) { emitline(".d"); };
|
||||
emitline("+");
|
||||
emitint(foff: i64);
|
||||
emitline("(SB),");
|
||||
emitfnname(c, ev.lhs.str, c.curmod);
|
||||
emitline("(SB)\n");
|
||||
};
|
||||
// #22: slot stride via the accessor (tagged is
|
||||
// rejected upstream; non-wide is 8 today — keeps the
|
||||
// stride on the accessor scale).
|
||||
@@ -2666,7 +2799,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
// only/`...` shapes (rule 7).
|
||||
if (r != nil && r.kind == nkind.N_ARRLIT) {
|
||||
emitslicedata(c, nm, d.nmod,
|
||||
d.lhs.type_: *tinfo, r);
|
||||
d.lhs.type_: *tinfo, d.lhs, r);
|
||||
} else {
|
||||
// zero-init: accept no rhs or nil.
|
||||
// Any other rhs is skipped →
|
||||
|
||||
@@ -38944,6 +38944,49 @@ export fn letpreintern(c: *cgen, file: *node) void = {
|
||||
// #87: tagged global with a str/slice-variant literal init —
|
||||
// pre-intern so emittaggeddata's DATAR (ptr@+8) finds its _S_
|
||||
// rodata row (the #48 tuple-arm pattern; cstage letpreintern twin).
|
||||
// #117: slice-of-tuple global — pre-intern each row's
|
||||
// str-element literals in row-then-element order so
|
||||
// emitslicedata's per-row DATAR patches find their _S_
|
||||
// rodata rows (cstage letpreintern twin). Bounded to
|
||||
// inline N_TTUPLE element types.
|
||||
if (!handled && r != nil && d.lhs != nil) {
|
||||
if (r.kind == nkind.N_ARRLIT
|
||||
&& d.lhs.kind == nkind.N_TSLICE) {
|
||||
let tupnode: *node = d.lhs.lhs;
|
||||
if (tupnode != nil && tupnode.kind == nkind.N_TTUPLE) {
|
||||
handled = true;
|
||||
let row: *node = r.list;
|
||||
for (row != nil) {
|
||||
let rw: *node = row;
|
||||
for (rw != nil && rw.kind == nkind.N_CAST) {
|
||||
rw = rw.lhs;
|
||||
};
|
||||
if (rw != nil && rw.kind == nkind.N_TUPLE) {
|
||||
let tp: *node = tupnode.list;
|
||||
let e: *node = rw.list;
|
||||
for (e != nil && tp != nil) {
|
||||
let et: *node = tp.lhs;
|
||||
let ev: *node = e;
|
||||
for (ev != nil && ev.kind == nkind.N_CAST) {
|
||||
ev = ev.lhs;
|
||||
};
|
||||
if (ev != nil) {
|
||||
if (ev.kind == nkind.N_STRLIT
|
||||
&& (isstrtype(c, et) || isslicetype(c, et))) {
|
||||
if (ev.str.len > 0) {
|
||||
internstrlit(c, ev.str);
|
||||
};
|
||||
};
|
||||
};
|
||||
e = e.next;
|
||||
tp = tp.next;
|
||||
};
|
||||
};
|
||||
row = row.next;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (!handled && r != nil && d.lhs != nil) {
|
||||
let tlt: *node = d.lhs;
|
||||
for (tlt != nil && tlt.kind == nkind.N_TNAME) {
|
||||
@@ -39684,7 +39727,7 @@ fn emitarraydata(c: *cgen, directive: str, name: str, module: str,
|
||||
// and slice-of-{str,slice,tagged} elements (per-element relocs / #17)
|
||||
// all loud-stop (rule 7, #10 follow-ups).
|
||||
fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
rhs: *node) void = {
|
||||
sltnode: *node, rhs: *node) void = {
|
||||
let su: *tinfo = slt;
|
||||
su = tichase(su);
|
||||
// Defensive, mirrors cstage emit_slice_data's
|
||||
@@ -39696,14 +39739,6 @@ fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
let etype: *tinfo = su.sub;
|
||||
let eu: *tinfo = etype;
|
||||
eu = tichase(eu);
|
||||
if (eu != nil) {
|
||||
if (eu.kind == tykind.TY_STR || eu.kind == tykind.TY_SLICE
|
||||
|| eu.kind == tykind.TY_TAGGED) {
|
||||
let m: str = "emitslicedata: slice-of-{str,slice,tagged} literal static-init unsupported (#10 follow-up, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
// Count elements; reject `...` (a slice literal has no target N).
|
||||
let k: i32 = 0;
|
||||
let e: *node = rhs.list;
|
||||
@@ -39718,23 +39753,84 @@ fn emitslicedata(c: *cgen, name: str, module: str, slt: *tinfo,
|
||||
k += 1;
|
||||
e = e.next;
|
||||
};
|
||||
let esz: i32 = etype.size: i32;
|
||||
// Synthesize [k]T to ride the emitarraylitbytes choke-point.
|
||||
let arrt: *tinfo = newtype(tykind.TY_ARRAY);
|
||||
arrt.sub = etype;
|
||||
arrt.alen = k: u64;
|
||||
arrt.size = (k * esz): u64;
|
||||
if (!emitarraylitbytes(c, arrt, rhs, 0)) {
|
||||
let m: str = "emitslicedata: slice-literal element not a foldable constant (#10, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
// #117 aggregate-element arm: a slice of inline (str,*fn)-style
|
||||
// TUPLE rows. The element type-AST node (sltnode.lhs = N_TTUPLE)
|
||||
// drives the per-element slot classification the node-based
|
||||
// emittuplerow helpers expect; cstage drives the same off the tuple
|
||||
// tinfo's params. Bounded to inline N_TTUPLE element types.
|
||||
let tupnode: *node = nil;
|
||||
if (sltnode != nil) { tupnode = sltnode.lhs; };
|
||||
let istuprow: bool = false;
|
||||
if (eu != nil && eu.kind == tykind.TY_TUPLE && tupnode != nil) {
|
||||
if (tupnode.kind == nkind.N_TTUPLE) { istuprow = true; };
|
||||
};
|
||||
if (istuprow) {
|
||||
let stride: i32 = etype.size: i32;
|
||||
// Validate every row before any bytes (two-pass, partial-row
|
||||
// safe).
|
||||
let e2: *node = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
let bad: bool = false;
|
||||
if (row == nil) { bad = true; }
|
||||
else if (row.kind != nkind.N_TUPLE) { bad = true; }
|
||||
else if (!tuplerowfoldable(c, tupnode, row)) { bad = true; };
|
||||
if (bad) {
|
||||
let m: str = "emitslicedata: tuple-row element not a foldable constant ((str,*fn) rows only; #117, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
e2 = e2.next;
|
||||
};
|
||||
// Backing: k rows, bytes (one DATAW) then per-row relocs.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
e2 = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
emittuplerowbytes(c, tupnode, row);
|
||||
e2 = e2.next;
|
||||
};
|
||||
emitline("\"\n");
|
||||
let rowoff: i32 = 0;
|
||||
e2 = rhs.list;
|
||||
for (e2 != nil) {
|
||||
let row: *node = e2;
|
||||
for (row != nil && row.kind == nkind.N_CAST) { row = row.lhs; };
|
||||
emittuplerowrelocs(c, name, module, true, rowoff, tupnode, row);
|
||||
rowoff += stride;
|
||||
e2 = e2.next;
|
||||
};
|
||||
} else {
|
||||
if (eu != nil) {
|
||||
if (eu.kind == tykind.TY_STR || eu.kind == tykind.TY_SLICE
|
||||
|| eu.kind == tykind.TY_TAGGED) {
|
||||
let m: str = "emitslicedata: slice-of-{str,slice,tagged} literal static-init unsupported (#10 follow-up, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
let esz: i32 = etype.size: i32;
|
||||
// Synthesize [k]T to ride the emitarraylitbytes choke-point.
|
||||
let arrt: *tinfo = newtype(tykind.TY_ARRAY);
|
||||
arrt.sub = etype;
|
||||
arrt.alen = k: u64;
|
||||
arrt.size = (k * esz): u64;
|
||||
if (!emitarraylitbytes(c, arrt, rhs, 0)) {
|
||||
let m: str = "emitslicedata: slice-literal element not a foldable constant (#10, rule 7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// Writable backing data.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
emitarraylitbytes(c, arrt, rhs, 1);
|
||||
emitline("\"\n");
|
||||
};
|
||||
// Writable backing data.
|
||||
emitline("DATAW ");
|
||||
emitsymnamehint(c, name, module);
|
||||
emitline(".d(SB),\"");
|
||||
emitarraylitbytes(c, arrt, rhs, 1);
|
||||
emitline("\"\n");
|
||||
// 24B header: ptr placeholder + LE len + LE cap (both = k). Word
|
||||
// sizes from the type table (rule 13).
|
||||
emitline("DATAW ");
|
||||
@@ -39850,6 +39946,23 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
|
||||
return true;
|
||||
};
|
||||
|
||||
// nodefnptr — true if `ev` (casts already peeled by the caller) is the
|
||||
// address-of a top-level fn (`&f`). The detect-half of the FIRST &fn→DATAR
|
||||
// reloc machinery (#117 slice-row + #119 scalar-global); mirrors the
|
||||
// address-of-fn codegen arm (fnretlookup at the N_UN TK_AMP ident,
|
||||
// cgenexpr.ww). The reloc target symbol is emitted via emitfnname at the
|
||||
// call site (cstage node_fnptr_sym returns the mangled string directly).
|
||||
fn nodefnptr(c: *cgen, ev: *node) bool = {
|
||||
if (ev == nil) { return false; };
|
||||
if (ev.kind != nkind.N_UN) { return false; };
|
||||
if (ev.op != tkind.TK_AMP) { return false; };
|
||||
let opnd: *node = ev.lhs;
|
||||
if (opnd == nil) { return false; };
|
||||
if (opnd.kind != nkind.N_IDENT) { return false; };
|
||||
if (fnretlookup(c, opnd.str) == nil) { return false; };
|
||||
return true;
|
||||
};
|
||||
|
||||
// tuplerowfoldable — validate every cast-peeled element of `rhs` (an
|
||||
// N_TUPLE) reduces to a static row: an int literal (foldintliteral) or a
|
||||
// str literal in a str/slice slot. A tagged element slot has no
|
||||
@@ -39880,6 +39993,8 @@ fn tuplerowfoldable(c: *cgen, tt: *node, rhs: *node) bool = {
|
||||
let wide: bool = isstrtype(c, et) || isslicetype(c, et);
|
||||
if (wide) {
|
||||
if (ev.kind != nkind.N_STRLIT) { return false; };
|
||||
} else if (nodefnptr(c, ev)) {
|
||||
// #117: a `&fn` element folds to an 8B reloc slot.
|
||||
} else {
|
||||
let v: u64 = 0u64;
|
||||
if (!foldintliteral(ev, &v)) { return false; };
|
||||
@@ -39918,6 +40033,11 @@ fn emittuplerowbytes(c: *cgen, tt: *node, rhs: *node) void = {
|
||||
i = 16;
|
||||
let ssz: i32 = primtypesize("str"): i32;
|
||||
for (i < ssz) { emitdatawbyte(0u8); i += 1; };
|
||||
} else if (nodefnptr(c, ev)) {
|
||||
// #117: a `&fn` element is an 8B zero ptr placeholder;
|
||||
// the reloc is patched in emittuplerowrelocs.
|
||||
let i: i32 = 0;
|
||||
for (i < 8) { emitdatawbyte(0u8); i += 1; };
|
||||
} else {
|
||||
let v: u64 = 0u64;
|
||||
foldintliteral(ev, &v);
|
||||
@@ -39965,6 +40085,19 @@ fn emittuplerowrelocs(c: *cgen, name: str, module: str, backing: bool, rowoff: i
|
||||
};
|
||||
foff += (tyslicesize(): i32);
|
||||
} else {
|
||||
// #117: the `&fn` element's reloc — the FIRST &fn→DATAR
|
||||
// in the emitter; patches the 8B slot at holder+foff
|
||||
// with the fn's TEXT VA via emitfnname.
|
||||
if (nodefnptr(c, ev)) {
|
||||
emitline("DATAR ");
|
||||
emitsymnamehint(c, name, module);
|
||||
if (backing) { emitline(".d"); };
|
||||
emitline("+");
|
||||
emitint(foff: i64);
|
||||
emitline("(SB),");
|
||||
emitfnname(c, ev.lhs.str, c.curmod);
|
||||
emitline("(SB)\n");
|
||||
};
|
||||
// #22: slot stride via the accessor (tagged is
|
||||
// rejected upstream; non-wide is 8 today — keeps the
|
||||
// stride on the accessor scale).
|
||||
@@ -40220,7 +40353,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
// only/`...` shapes (rule 7).
|
||||
if (r != nil && r.kind == nkind.N_ARRLIT) {
|
||||
emitslicedata(c, nm, d.nmod,
|
||||
d.lhs.type_: *tinfo, r);
|
||||
d.lhs.type_: *tinfo, d.lhs, r);
|
||||
} else {
|
||||
// zero-init: accept no rhs or nil.
|
||||
// Any other rhs is skipped →
|
||||
|
||||
Reference in New Issue
Block a user