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:
@@ -586,11 +586,13 @@ fn letscalarprim(nm: str) bool = {
|
||||
// aliases so byte output matches C cgen, which resolves Type kinds.
|
||||
// 8 → scalar (literal init supported)
|
||||
// 16 → str (only zero-init / nil / "" supported)
|
||||
// 24 → slice (only zero-init supported)
|
||||
fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
if (d == nil) { return 0; };
|
||||
let t: *node = d.lhs;
|
||||
for (t != nil) {
|
||||
if (t.kind == nkind.N_TPTR) { return 8; };
|
||||
if (t.kind == nkind.N_TSLICE) { return 24; };
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
let nm: str = t.str;
|
||||
if (letscalarprim(nm)) { return 8; };
|
||||
@@ -656,6 +658,24 @@ fn letvarisstr(c: *cgen, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letvarisslice — is the named top-level let a slice global?
|
||||
// Slice headers are 24 bytes; the ABI flows as (AX, BX, CX) so the
|
||||
// load sequence ends with `MOVQ 16(CX), CX` (overwrites the
|
||||
// address holder with the cap). Mirrors C cgen's `let_isslice`.
|
||||
fn letvarisslice(c: *cgen, name: str) bool = {
|
||||
let lv: *letvar = c.lets;
|
||||
for (lv != nil) {
|
||||
if (streq(lv.name, name)) {
|
||||
let t: *node = lv.tnode;
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind == nkind.N_TSLICE) { return true; };
|
||||
return false;
|
||||
};
|
||||
lv = lv.lvnext;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// emitdatawbyte — write one byte of an asm string literal using
|
||||
// the same escape rules as emitdefconstants / emitdatasection.
|
||||
fn emitdatawbyte(b: u8) void = {
|
||||
@@ -765,6 +785,35 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == 24) {
|
||||
// Slice: zero-init only (no slice-literal
|
||||
// syntax to honour). Any rhs other than
|
||||
// `nil` is skipped → undefined symbol at
|
||||
// link.
|
||||
let ok: bool = true;
|
||||
if (d.rhs != nil) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
r = r.lhs;
|
||||
};
|
||||
ok = false;
|
||||
if (r != nil) {
|
||||
if (r.kind == nkind.N_NIL) { ok = true; };
|
||||
};
|
||||
};
|
||||
if (ok) {
|
||||
emitline("DATAW ");
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB),\"");
|
||||
let i: i32 = 0;
|
||||
for (i < 24) {
|
||||
emitdatawbyte(0u8);
|
||||
i += 1;
|
||||
};
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
d = d.next;
|
||||
|
||||
Reference in New Issue
Block a user