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:
@@ -113,6 +113,31 @@ static const struct fixture fixtures[] = {
|
||||
"};\n",
|
||||
7,
|
||||
},
|
||||
{
|
||||
"slice-zeroinit",
|
||||
/* Slice globals start as {nil, 0, 0}. .len and .cap both
|
||||
* read zero; .ptr is nil but we don't dereference it. */
|
||||
"let buf: []u8;\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\treturn (buf.len + buf.cap): i32;\n"
|
||||
"};\n",
|
||||
0,
|
||||
},
|
||||
{
|
||||
"slice-cap-via-raw-pointer",
|
||||
/* Drive the slice header through a raw u64 pointer cast
|
||||
* — the language has no slice-reassignment expression
|
||||
* yet, so this is the only way to fill the header from
|
||||
* ww source today. .cap reads back as the value we
|
||||
* wrote. */
|
||||
"let buf: []u8;\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\tlet p: *u64 = (&buf): *u64;\n"
|
||||
"\tp[2] = 99u64;\n"
|
||||
"\treturn buf.cap: i32;\n"
|
||||
"};\n",
|
||||
99,
|
||||
},
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user