w6c+selfhost: struct globals — zero-init DATAW + LEAQ-based field access
Extend top-level mutable `let` to cover structs. Same approach as
str / slice: take the field-access base through &name(SB) instead
of off(BP).
- emit_lets / emitletdataw: emit `sizeof(T)` zero bytes for any
struct global without a baked-in initialiser. Struct-literal
init is skipped → undefined symbol at link if used;
- cgdot read path: when the IDENT base's local lookup misses and
the name is a struct let, LEAQ name(SB), CX and load the field
at fi.foff(CX) with the width-aware op (MOVQ / MOVL /
MOVZBQ / MOVSXD; MOVQ pair for str fields);
- cgassign write path: parallel handling for plain `=` (incl. str
fields) and the compound ops (+=, -=) via load → push → eval
rhs → combine → store with a re-LEAQ between cgexpr clobbers.
Tagged-union fields on struct globals are unsupported in v1 — the
local path's tagged branch isn't generalised yet. Whole-struct
by-value flow through expressions remains NYI (matches the local
status). 630_let_global gains 3 fixtures (read/write, compound +=,
narrow u8 field); selfhost mirror keeps test 990 / 994 / 995 byte
identical; bootstrap fixed point holds.
This commit is contained in:
@@ -138,6 +138,49 @@ static const struct fixture fixtures[] = {
|
||||
"};\n",
|
||||
99,
|
||||
},
|
||||
{
|
||||
"struct-field-readwrite",
|
||||
/* Top-level struct global. Field writes hit the global
|
||||
* via LEAQ name(SB) + offset; reads pull each field
|
||||
* with the right width. */
|
||||
"type point = struct { x: i32, y: i32 };\n"
|
||||
"let p: point;\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\tp.x = 7;\n"
|
||||
"\tp.y = 35;\n"
|
||||
"\treturn p.x + p.y;\n"
|
||||
"};\n",
|
||||
42,
|
||||
},
|
||||
{
|
||||
"struct-field-compound",
|
||||
/* Compound += on a struct global field — load via
|
||||
* LEAQ+disp, push, eval rhs, combine, store. */
|
||||
"type counter = struct { n: i64 };\n"
|
||||
"let c: counter;\n"
|
||||
"fn bump(d: i64) void = { c.n += d; };\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\tbump(10i64);\n"
|
||||
"\tbump(15i64);\n"
|
||||
"\tbump(17i64);\n"
|
||||
"\treturn c.n: i32;\n"
|
||||
"};\n",
|
||||
42,
|
||||
},
|
||||
{
|
||||
"struct-narrow-field",
|
||||
/* u8 field on a struct global. Read uses MOVZBQ, store
|
||||
* uses MOVB. Pre-fix this would have stomped neighbouring
|
||||
* bytes by emitting MOVQ. */
|
||||
"type packet = struct { hdr: u8, body: u32 };\n"
|
||||
"let pkt: packet;\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\tpkt.hdr = 42u8;\n"
|
||||
"\tpkt.body = 999u32;\n"
|
||||
"\treturn pkt.hdr: i32;\n"
|
||||
"};\n",
|
||||
42,
|
||||
},
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user