wcc/cgen: #117 prep — factor emit_tuple_row backing-relative (byte-neutral)

This commit is contained in:
2026-06-06 20:02:32 +09:00
parent f8be2ae8dd
commit df1928182e
4 changed files with 282 additions and 175 deletions

View File

@@ -15010,44 +15010,24 @@ emit_tagged_data(FILE *out, Cg *c, const char *name, const char *module,
return 1;
}
/* emit_tuple_data — module-level `let g: (T0, T1, ...) = (v0, v1, ...);`
* static init (C-t3, #48). Slot layout (C-t0): a scalar element is one
* 8B LE word, a str element its 24B header slot (8 zero ptr placeholder
* + LE len + 8 zero cap) with a DATAR patching the ptr word at the
* element's slot offset — the per-element twin of the scalar-str-global
* arm, offset like emit_strarray_data's rows. Elements must reduce to
* int (fold_int_literal) or str literals; anything else returns 0 and
* the caller loud-stops (rule 7 — pre-C-t3 the whole definition was
* SILENTLY skipped and reads saw BP-frame garbage). rhs == NULL
* zero-inits the slot. */
/* tuple_row_foldable — validate that every cast-peeled element of `rhs`
* (an N_TUPLE) reduces to a static row: an int literal (fold_int_literal)
* or a str literal in a str/slice slot. A tagged element slot has no
* static-init shape (tag word + payload widening) — reject so the caller
* loud-stops (#22a, rule 7); pre-guard an int init would have emitted one
* 8B word into the 16B+ box (silent layout skew). The validate twin of
* emit_tuple_row_bytes / emit_tuple_row_relocs: two-pass keeps a partial
* row out of the output (emit_array_data precedent). Factored from
* emit_tuple_data so the slice-of-tuple backing (#117) shares it. */
static int
emit_tuple_data(FILE *out, Cg *c, const char *name, const char *module,
Type *t, Node *rhs)
tuple_row_foldable(Cg *c, Type *u, 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;
/* 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). */
(void)c;
Tparam *tp = u->params;
for (Node *e = rhs->list; e; e = e->next, tp = tp ? tp->next : NULL) {
Node *ev = e;
while (ev && ev->kind == N_CAST) ev = ev->lhs;
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);
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;
if (!fold_int_literal(ev, &v)) return 0;
}
fprintf(out, "DATAW %s(SB),\"", sym);
tp = u->params;
return 1;
}
/* 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) {
Node *ev = e;
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++)
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) {
Node *ev = e;
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,
ev->strlen);
fprintf(out, "DATAR %s+%d(SB),%s(SB)\n",
sym, foff, lab);
holder, foff, lab);
}
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;
}