w6c: tagged-union fields on struct globals — LEAQ-based read+write
Field write extends the existing TY_TAGGED branch with an is_global arm: LEAQ name(SB),CX after cgexpr (no AX/BX clobber), then MOVQ into slot+foff+0 (tag) and slot+foff+8 (value, plus +16 for str- typed variants). Field read now treats tagged fields specially — load AX=tag, DX=val0, CX=val1 (when union >16B), mirroring the tagged-return ABI that let-init and match dispatch already expect. Previously the scalar-load path read 8B into AX and left DX/CX with junk, which silently broke local tagged-field reads too.
This commit is contained in:
@@ -232,6 +232,61 @@ static const struct fixture fixtures[] = {
|
||||
"};\n",
|
||||
11,
|
||||
},
|
||||
{
|
||||
"struct-tagged-field-i64",
|
||||
/* Tagged-union field on a struct global. Write goes
|
||||
* LEAQ name(SB),CX + MOVQ to slot+foff+8 (value) and
|
||||
* slot+foff+0 (tag). Read pulls AX=tag, DX=val0,
|
||||
* CX=val1 from those same slots and match dispatches. */
|
||||
"type tok = (i64 | str | void);\n"
|
||||
"type ent = struct { id: i32, t: tok };\n"
|
||||
"let e: ent;\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\te.t = 42i64: tok;\n"
|
||||
"\tlet v: tok = e.t;\n"
|
||||
"\tmatch (v) {\n"
|
||||
"\tcase let n: i64 => return n: i32;\n"
|
||||
"\tcase let s: str => return 1;\n"
|
||||
"\tcase void => return 2;\n"
|
||||
"\t};\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
42,
|
||||
},
|
||||
{
|
||||
"struct-tagged-field-str",
|
||||
"type tok = (i64 | str | void);\n"
|
||||
"type ent = struct { id: i32, t: tok };\n"
|
||||
"let e: ent;\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\te.t = \"hello\";\n"
|
||||
"\tlet v: tok = e.t;\n"
|
||||
"\tmatch (v) {\n"
|
||||
"\tcase let n: i64 => return 1;\n"
|
||||
"\tcase let s: str => return s.len: i32;\n"
|
||||
"\tcase void => return 2;\n"
|
||||
"\t};\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
5,
|
||||
},
|
||||
{
|
||||
"struct-tagged-field-void",
|
||||
"type tok = (i64 | str | void);\n"
|
||||
"type ent = struct { id: i32, t: tok };\n"
|
||||
"let e: ent;\n"
|
||||
"fn main() i32 = {\n"
|
||||
"\te.t = void;\n"
|
||||
"\tlet v: tok = e.t;\n"
|
||||
"\tmatch (v) {\n"
|
||||
"\tcase let n: i64 => return 1;\n"
|
||||
"\tcase let s: str => return 2;\n"
|
||||
"\tcase void => return 7;\n"
|
||||
"\t};\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
7,
|
||||
},
|
||||
{
|
||||
"struct-narrow-field",
|
||||
/* u8 field on a struct global. Read uses MOVZBQ, store
|
||||
|
||||
Reference in New Issue
Block a user