wcc/cgen: #117 prep — factor emit_tuple_row backing-relative (byte-neutral)
This commit is contained in:
103
cmd/w6c/cgen.c
103
cmd/w6c/cgen.c
@@ -15010,44 +15010,24 @@ emit_tagged_data(FILE *out, Cg *c, const char *name, const char *module,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* emit_tuple_data — module-level `let g: (T0, T1, ...) = (v0, v1, ...);`
|
/* tuple_row_foldable — validate that every cast-peeled element of `rhs`
|
||||||
* static init (C-t3, #48). Slot layout (C-t0): a scalar element is one
|
* (an N_TUPLE) reduces to a static row: an int literal (fold_int_literal)
|
||||||
* 8B LE word, a str element its 24B header slot (8 zero ptr placeholder
|
* or a str literal in a str/slice slot. A tagged element slot has no
|
||||||
* + LE len + 8 zero cap) with a DATAR patching the ptr word at the
|
* static-init shape (tag word + payload widening) — reject so the caller
|
||||||
* element's slot offset — the per-element twin of the scalar-str-global
|
* loud-stops (#22a, rule 7); pre-guard an int init would have emitted one
|
||||||
* arm, offset like emit_strarray_data's rows. Elements must reduce to
|
* 8B word into the 16B+ box (silent layout skew). The validate twin of
|
||||||
* int (fold_int_literal) or str literals; anything else returns 0 and
|
* emit_tuple_row_bytes / emit_tuple_row_relocs: two-pass keeps a partial
|
||||||
* the caller loud-stops (rule 7 — pre-C-t3 the whole definition was
|
* row out of the output (emit_array_data precedent). Factored from
|
||||||
* SILENTLY skipped and reads saw BP-frame garbage). rhs == NULL
|
* emit_tuple_data so the slice-of-tuple backing (#117) shares it. */
|
||||||
* zero-inits the slot. */
|
|
||||||
static int
|
static int
|
||||||
emit_tuple_data(FILE *out, Cg *c, const char *name, const char *module,
|
tuple_row_foldable(Cg *c, Type *u, Node *rhs)
|
||||||
Type *t, Node *rhs)
|
|
||||||
{
|
{
|
||||||
Type *u = type_unwrap(t);
|
(void)c;
|
||||||
if (u == NULL || u->kind != TY_TUPLE) return 0;
|
|
||||||
const char *sym = mod_mangle_value(c, name, module);
|
|
||||||
if (rhs == NULL) {
|
|
||||||
fprintf(out, "DATAW %s(SB),\"", sym);
|
|
||||||
for (int i = 0; i < (int)u->size; i++)
|
|
||||||
emit_data_byte(out, 0);
|
|
||||||
fputs("\"\n", out);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (rhs->kind != N_TUPLE) return 0;
|
|
||||||
/* Validate: every cast-peeled element folds (int) or is a strlit
|
|
||||||
* in a str slot. Two-pass so a partial row never reaches the
|
|
||||||
* output (emit_array_data precedent). */
|
|
||||||
Tparam *tp = u->params;
|
Tparam *tp = u->params;
|
||||||
for (Node *e = rhs->list; e; e = e->next, tp = tp ? tp->next : NULL) {
|
for (Node *e = rhs->list; e; e = e->next, tp = tp ? tp->next : NULL) {
|
||||||
Node *ev = e;
|
Node *ev = e;
|
||||||
while (ev && ev->kind == N_CAST) ev = ev->lhs;
|
while (ev && ev->kind == N_CAST) ev = ev->lhs;
|
||||||
if (ev == NULL) return 0;
|
if (ev == NULL) return 0;
|
||||||
/* #22a (rule 7): a tagged element slot has no static-init
|
|
||||||
* shape (tag word + payload widening) — reject so the
|
|
||||||
* caller loud-stops; pre-guard an int init would have
|
|
||||||
* emitted one 8B word into the 16B+ box (silent layout
|
|
||||||
* skew). */
|
|
||||||
{
|
{
|
||||||
Type *eu = type_chase_named(tp ? tp->type : NULL);
|
Type *eu = type_chase_named(tp ? tp->type : NULL);
|
||||||
if (eu && eu->kind == TY_TAGGED) return 0;
|
if (eu && eu->kind == TY_TAGGED) return 0;
|
||||||
@@ -15061,8 +15041,19 @@ emit_tuple_data(FILE *out, Cg *c, const char *name, const char *module,
|
|||||||
u64 v;
|
u64 v;
|
||||||
if (!fold_int_literal(ev, &v)) return 0;
|
if (!fold_int_literal(ev, &v)) return 0;
|
||||||
}
|
}
|
||||||
fprintf(out, "DATAW %s(SB),\"", sym);
|
return 1;
|
||||||
tp = u->params;
|
}
|
||||||
|
|
||||||
|
/* emit_tuple_row_bytes — the row's element bytes, concatenated, into the
|
||||||
|
* currently-open DATAW quoted string (no DATAW wrapper, no sym). Slot
|
||||||
|
* layout (C-t0): a scalar element is one 8B LE word; a str/slice element
|
||||||
|
* its 24B header slot (8 zero ptr placeholder + LE len + 8 zero cap).
|
||||||
|
* Caller has already proven the row foldable (tuple_row_foldable). */
|
||||||
|
static void
|
||||||
|
emit_tuple_row_bytes(Cg *c, FILE *out, Type *u, Node *rhs)
|
||||||
|
{
|
||||||
|
(void)c;
|
||||||
|
Tparam *tp = u->params;
|
||||||
for (Node *e = rhs->list; e; e = e->next, tp = tp ? tp->next : NULL) {
|
for (Node *e = rhs->list; e; e = e->next, tp = tp ? tp->next : NULL) {
|
||||||
Node *ev = e;
|
Node *ev = e;
|
||||||
while (ev && ev->kind == N_CAST) ev = ev->lhs;
|
while (ev && ev->kind == N_CAST) ev = ev->lhs;
|
||||||
@@ -15082,9 +15073,19 @@ emit_tuple_data(FILE *out, Cg *c, const char *name, const char *module,
|
|||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
emit_data_byte(out, (u8)((v >> (i * 8)) & 0xff));
|
emit_data_byte(out, (u8)((v >> (i * 8)) & 0xff));
|
||||||
}
|
}
|
||||||
fputs("\"\n", out);
|
}
|
||||||
int foff = 0;
|
|
||||||
tp = u->params;
|
/* emit_tuple_row_relocs — the row's DATAR ptr patches, at backing-relative
|
||||||
|
* <holder>+<row_off>+<slot>. A str element patches the ptr word with the
|
||||||
|
* interned strlit's VA; the slot stride steps by tuple_eslot. row_off lets
|
||||||
|
* a slice backing place k rows contiguously (#117); emit_tuple_data passes
|
||||||
|
* 0 (foff matches the absolute element offset — byte-neutral). */
|
||||||
|
static void
|
||||||
|
emit_tuple_row_relocs(Cg *c, FILE *out, const char *holder, int row_off,
|
||||||
|
Type *u, Node *rhs)
|
||||||
|
{
|
||||||
|
int foff = row_off;
|
||||||
|
Tparam *tp = u->params;
|
||||||
for (Node *e = rhs->list; e; e = e->next, tp = tp ? tp->next : NULL) {
|
for (Node *e = rhs->list; e; e = e->next, tp = tp ? tp->next : NULL) {
|
||||||
Node *ev = e;
|
Node *ev = e;
|
||||||
while (ev && ev->kind == N_CAST) ev = ev->lhs;
|
while (ev && ev->kind == N_CAST) ev = ev->lhs;
|
||||||
@@ -15094,10 +15095,38 @@ emit_tuple_data(FILE *out, Cg *c, const char *name, const char *module,
|
|||||||
const char *lab = intern_strlit(c, ev->str,
|
const char *lab = intern_strlit(c, ev->str,
|
||||||
ev->strlen);
|
ev->strlen);
|
||||||
fprintf(out, "DATAR %s+%d(SB),%s(SB)\n",
|
fprintf(out, "DATAR %s+%d(SB),%s(SB)\n",
|
||||||
sym, foff, lab);
|
holder, foff, lab);
|
||||||
}
|
}
|
||||||
foff += tuple_eslot(tp ? tp->type : NULL);
|
foff += tuple_eslot(tp ? tp->type : NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* emit_tuple_data — module-level `let g: (T0, T1, ...) = (v0, v1, ...);`
|
||||||
|
* static init (C-t3, #48). One slot-laid DATAW row (+ DATAR str-element
|
||||||
|
* ptr patches) via the backing-relative emit_tuple_row helpers; rhs ==
|
||||||
|
* NULL zero-inits. Unsupported element inits return 0 and the caller
|
||||||
|
* loud-stops (rule 7 — pre-C-t3 the whole definition was SILENTLY skipped
|
||||||
|
* and reads saw BP-frame garbage). */
|
||||||
|
static int
|
||||||
|
emit_tuple_data(FILE *out, Cg *c, const char *name, const char *module,
|
||||||
|
Type *t, Node *rhs)
|
||||||
|
{
|
||||||
|
Type *u = type_unwrap(t);
|
||||||
|
if (u == NULL || u->kind != TY_TUPLE) return 0;
|
||||||
|
const char *sym = mod_mangle_value(c, name, module);
|
||||||
|
if (rhs == NULL) {
|
||||||
|
fprintf(out, "DATAW %s(SB),\"", sym);
|
||||||
|
for (int i = 0; i < (int)u->size; i++)
|
||||||
|
emit_data_byte(out, 0);
|
||||||
|
fputs("\"\n", out);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (rhs->kind != N_TUPLE) return 0;
|
||||||
|
if (!tuple_row_foldable(c, u, rhs)) return 0;
|
||||||
|
fprintf(out, "DATAW %s(SB),\"", sym);
|
||||||
|
emit_tuple_row_bytes(c, out, u, rhs);
|
||||||
|
fputs("\"\n", out);
|
||||||
|
emit_tuple_row_relocs(c, out, sym, 0, u, rhs);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39850,38 +39850,17 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// emittupledata — module-level `let g: (T0, T1, ...) = (v0, ...);`
|
// tuplerowfoldable — validate every cast-peeled element of `rhs` (an
|
||||||
// static init (C-t3, #48). Slot layout (C-t0): a scalar element is one
|
// N_TUPLE) reduces to a static row: an int literal (foldintliteral) or a
|
||||||
// 8B LE word, a str element its 24B header slot (8 zero ptr placeholder
|
// str literal in a str/slice slot. A tagged element slot has no
|
||||||
// + LE len + 8 zero cap) with a DATAR patching the ptr word at the
|
// static-init shape (tag word + payload widening) — reject so the caller
|
||||||
// element's slot offset — the per-element twin of the scalar-str-global
|
// loud-stops (#22a, rule 7); pre-guard an int init would have emitted one
|
||||||
// arm, offset like emitstrarraydata's rows. Elements must reduce to int
|
// 8B word into the 16B+ box (silent layout skew). The validate twin of
|
||||||
// (foldintliteral) or str literals; anything else returns false and the
|
// emittuplerowbytes / emittuplerowrelocs; two-pass keeps a partial row
|
||||||
// caller loud-stops (rule 7 — pre-C-t3 the whole definition was
|
// out of the output (emitarraydata precedent). Factored from emittupledata
|
||||||
// SILENTLY skipped and reads saw garbage). rhs == nil zero-inits the
|
// so the slice-of-tuple backing (#117) shares it. Mirror of cstage
|
||||||
// slot. Mirror of cstage emit_tuple_data.
|
// tuple_row_foldable.
|
||||||
fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool = {
|
fn tuplerowfoldable(c: *cgen, tt: *node, rhs: *node) bool = {
|
||||||
if (tt == nil) { return false; };
|
|
||||||
if (rhs == nil) {
|
|
||||||
// #22: slot-sum via the accessor so the zero-fill matches
|
|
||||||
// the checker size (cstage zero-emits u->size).
|
|
||||||
let zsz: i32 = 0;
|
|
||||||
let p0: *node = tt.list;
|
|
||||||
for (p0 != nil) {
|
|
||||||
zsz += tupeslotn(p0.lhs);
|
|
||||||
p0 = p0.next;
|
|
||||||
};
|
|
||||||
emitline("DATAW ");
|
|
||||||
emitsymnamehint(c, name, module);
|
|
||||||
emitline("(SB),\"");
|
|
||||||
let zi: i32 = 0;
|
|
||||||
for (zi < zsz) { emitdatawbyte(0u8); zi += 1; };
|
|
||||||
emitline("\"\n");
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
if (rhs.kind != nkind.N_TUPLE) { return false; };
|
|
||||||
// Validate first (two-pass, emitarraydata precedent) so a partial
|
|
||||||
// row never reaches the output.
|
|
||||||
let tp: *node = tt.list;
|
let tp: *node = tt.list;
|
||||||
let e: *node = rhs.list;
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
@@ -39890,11 +39869,6 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
let ev: *node = e;
|
let ev: *node = e;
|
||||||
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
||||||
if (ev == nil) { return false; };
|
if (ev == nil) { return false; };
|
||||||
// #22a (rule 7): a tagged element slot has no static-init
|
|
||||||
// shape (tag word + payload widening) — reject so the caller
|
|
||||||
// loud-stops; pre-guard an int init would have emitted one
|
|
||||||
// 8B word into the 16B+ box (silent layout skew). Mirrors
|
|
||||||
// cstage emit_tuple_data.
|
|
||||||
{
|
{
|
||||||
let eti: *tinfo = nil;
|
let eti: *tinfo = nil;
|
||||||
if (et != nil) { eti = et.type_: *tinfo; };
|
if (et != nil) { eti = et.type_: *tinfo; };
|
||||||
@@ -39913,11 +39887,18 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
emitline("DATAW ");
|
return true;
|
||||||
emitsymnamehint(c, name, module);
|
};
|
||||||
emitline("(SB),\"");
|
|
||||||
tp = tt.list;
|
// emittuplerowbytes — the row's element bytes, concatenated, into the
|
||||||
e = rhs.list;
|
// currently-open DATAW quoted string (no DATAW wrapper, no sym). Slot
|
||||||
|
// layout (C-t0): a scalar element is one 8B LE word; a str/slice element
|
||||||
|
// its 24B header slot (8 zero ptr placeholder + LE len + 8 zero cap).
|
||||||
|
// Caller has already proven the row foldable. Mirror of cstage
|
||||||
|
// emit_tuple_row_bytes.
|
||||||
|
fn emittuplerowbytes(c: *cgen, tt: *node, rhs: *node) void = {
|
||||||
|
let tp: *node = tt.list;
|
||||||
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
let et: *node = nil;
|
let et: *node = nil;
|
||||||
if (tp != nil) { et = tp.lhs; };
|
if (tp != nil) { et = tp.lhs; };
|
||||||
@@ -39951,10 +39932,19 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
emitline("\"\n");
|
};
|
||||||
let foff: i32 = 0;
|
|
||||||
tp = tt.list;
|
// emittuplerowrelocs — the row's DATAR ptr patches, at backing-relative
|
||||||
e = rhs.list;
|
// <holder>+<rowoff>+<slot>. A str element patches the ptr word with the
|
||||||
|
// interned strlit's VA; the slot stride steps by tyslicesize/tupeslotn.
|
||||||
|
// `backing` writes the "<sym>.d" backing label; rowoff lets a slice
|
||||||
|
// backing place k rows contiguously (#117), emittupledata passes 0 (foff
|
||||||
|
// matches the absolute element offset — byte-neutral). Mirror of cstage
|
||||||
|
// emit_tuple_row_relocs.
|
||||||
|
fn emittuplerowrelocs(c: *cgen, name: str, module: str, backing: bool, rowoff: i32, tt: *node, rhs: *node) void = {
|
||||||
|
let foff: i32 = rowoff;
|
||||||
|
let tp: *node = tt.list;
|
||||||
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
let et: *node = nil;
|
let et: *node = nil;
|
||||||
if (tp != nil) { et = tp.lhs; };
|
if (tp != nil) { et = tp.lhs; };
|
||||||
@@ -39966,6 +39956,7 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
let lab: str = internstrlit(c, ev.str);
|
let lab: str = internstrlit(c, ev.str);
|
||||||
emitline("DATAR ");
|
emitline("DATAR ");
|
||||||
emitsymnamehint(c, name, module);
|
emitsymnamehint(c, name, module);
|
||||||
|
if (backing) { emitline(".d"); };
|
||||||
emitline("+");
|
emitline("+");
|
||||||
emitint(foff: i64);
|
emitint(foff: i64);
|
||||||
emitline("(SB),");
|
emitline("(SB),");
|
||||||
@@ -39982,6 +39973,41 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// emittupledata — module-level `let g: (T0, T1, ...) = (v0, ...);`
|
||||||
|
// static init (C-t3, #48). One slot-laid DATAW row (+ DATAR str-element
|
||||||
|
// ptr patches) via the backing-relative emittuplerow helpers; rhs == nil
|
||||||
|
// zero-inits. Unsupported element inits return false and the caller
|
||||||
|
// loud-stops (rule 7 — pre-C-t3 the whole definition was SILENTLY skipped
|
||||||
|
// and reads saw garbage). Mirror of cstage emit_tuple_data.
|
||||||
|
fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool = {
|
||||||
|
if (tt == nil) { return false; };
|
||||||
|
if (rhs == nil) {
|
||||||
|
// #22: slot-sum via the accessor so the zero-fill matches
|
||||||
|
// the checker size (cstage zero-emits u->size).
|
||||||
|
let zsz: i32 = 0;
|
||||||
|
let p0: *node = tt.list;
|
||||||
|
for (p0 != nil) {
|
||||||
|
zsz += tupeslotn(p0.lhs);
|
||||||
|
p0 = p0.next;
|
||||||
|
};
|
||||||
|
emitline("DATAW ");
|
||||||
|
emitsymnamehint(c, name, module);
|
||||||
|
emitline("(SB),\"");
|
||||||
|
let zi: i32 = 0;
|
||||||
|
for (zi < zsz) { emitdatawbyte(0u8); zi += 1; };
|
||||||
|
emitline("\"\n");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (rhs.kind != nkind.N_TUPLE) { return false; };
|
||||||
|
if (!tuplerowfoldable(c, tt, rhs)) { return false; };
|
||||||
|
emitline("DATAW ");
|
||||||
|
emitsymnamehint(c, name, module);
|
||||||
|
emitline("(SB),\"");
|
||||||
|
emittuplerowbytes(c, tt, rhs);
|
||||||
|
emitline("\"\n");
|
||||||
|
emittuplerowrelocs(c, name, module, false, 0, tt, rhs);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2296,38 +2296,17 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// emittupledata — module-level `let g: (T0, T1, ...) = (v0, ...);`
|
// tuplerowfoldable — validate every cast-peeled element of `rhs` (an
|
||||||
// static init (C-t3, #48). Slot layout (C-t0): a scalar element is one
|
// N_TUPLE) reduces to a static row: an int literal (foldintliteral) or a
|
||||||
// 8B LE word, a str element its 24B header slot (8 zero ptr placeholder
|
// str literal in a str/slice slot. A tagged element slot has no
|
||||||
// + LE len + 8 zero cap) with a DATAR patching the ptr word at the
|
// static-init shape (tag word + payload widening) — reject so the caller
|
||||||
// element's slot offset — the per-element twin of the scalar-str-global
|
// loud-stops (#22a, rule 7); pre-guard an int init would have emitted one
|
||||||
// arm, offset like emitstrarraydata's rows. Elements must reduce to int
|
// 8B word into the 16B+ box (silent layout skew). The validate twin of
|
||||||
// (foldintliteral) or str literals; anything else returns false and the
|
// emittuplerowbytes / emittuplerowrelocs; two-pass keeps a partial row
|
||||||
// caller loud-stops (rule 7 — pre-C-t3 the whole definition was
|
// out of the output (emitarraydata precedent). Factored from emittupledata
|
||||||
// SILENTLY skipped and reads saw garbage). rhs == nil zero-inits the
|
// so the slice-of-tuple backing (#117) shares it. Mirror of cstage
|
||||||
// slot. Mirror of cstage emit_tuple_data.
|
// tuple_row_foldable.
|
||||||
fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool = {
|
fn tuplerowfoldable(c: *cgen, tt: *node, rhs: *node) bool = {
|
||||||
if (tt == nil) { return false; };
|
|
||||||
if (rhs == nil) {
|
|
||||||
// #22: slot-sum via the accessor so the zero-fill matches
|
|
||||||
// the checker size (cstage zero-emits u->size).
|
|
||||||
let zsz: i32 = 0;
|
|
||||||
let p0: *node = tt.list;
|
|
||||||
for (p0 != nil) {
|
|
||||||
zsz += tupeslotn(p0.lhs);
|
|
||||||
p0 = p0.next;
|
|
||||||
};
|
|
||||||
emitline("DATAW ");
|
|
||||||
emitsymnamehint(c, name, module);
|
|
||||||
emitline("(SB),\"");
|
|
||||||
let zi: i32 = 0;
|
|
||||||
for (zi < zsz) { emitdatawbyte(0u8); zi += 1; };
|
|
||||||
emitline("\"\n");
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
if (rhs.kind != nkind.N_TUPLE) { return false; };
|
|
||||||
// Validate first (two-pass, emitarraydata precedent) so a partial
|
|
||||||
// row never reaches the output.
|
|
||||||
let tp: *node = tt.list;
|
let tp: *node = tt.list;
|
||||||
let e: *node = rhs.list;
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
@@ -2336,11 +2315,6 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
let ev: *node = e;
|
let ev: *node = e;
|
||||||
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
||||||
if (ev == nil) { return false; };
|
if (ev == nil) { return false; };
|
||||||
// #22a (rule 7): a tagged element slot has no static-init
|
|
||||||
// shape (tag word + payload widening) — reject so the caller
|
|
||||||
// loud-stops; pre-guard an int init would have emitted one
|
|
||||||
// 8B word into the 16B+ box (silent layout skew). Mirrors
|
|
||||||
// cstage emit_tuple_data.
|
|
||||||
{
|
{
|
||||||
let eti: *tinfo = nil;
|
let eti: *tinfo = nil;
|
||||||
if (et != nil) { eti = et.type_: *tinfo; };
|
if (et != nil) { eti = et.type_: *tinfo; };
|
||||||
@@ -2359,11 +2333,18 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
emitline("DATAW ");
|
return true;
|
||||||
emitsymnamehint(c, name, module);
|
};
|
||||||
emitline("(SB),\"");
|
|
||||||
tp = tt.list;
|
// emittuplerowbytes — the row's element bytes, concatenated, into the
|
||||||
e = rhs.list;
|
// currently-open DATAW quoted string (no DATAW wrapper, no sym). Slot
|
||||||
|
// layout (C-t0): a scalar element is one 8B LE word; a str/slice element
|
||||||
|
// its 24B header slot (8 zero ptr placeholder + LE len + 8 zero cap).
|
||||||
|
// Caller has already proven the row foldable. Mirror of cstage
|
||||||
|
// emit_tuple_row_bytes.
|
||||||
|
fn emittuplerowbytes(c: *cgen, tt: *node, rhs: *node) void = {
|
||||||
|
let tp: *node = tt.list;
|
||||||
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
let et: *node = nil;
|
let et: *node = nil;
|
||||||
if (tp != nil) { et = tp.lhs; };
|
if (tp != nil) { et = tp.lhs; };
|
||||||
@@ -2397,10 +2378,19 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
emitline("\"\n");
|
};
|
||||||
let foff: i32 = 0;
|
|
||||||
tp = tt.list;
|
// emittuplerowrelocs — the row's DATAR ptr patches, at backing-relative
|
||||||
e = rhs.list;
|
// <holder>+<rowoff>+<slot>. A str element patches the ptr word with the
|
||||||
|
// interned strlit's VA; the slot stride steps by tyslicesize/tupeslotn.
|
||||||
|
// `backing` writes the "<sym>.d" backing label; rowoff lets a slice
|
||||||
|
// backing place k rows contiguously (#117), emittupledata passes 0 (foff
|
||||||
|
// matches the absolute element offset — byte-neutral). Mirror of cstage
|
||||||
|
// emit_tuple_row_relocs.
|
||||||
|
fn emittuplerowrelocs(c: *cgen, name: str, module: str, backing: bool, rowoff: i32, tt: *node, rhs: *node) void = {
|
||||||
|
let foff: i32 = rowoff;
|
||||||
|
let tp: *node = tt.list;
|
||||||
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
let et: *node = nil;
|
let et: *node = nil;
|
||||||
if (tp != nil) { et = tp.lhs; };
|
if (tp != nil) { et = tp.lhs; };
|
||||||
@@ -2412,6 +2402,7 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
let lab: str = internstrlit(c, ev.str);
|
let lab: str = internstrlit(c, ev.str);
|
||||||
emitline("DATAR ");
|
emitline("DATAR ");
|
||||||
emitsymnamehint(c, name, module);
|
emitsymnamehint(c, name, module);
|
||||||
|
if (backing) { emitline(".d"); };
|
||||||
emitline("+");
|
emitline("+");
|
||||||
emitint(foff: i64);
|
emitint(foff: i64);
|
||||||
emitline("(SB),");
|
emitline("(SB),");
|
||||||
@@ -2428,6 +2419,41 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// emittupledata — module-level `let g: (T0, T1, ...) = (v0, ...);`
|
||||||
|
// static init (C-t3, #48). One slot-laid DATAW row (+ DATAR str-element
|
||||||
|
// ptr patches) via the backing-relative emittuplerow helpers; rhs == nil
|
||||||
|
// zero-inits. Unsupported element inits return false and the caller
|
||||||
|
// loud-stops (rule 7 — pre-C-t3 the whole definition was SILENTLY skipped
|
||||||
|
// and reads saw garbage). Mirror of cstage emit_tuple_data.
|
||||||
|
fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool = {
|
||||||
|
if (tt == nil) { return false; };
|
||||||
|
if (rhs == nil) {
|
||||||
|
// #22: slot-sum via the accessor so the zero-fill matches
|
||||||
|
// the checker size (cstage zero-emits u->size).
|
||||||
|
let zsz: i32 = 0;
|
||||||
|
let p0: *node = tt.list;
|
||||||
|
for (p0 != nil) {
|
||||||
|
zsz += tupeslotn(p0.lhs);
|
||||||
|
p0 = p0.next;
|
||||||
|
};
|
||||||
|
emitline("DATAW ");
|
||||||
|
emitsymnamehint(c, name, module);
|
||||||
|
emitline("(SB),\"");
|
||||||
|
let zi: i32 = 0;
|
||||||
|
for (zi < zsz) { emitdatawbyte(0u8); zi += 1; };
|
||||||
|
emitline("\"\n");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (rhs.kind != nkind.N_TUPLE) { return false; };
|
||||||
|
if (!tuplerowfoldable(c, tt, rhs)) { return false; };
|
||||||
|
emitline("DATAW ");
|
||||||
|
emitsymnamehint(c, name, module);
|
||||||
|
emitline("(SB),\"");
|
||||||
|
emittuplerowbytes(c, tt, rhs);
|
||||||
|
emitline("\"\n");
|
||||||
|
emittuplerowrelocs(c, name, module, false, 0, tt, rhs);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39850,38 +39850,17 @@ fn emittaggeddata(c: *cgen, name: str, module: str, tt: *node, rhs: *node, sz: i
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// emittupledata — module-level `let g: (T0, T1, ...) = (v0, ...);`
|
// tuplerowfoldable — validate every cast-peeled element of `rhs` (an
|
||||||
// static init (C-t3, #48). Slot layout (C-t0): a scalar element is one
|
// N_TUPLE) reduces to a static row: an int literal (foldintliteral) or a
|
||||||
// 8B LE word, a str element its 24B header slot (8 zero ptr placeholder
|
// str literal in a str/slice slot. A tagged element slot has no
|
||||||
// + LE len + 8 zero cap) with a DATAR patching the ptr word at the
|
// static-init shape (tag word + payload widening) — reject so the caller
|
||||||
// element's slot offset — the per-element twin of the scalar-str-global
|
// loud-stops (#22a, rule 7); pre-guard an int init would have emitted one
|
||||||
// arm, offset like emitstrarraydata's rows. Elements must reduce to int
|
// 8B word into the 16B+ box (silent layout skew). The validate twin of
|
||||||
// (foldintliteral) or str literals; anything else returns false and the
|
// emittuplerowbytes / emittuplerowrelocs; two-pass keeps a partial row
|
||||||
// caller loud-stops (rule 7 — pre-C-t3 the whole definition was
|
// out of the output (emitarraydata precedent). Factored from emittupledata
|
||||||
// SILENTLY skipped and reads saw garbage). rhs == nil zero-inits the
|
// so the slice-of-tuple backing (#117) shares it. Mirror of cstage
|
||||||
// slot. Mirror of cstage emit_tuple_data.
|
// tuple_row_foldable.
|
||||||
fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool = {
|
fn tuplerowfoldable(c: *cgen, tt: *node, rhs: *node) bool = {
|
||||||
if (tt == nil) { return false; };
|
|
||||||
if (rhs == nil) {
|
|
||||||
// #22: slot-sum via the accessor so the zero-fill matches
|
|
||||||
// the checker size (cstage zero-emits u->size).
|
|
||||||
let zsz: i32 = 0;
|
|
||||||
let p0: *node = tt.list;
|
|
||||||
for (p0 != nil) {
|
|
||||||
zsz += tupeslotn(p0.lhs);
|
|
||||||
p0 = p0.next;
|
|
||||||
};
|
|
||||||
emitline("DATAW ");
|
|
||||||
emitsymnamehint(c, name, module);
|
|
||||||
emitline("(SB),\"");
|
|
||||||
let zi: i32 = 0;
|
|
||||||
for (zi < zsz) { emitdatawbyte(0u8); zi += 1; };
|
|
||||||
emitline("\"\n");
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
if (rhs.kind != nkind.N_TUPLE) { return false; };
|
|
||||||
// Validate first (two-pass, emitarraydata precedent) so a partial
|
|
||||||
// row never reaches the output.
|
|
||||||
let tp: *node = tt.list;
|
let tp: *node = tt.list;
|
||||||
let e: *node = rhs.list;
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
@@ -39890,11 +39869,6 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
let ev: *node = e;
|
let ev: *node = e;
|
||||||
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
for (ev != nil && ev.kind == nkind.N_CAST) { ev = ev.lhs; };
|
||||||
if (ev == nil) { return false; };
|
if (ev == nil) { return false; };
|
||||||
// #22a (rule 7): a tagged element slot has no static-init
|
|
||||||
// shape (tag word + payload widening) — reject so the caller
|
|
||||||
// loud-stops; pre-guard an int init would have emitted one
|
|
||||||
// 8B word into the 16B+ box (silent layout skew). Mirrors
|
|
||||||
// cstage emit_tuple_data.
|
|
||||||
{
|
{
|
||||||
let eti: *tinfo = nil;
|
let eti: *tinfo = nil;
|
||||||
if (et != nil) { eti = et.type_: *tinfo; };
|
if (et != nil) { eti = et.type_: *tinfo; };
|
||||||
@@ -39913,11 +39887,18 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
emitline("DATAW ");
|
return true;
|
||||||
emitsymnamehint(c, name, module);
|
};
|
||||||
emitline("(SB),\"");
|
|
||||||
tp = tt.list;
|
// emittuplerowbytes — the row's element bytes, concatenated, into the
|
||||||
e = rhs.list;
|
// currently-open DATAW quoted string (no DATAW wrapper, no sym). Slot
|
||||||
|
// layout (C-t0): a scalar element is one 8B LE word; a str/slice element
|
||||||
|
// its 24B header slot (8 zero ptr placeholder + LE len + 8 zero cap).
|
||||||
|
// Caller has already proven the row foldable. Mirror of cstage
|
||||||
|
// emit_tuple_row_bytes.
|
||||||
|
fn emittuplerowbytes(c: *cgen, tt: *node, rhs: *node) void = {
|
||||||
|
let tp: *node = tt.list;
|
||||||
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
let et: *node = nil;
|
let et: *node = nil;
|
||||||
if (tp != nil) { et = tp.lhs; };
|
if (tp != nil) { et = tp.lhs; };
|
||||||
@@ -39951,10 +39932,19 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
emitline("\"\n");
|
};
|
||||||
let foff: i32 = 0;
|
|
||||||
tp = tt.list;
|
// emittuplerowrelocs — the row's DATAR ptr patches, at backing-relative
|
||||||
e = rhs.list;
|
// <holder>+<rowoff>+<slot>. A str element patches the ptr word with the
|
||||||
|
// interned strlit's VA; the slot stride steps by tyslicesize/tupeslotn.
|
||||||
|
// `backing` writes the "<sym>.d" backing label; rowoff lets a slice
|
||||||
|
// backing place k rows contiguously (#117), emittupledata passes 0 (foff
|
||||||
|
// matches the absolute element offset — byte-neutral). Mirror of cstage
|
||||||
|
// emit_tuple_row_relocs.
|
||||||
|
fn emittuplerowrelocs(c: *cgen, name: str, module: str, backing: bool, rowoff: i32, tt: *node, rhs: *node) void = {
|
||||||
|
let foff: i32 = rowoff;
|
||||||
|
let tp: *node = tt.list;
|
||||||
|
let e: *node = rhs.list;
|
||||||
for (e != nil) {
|
for (e != nil) {
|
||||||
let et: *node = nil;
|
let et: *node = nil;
|
||||||
if (tp != nil) { et = tp.lhs; };
|
if (tp != nil) { et = tp.lhs; };
|
||||||
@@ -39966,6 +39956,7 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
let lab: str = internstrlit(c, ev.str);
|
let lab: str = internstrlit(c, ev.str);
|
||||||
emitline("DATAR ");
|
emitline("DATAR ");
|
||||||
emitsymnamehint(c, name, module);
|
emitsymnamehint(c, name, module);
|
||||||
|
if (backing) { emitline(".d"); };
|
||||||
emitline("+");
|
emitline("+");
|
||||||
emitint(foff: i64);
|
emitint(foff: i64);
|
||||||
emitline("(SB),");
|
emitline("(SB),");
|
||||||
@@ -39982,6 +39973,41 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool =
|
|||||||
e = e.next;
|
e = e.next;
|
||||||
if (tp != nil) { tp = tp.next; };
|
if (tp != nil) { tp = tp.next; };
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// emittupledata — module-level `let g: (T0, T1, ...) = (v0, ...);`
|
||||||
|
// static init (C-t3, #48). One slot-laid DATAW row (+ DATAR str-element
|
||||||
|
// ptr patches) via the backing-relative emittuplerow helpers; rhs == nil
|
||||||
|
// zero-inits. Unsupported element inits return false and the caller
|
||||||
|
// loud-stops (rule 7 — pre-C-t3 the whole definition was SILENTLY skipped
|
||||||
|
// and reads saw garbage). Mirror of cstage emit_tuple_data.
|
||||||
|
fn emittupledata(c: *cgen, name: str, module: str, tt: *node, rhs: *node) bool = {
|
||||||
|
if (tt == nil) { return false; };
|
||||||
|
if (rhs == nil) {
|
||||||
|
// #22: slot-sum via the accessor so the zero-fill matches
|
||||||
|
// the checker size (cstage zero-emits u->size).
|
||||||
|
let zsz: i32 = 0;
|
||||||
|
let p0: *node = tt.list;
|
||||||
|
for (p0 != nil) {
|
||||||
|
zsz += tupeslotn(p0.lhs);
|
||||||
|
p0 = p0.next;
|
||||||
|
};
|
||||||
|
emitline("DATAW ");
|
||||||
|
emitsymnamehint(c, name, module);
|
||||||
|
emitline("(SB),\"");
|
||||||
|
let zi: i32 = 0;
|
||||||
|
for (zi < zsz) { emitdatawbyte(0u8); zi += 1; };
|
||||||
|
emitline("\"\n");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (rhs.kind != nkind.N_TUPLE) { return false; };
|
||||||
|
if (!tuplerowfoldable(c, tt, rhs)) { return false; };
|
||||||
|
emitline("DATAW ");
|
||||||
|
emitsymnamehint(c, name, module);
|
||||||
|
emitline("(SB),\"");
|
||||||
|
emittuplerowbytes(c, tt, rhs);
|
||||||
|
emitline("\"\n");
|
||||||
|
emittuplerowrelocs(c, name, module, false, 0, tt, rhs);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user