w6c+selfhost: slice globals — 24B DATAW + (AX,BX,CX) load
Extend top-level mutable `let` to cover slices. Same shape as the
str work, with one more 8-byte field and the address holder CX
overwritten by the cap as the last load step:
- emit_lets / emitletdataw: 24-byte zero DATAW for `let v: []u8;`
(and the trivial `nil` init); no slice-literal syntax exists
so the no-init path is the only supported shape;
- cgident: LEAQ name(SB), CX → MOVQ (CX), AX → MOVQ 8(CX), BX →
MOVQ 16(CX), CX, so the slice ABI triple lands in (AX, BX, CX);
- cgdot: .cap delta 16 wired alongside .ptr / .len through the
same &name(SB) base.
Slice reassignment (`v = some_slice;`) is still unsupported — slice
values don't yet flow as a full (AX, BX, CX) triple through general
expressions even for locals — so reads/`&` are the supported surface
today. Manual fill through `(&v): *u64` continues to work.
Tests 630 (10/10), 990, 994, 995 stay green; bootstrap fixed point
holds.
This commit is contained in:
@@ -398,9 +398,9 @@ struct LetVar {
|
||||
static LetVar *letvars;
|
||||
|
||||
/* Slot size for a top-level `let` of type t, or 0 if the type isn't
|
||||
* supported as a writable global yet. Floats (MOVSS/SD) and slice/
|
||||
* struct/tagged unions are deferred. enums route through their
|
||||
* storage type. Keep this tight — extending it requires the matching
|
||||
* supported as a writable global yet. Floats (MOVSS/SD) and struct/
|
||||
* tagged unions are deferred. enums route through their storage
|
||||
* type. Keep this tight — extending it requires the matching
|
||||
* load/store code below. */
|
||||
static int
|
||||
let_emit_size(Type *t)
|
||||
@@ -417,6 +417,8 @@ let_emit_size(Type *t)
|
||||
return 8;
|
||||
case TY_STR:
|
||||
return 16; /* {ptr, len}; literal-strlit init NYI. */
|
||||
case TY_SLICE:
|
||||
return 24; /* {ptr, len, cap}; no init only. */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -433,6 +435,16 @@ let_isstr(Type *t)
|
||||
return u && u->kind == TY_STR;
|
||||
}
|
||||
|
||||
/* Is the unwrapped type a slice? Slice globals flow as the (AX, BX,
|
||||
* CX) triple — same as the local ABI. */
|
||||
static int
|
||||
let_isslice(Type *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
Type *u = (t->kind == TY_NAMED) ? t->under : t;
|
||||
return u && u->kind == TY_SLICE;
|
||||
}
|
||||
|
||||
static int
|
||||
decl_has_ffisym(Node *d)
|
||||
{
|
||||
@@ -764,13 +776,20 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
areg(D_BX));
|
||||
goto ident_done;
|
||||
}
|
||||
if (let_islet(n->str) && let_isstr(n->type)) {
|
||||
/* Top-level str global: load both halves via
|
||||
* its address (the asm has no `name+8(SB)`
|
||||
* operand form). */
|
||||
if (let_islet(n->str)
|
||||
&& (let_isstr(n->type) || let_isslice(n->type))) {
|
||||
/* Top-level str/slice global: load each half
|
||||
* via its address (the asm has no `name+8(SB)`
|
||||
* operand form). Slice has a third 8B (cap)
|
||||
* — the address holder CX gets overwritten by
|
||||
* the cap as the last step, after we no longer
|
||||
* need it. */
|
||||
int is_slice = let_isslice(n->type);
|
||||
ins2(c, A_LEAQ, masym(c, n->str), areg(D_CX));
|
||||
ins2(c, A_MOVQ, amem(D_CX, 0), areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_CX, 8), areg(D_BX));
|
||||
if (is_slice)
|
||||
ins2(c, A_MOVQ, amem(D_CX, 16), areg(D_CX));
|
||||
goto ident_done;
|
||||
}
|
||||
ins2(c, A_MOVQ, masym(c, n->str), areg(D_AX));
|
||||
@@ -3662,7 +3681,10 @@ emit_data_row_zero(FILE *out, const char *dir, const char *name, int sz)
|
||||
* str lets (16B): emit 16 zero bytes when there is no init (or
|
||||
* the init is `nil` / `""`). A non-empty strlit init would need a
|
||||
* compile-time .data → .text relocation (asm doesn't support that
|
||||
* yet); we silently skip and let the link fail loudly. */
|
||||
* yet); we silently skip and let the link fail loudly.
|
||||
*
|
||||
* Slice lets (24B): no-init only — the slot is zero. There's no
|
||||
* literal slice syntax to honour, so this is the natural shape. */
|
||||
static void
|
||||
emit_lets(Cg *c, FILE *out, Node *file)
|
||||
{
|
||||
@@ -3687,10 +3709,11 @@ emit_lets(Cg *c, FILE *out, Node *file)
|
||||
emit_data_row(out, "DATAW", mod_mangle(c, d->str), v);
|
||||
continue;
|
||||
}
|
||||
/* Multi-word (str, 16B). Only zero-init shapes are
|
||||
* supported: no rhs, or `nil`, or `""` (which interns to
|
||||
* a strlit but we still emit a zero header — the program
|
||||
* has to assign a real strlit at runtime to use it). */
|
||||
/* Multi-word (str=16, slice=24). Only zero-init shapes
|
||||
* are supported: no rhs, or `nil`, or `""` (which interns
|
||||
* to a strlit but we still emit a zero header — the
|
||||
* program has to assign a real strlit/slice at runtime
|
||||
* to use it). */
|
||||
if (d->rhs != NULL) {
|
||||
Node *r = d->rhs;
|
||||
while (r != NULL && r->kind == N_CAST) r = r->lhs;
|
||||
|
||||
Reference in New Issue
Block a user