w6c+cgen: len() over indexed str/slice element extracts .len (fix #19)
`len(xs[i])` over a [N]str/[]str (and []T slice) element returned the element's .ptr, not its length, on BOTH stages (shared gap, not rule-10): the len() builtin had no N_INDEX arm, so it fell to the bare-cgexpr fallback, where the N_INDEX str/slice load (cgslicehdr) leaves AX=.ptr, BX=.len, CX=.cap — and len() returned AX (the ptr) as the length. Add an N_INDEX arm gated on a (TY_SLICE||TY_STR) element in both stages: cgexpr the element, then MOVQ BX,AX to shuffle the len word into the result reg — the same shape as the #14 .len pseudo-field fix. Byte-id neutral (no bootstrap source uses len(indexed-element)); regenerated w6c + wwdump combined.ww. New 802_lenidx_run pins runtime + cs==ww.
This commit is contained in:
@@ -5998,6 +5998,18 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
} else {
|
||||
cgexpr(c, a, locals);
|
||||
}
|
||||
} else if (u && (u->kind == TY_SLICE || u->kind == TY_STR)
|
||||
&& a->kind == N_INDEX) {
|
||||
/* #19: len() of an INDEXED str/slice element
|
||||
* (`len(xs[i])`). The N_INDEX str/slice load leaves
|
||||
* AX=.ptr, BX=.len, CX=.cap (cgslicehdr) — the bare
|
||||
* cgexpr fallback below then returned AX (the ptr) AS
|
||||
* the length. Shuffle BX (the len word) into AX, the
|
||||
* same MOVQ BX,AX shape as the #14 .len pseudo-field
|
||||
* fix. Same family as #18 (shared cstage==wwstage gap,
|
||||
* not a rule-10 divergence). */
|
||||
cgexpr(c, a, locals);
|
||||
ins2(c, A_MOVQ, areg(D_BX), areg(D_AX));
|
||||
} else if (u && u->kind == TY_ARRAY) {
|
||||
ins2(c, A_MOVQ, aimm((long long)u->alen), areg(D_AX));
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user