w6c+w6c_ww: emit module-level slice-literal static-init (header+backing+reloc) (fix #10 part a)
`let g: []T = [v0, v1, …];` at module scope had no cgen arm: emit_lets /
emitletdataw handled str-lit and array-lit but not slice-lit, so NO
`DATAW main.g` was emitted and BOTH stages failed to link ("undefined
reference to main.g"). byte-id-blind — only the link step exposed it.
emit_slice_data / emitslicedata (parallel to the #18 str-array reloc
helper, generalized to a 24B header + array-backed data):
1. writable backing DATAW "<mangled g>.d" holding the k element bytes,
routed through the emit_array_lit_bytes / emitarraylitbytes choke-
point via a synthesized [k]T (int/float element kinds reduce exactly
as a [N]T global's do);
2. 24B header { ptr-placeholder, LE len, LE cap } (len = cap = k), word
sizes from the type table (ty_uintptr/ty_size, primtypesize) per
rule-13;
3. DATAR g+0 -> backing patches the ptr word.
The backing label's second '.' can't collide with a user global (source
identifiers carry no '.').
New emit_lets / slice arm gated on N_ARRLIT + slice-typed; rides on #18,
which keeps the module-level initializer as N_ARRLIT in both stages.
Aliased-slice spelling (`type S = []T; let g: S = [...]`): cstage
let_isslice already resolves the alias via type_unwrap, but wwstage
letvarisslice keyed only on the syntactic N_TSLICE node — unlike its
siblings letvarisstr/letvarisstruct/letvarisfloat, which all walk the
N_TNAME alias chain. So an aliased-slice global misrouted to the str arm
and never reached emitslicedata, link-failing on wwstage while cstage
emitted correctly (a cs≠ww divergence this fix would otherwise introduce).
letvarisslice now walks the alias chain exactly as letvarisstr does
(align wwstage UP to runtime-correct cstage, the #211 pattern); an alias
of a slice IS a slice. emitslicedata gains the nil/non-slice guard cstage
emit_slice_data already had (rule-10 symmetry; unreachable behind the
gate, guards the su.sub deref).
rule-7 loud-stops, symmetric both stages: read-only `def` slice-literal
(DATAR holder must be DATAW, w6a asm.c:362), `...` repeat (a slice
literal has no target length), and slice-of-{str,slice,tagged} elements
(per-element relocs / #17) — never silent no-emit.
Deferred (filed): struct-element module-level slice-literal surfaces a
separate checker cs!=ww ("let: not assignable" on wwstage, wrong runtime
on cstage) — out of #10's data-emission scope.
Test 687 (table-driven): []u8/[]i64/[]i32 element read-back + len + cap +
1-element edge + aliased-slice-type, dual-stage runtime + asm byte-id,
plus 3 build-fail rows for the loud-stops. selfhost combined.ww
regenerated.
This commit is contained in:
@@ -11647,6 +11647,80 @@ emit_array_data(FILE *out, Cg *c, const char *directive,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* emit_slice_data — module-level `let g: []T = [v0, v1, …];` static
|
||||
* init (#10 part a). A slice literal needs three things: a writable
|
||||
* backing holding the k elements, a 24B header { ptr, len, cap }, and a
|
||||
* DATAR patching the ptr word with the backing's VA. The backing rides
|
||||
* the emit_array_lit_bytes choke-point via a synthesized [k]T so int /
|
||||
* float / struct / nested-array elements reduce exactly as a [N]T
|
||||
* global's do. The backing symbol is "<mangled g>.d": a second '.' can
|
||||
* never collide with a user global, since source identifiers carry no
|
||||
* '.' (one is inserted only by the module mangle).
|
||||
*
|
||||
* Scoped to a writable `let` — A_DATAR's holder must be a DATAW slot
|
||||
* (w6a asm.c:362), so a read-only `def []T = [...]` can't carry the ptr
|
||||
* reloc. That, a `...` repeat (a slice literal has no target length),
|
||||
* and slice-of-{str,slice,tagged} elements (per-element relocs / #17)
|
||||
* all loud-stop (rule 7) — #10 follow-ups, never silent fall-through.
|
||||
* Returns 0 only on the early shape guards (not a slice / rhs not
|
||||
* N_ARRLIT) so the caller's gate stays the sole entry contract. */
|
||||
static int
|
||||
emit_slice_data(FILE *out, Cg *c, const char *directive, const char *name,
|
||||
const char *module, Type *t, Node *rhs)
|
||||
{
|
||||
Type *u = type_unwrap(t);
|
||||
if (u == NULL || u->kind != TY_SLICE) return 0;
|
||||
if (rhs == NULL || rhs->kind != N_ARRLIT) return 0;
|
||||
if (strcmp(directive, "DATAW") != 0)
|
||||
fatal("emit_slice_data: slice-literal static-init needs a "
|
||||
"writable `let` (DATAR holder must be DATAW, w6a "
|
||||
"asm.c:362); read-only `def` unsupported (#10, rule 7)");
|
||||
Type *etype = u->sub;
|
||||
Type *eu = (etype && etype->kind == TY_NAMED) ? etype->under : etype;
|
||||
if (eu && (eu->kind == TY_STR || eu->kind == TY_SLICE
|
||||
|| eu->kind == TY_TAGGED))
|
||||
fatal("emit_slice_data: slice-of-{str,slice,tagged} literal "
|
||||
"static-init unsupported (#10 follow-up, rule 7)");
|
||||
int k = 0;
|
||||
for (Node *e = rhs->list; e; e = e->next) {
|
||||
if (e->kind == N_FIELD && e->str && strcmp(e->str, "...") == 0)
|
||||
fatal("emit_slice_data: '...' repeat has no target "
|
||||
"length in a slice literal (#10, rule 7)");
|
||||
k++;
|
||||
}
|
||||
int esz = etype ? (int)etype->size : 1;
|
||||
/* Synthesize [k]T to ride the emit_array_lit_bytes choke-point. */
|
||||
Type arr;
|
||||
memset(&arr, 0, sizeof arr);
|
||||
arr.kind = TY_ARRAY;
|
||||
arr.sub = etype;
|
||||
arr.alen = (u64)k;
|
||||
arr.size = (u64)k * (u64)esz;
|
||||
if (!emit_array_lit_bytes(out, c, &arr, rhs, 0))
|
||||
fatal("emit_slice_data: slice-literal element not a foldable "
|
||||
"constant (#10, rule 7)");
|
||||
|
||||
const char *sym = mod_mangle_value(c, name, module);
|
||||
const char *bk = aprintf(c->a, "%s.d", sym);
|
||||
/* Writable backing data. */
|
||||
fprintf(out, "DATAW %s(SB),\"", bk);
|
||||
emit_array_lit_bytes(out, c, &arr, rhs, 1);
|
||||
fputs("\"\n", out);
|
||||
/* 24B header: ptr placeholder + LE len + LE cap (both = k). Word
|
||||
* sizes from the type table (rule 13). */
|
||||
fprintf(out, "DATAW %s(SB),\"", sym);
|
||||
for (int i = 0; i < (int)ty_uintptr->size; i++) emit_data_byte(out, 0);
|
||||
u64 kv = (u64)k;
|
||||
for (int i = 0; i < (int)ty_size->size; i++)
|
||||
emit_data_byte(out, (u8)((kv >> (i * 8)) & 0xff));
|
||||
for (int i = 0; i < (int)ty_size->size; i++)
|
||||
emit_data_byte(out, (u8)((kv >> (i * 8)) & 0xff));
|
||||
fputs("\"\n", out);
|
||||
/* Patch the ptr word with the backing VA. */
|
||||
fprintf(out, "DATAR %s+0(SB),%s(SB)\n", sym, bk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_lets(Cg *c, FILE *out, Node *file)
|
||||
{
|
||||
@@ -11725,6 +11799,17 @@ emit_lets(Cg *c, FILE *out, Node *file)
|
||||
continue;
|
||||
/* fall through to zero-init */
|
||||
}
|
||||
/* #10: slice-literal static init `let g: []T = [v0, …];`.
|
||||
* Header { ptr, len, cap } + a writable backing + a DATAR
|
||||
* patching ptr → backing. emit_slice_data loud-stops on the
|
||||
* deferred element kinds and on the read-only / `...` shapes
|
||||
* (rule 7); when the gate matches it always emits or fatals,
|
||||
* never silently falls through. */
|
||||
if (r != NULL && r->kind == N_ARRLIT && let_isslice(d->type)) {
|
||||
if (emit_slice_data(out, c, "DATAW", d->str,
|
||||
d->module, d->type, r))
|
||||
continue;
|
||||
}
|
||||
/* Otherwise: zero-init. str accepts nil / ""; struct
|
||||
* accepts no rhs at all; slice accepts nil; array with no
|
||||
* literal init (or a non-constant one) zero-fills. */
|
||||
@@ -11809,6 +11894,15 @@ emit_defs(Cg *c, FILE *out, Node *file)
|
||||
d->str, d->module, d->type, d->rhs);
|
||||
continue;
|
||||
}
|
||||
/* #10: a read-only `def g: []T = [...]` slice literal can't
|
||||
* carry the ptr reloc emit_slice_data needs (DATAR holder must
|
||||
* be DATAW, w6a asm.c:362). Loud-stop rather than silently
|
||||
* emit nothing and surface an undefined-ref at link. */
|
||||
if (let_isslice(d->type) && d->rhs->kind == N_ARRLIT)
|
||||
fatal("emit_defs: module-level slice-literal init needs "
|
||||
"a writable `let` (DATAR holder must be DATAW, w6a "
|
||||
"asm.c:362); read-only `def` unsupported (#10, "
|
||||
"rule 7)");
|
||||
}
|
||||
(void)c;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user