wcc/cgen: #21 def-str/slice by-value arg pushes all 3 header words (wwstage)
Recognizer flip: nodeisstr/nodeisslice type-key a def ident (was local-keyed → fell to scalar default PUSHQ, dropped len/cap). Mirrors cstage node_isstr/node_isslice; push/pop stay symmetric via the shared recognizer. wwstage-only; cstage already correct.
This commit is contained in:
@@ -31,9 +31,22 @@
|
||||
* str_glob_ptr | let s:str="abcd"; take reads x[0] (uses ptr) | 97
|
||||
* slice_glob_len | let g:[]int=[10..50]; take reads x.len | 5
|
||||
* slice_glob_idx | let g:[]int=[10..50]; take reads x[2] | 30
|
||||
* def_str_len | def s:str="abcd"; take reads x.len (#21) | 4
|
||||
* def_str_ptr | def s:str="abcd"; take reads x[0] (#21) | 97
|
||||
* def_str_return | return <def-str>; take reads x.len (#21) | 5
|
||||
* ctrl_local_str | LOCAL str arg (off!=0, unchanged, byte-id) | 2
|
||||
* ctrl_local_sl | LOCAL []int arg (off!=0, unchanged, byte-id) | 8
|
||||
*
|
||||
* The def_* rows are the #21 residual of this by-value-global family: a
|
||||
* module-level `def s: str` (NO DATA symbol) passed BY VALUE. Pre-fix wwstage's
|
||||
* nodeisstr was LOCAL-keyed for an N_IDENT (def→false), so the def-str fell to
|
||||
* the scalar single-PUSHQ default and dropped len/cap; cstage's node_isstr is
|
||||
* TYPE-keyed (n->type) and pushes all 3 words. A def rides cgident's const-fold
|
||||
* (LEAQ _S_n, MOVQ $len) — NOT the let LEAQ name(SB) path — then the now
|
||||
* type-keyed nodeisstr triple push. def_str_return is a SIBLING guard (a
|
||||
* def-str flowed through a fn return, then pushed via nodeisstr's pre-existing
|
||||
* N_CALL arm) — byte-id-identical pre/post-fix, no #21 teeth of its own.
|
||||
*
|
||||
* The *_glob_* rows are mutation-sane: pre-fix wwstage drops len/cap and the
|
||||
* callee reads garbage; cstage is correct. ctrl_* guard the unchanged local
|
||||
* path. A byte-id row pins cstage==wwstage `.s` for each source.
|
||||
@@ -101,6 +114,42 @@ static const struct row rows[] = {
|
||||
"export fn main() i32 = { return take(g): i32; };\n",
|
||||
30 },
|
||||
|
||||
/* def_str_len — THE #21 regression pin: a module-level `def s: str`
|
||||
* passed BY VALUE, callee reads x.len. Pre-fix wwstage drops len/cap
|
||||
* (scalar single-PUSHQ default); cstage type-keyed pushes all 3 words.
|
||||
* A def has NO DATA symbol — it rides cgident's const-fold (LEAQ _S_x,
|
||||
* MOVQ $len BX, $len CX), then the type-keyed str triple push. */
|
||||
{ "def_str_len",
|
||||
"package main;\n"
|
||||
"def s: str = \"abcd\";\n"
|
||||
"fn take(x: str) int = { return x.len: int; };\n"
|
||||
"export fn main() i32 = { return take(s): i32; };\n",
|
||||
4 },
|
||||
|
||||
/* def_str_ptr — def-str by value, callee reads x[0] (proves the ptr
|
||||
* word survived the push). 'a' == 97. */
|
||||
{ "def_str_ptr",
|
||||
"package main;\n"
|
||||
"def s: str = \"abcd\";\n"
|
||||
"fn take(x: str) int = { return x[0]: int; };\n"
|
||||
"export fn main() i32 = { return take(s): i32; };\n",
|
||||
97 },
|
||||
|
||||
/* def_str_return — a def-str flowed through a fn return: give()'s
|
||||
* `return s` leaves the const-folded str header (AX=ptr/BX=len/CX=cap),
|
||||
* and the outer `take(give())` arg rides nodeisstr's pre-existing N_CALL
|
||||
* arm (give returns str) for the 3-word push. A #21 SIBLING, not the
|
||||
* N_IDENT def arm — it is byte-id-IDENTICAL pre- and post-fix (no teeth
|
||||
* of its own), kept as a convergence guard that a def-str surviving a fn
|
||||
* return stays a full str header on both stages. */
|
||||
{ "def_str_return",
|
||||
"package main;\n"
|
||||
"def s: str = \"hello\";\n"
|
||||
"fn give() str = { return s; };\n"
|
||||
"fn take(x: str) int = { return x.len: int; };\n"
|
||||
"export fn main() i32 = { return take(give()): i32; };\n",
|
||||
5 },
|
||||
|
||||
/* ctrl_local_str — a LOCAL str arg (off!=0). cgen unchanged; pins the
|
||||
* local-str push path stays byte-id (no regress). */
|
||||
{ "ctrl_local_str",
|
||||
|
||||
Reference in New Issue
Block a user