wcc: str -> 24B {ptr,len,cap}, 3-reg ABI -- parity with []u8 (both stages)
A ww `str` becomes a 24-byte {ptr,len,cap} value, identical in layout to
[]u8 -- the enabling prerequisite for the Phase 2 `str == []u8` collapse.
Both stages, atomically:
- ty_str 16->24B; str value flows 3-reg AX/BX/CX (was 2-reg); str literals
emit cap (=len).
- str in a tagged union grows to a 32B slot, using the AX/DX/CX/R8 4th-word
path already used by 32B slice-variant unions -- str-variant is now
structurally identical.
- tuple (scalar,str) return: 4-reg AX/DX/CX/R8 + 32B receive, extending the
existing type-keyed return (no sret).
- str == []u8 for index and .ptr/.len/.cap, kind-gated where size-based
dispatch collided at 24B; cstage and wwstage mirror exactly.
- table-driven runtime coverage: test/wcc/928_str_abi_run.c.
Cannot be split (rule 10/11): a 24B str and a 16B str cannot coexist across
the two compiler stages without breaking byte-identity, so the size change
and every dependent ABI/codegen site land in one atomic commit, both stages.
Known follow-ups (zero corpus impact, tracked): str-literal global .cap
static-init; >16B struct by-value (pre-existing); tagged-union
match-scrutinee stage divergence (pre-existing).
This commit is contained in:
@@ -239,7 +239,10 @@ static const struct asm_disp_row asm_disp_rows[] = {
|
||||
"package main;\n"
|
||||
"type holder = struct { s: str };\n"
|
||||
"fn dummy() *holder = { return alloc(holder { s = \"x\" })!; };\n",
|
||||
"\tMOVQ\tAX, (CX)\n" },
|
||||
/* #1/Phase 3: str IS []u8 (24B), so the alloc-str-field store
|
||||
* routes the heap base through DX (CX now holds the cap) and
|
||||
* writes 3 words (ptr/len/cap). Was `(CX)` in the 16B world. */
|
||||
"\tMOVQ\tAX, (DX)\n" },
|
||||
/* str at non-zero foff. Pins that the displacement IS emitted
|
||||
* (`8(CX)`) when foff != 0 — emitdispreg must not suppress
|
||||
* non-zero offsets too. Pre-fix and post-fix both pass this; it
|
||||
@@ -250,7 +253,8 @@ static const struct asm_disp_row asm_disp_rows[] = {
|
||||
"fn dummy() *holder = {\n"
|
||||
" return alloc(holder { pad = 0, s = \"x\" })!;\n"
|
||||
"};\n",
|
||||
"\tMOVQ\tAX, 8(CX)\n" },
|
||||
/* #1/Phase 3: DX base (str IS []u8, cap in CX); was `8(CX)`. */
|
||||
"\tMOVQ\tAX, 8(DX)\n" },
|
||||
/* Generic 8-byte field at foff=0 (non-str, non-float path). Covers
|
||||
* the `else` branch's `MOVQ AX, (BX)` store via fieldstoreop. */
|
||||
{ "alloc_int_at_offset0",
|
||||
|
||||
Reference in New Issue
Block a user