w6c+wwstage: len() of tuple-element slice reads .len not .ptr (#235)
len() special-cased only a plain N_IDENT slice operand (load .len at BP+off+8) and an array operand (fold $alen); every other shape fell back to a bare cgexpr(operand), which for a slice leaves AX=.ptr. A tuple- element read (t.N) loads only AX=.ptr, so len(t.N) on a slice/str tuple element returned the slice's .ptr word AS its length — a silent miscompile, gate-blind because the bootstrap never does len() on a slice-typed tuple element (sibling of the #234/#237 tuple-sret cluster). Both stages: detect a slice/str tuple-element len() operand and load the element's .len word directly at BP + element_off + 8, mirroring the N_IDENT slice arm and the tuple-field-offset walk (element_off sums preceding element sizes through the type table). Byte-identical asm (rule 10). The separate tuple-element-read full-header gap is #238; a leading-scalar mixed-tuple has its own pre-existing sret-layout cs/ww divergence, filed apart from #235. Test 903_tuple_elem_slice_len_run: 4 slice/str-only tuple rows (two/ three slices, str+slice, slice+str; distinct lengths), build+run both drivers + cs==ww byte-id. 12/12 ok.
This commit is contained in:
@@ -5328,6 +5328,39 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, amem(D_BP, off + 8),
|
||||
areg(D_AX));
|
||||
}
|
||||
} else if (u && (u->kind == TY_SLICE || u->kind == TY_STR)
|
||||
&& a->kind == N_DOT && a->lhs
|
||||
&& a->lhs->kind == N_IDENT && a->str) {
|
||||
/* #235: len() of a tuple-element slice/str
|
||||
* (`len(t.N)`). The tuple-element read leaves only
|
||||
* AX=.ptr — it has no slice-header sibling (that
|
||||
* gap is #238) — so the bare cgexpr fallback below
|
||||
* returned .ptr AS the length. Load the element's
|
||||
* .len word directly at BP + element_off + 8,
|
||||
* mirroring the N_IDENT slice arm above and the
|
||||
* tuple-field-offset walk (cgen.c N_DOT TY_TUPLE). */
|
||||
Type *bt = a->lhs->type;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED)
|
||||
? bt->under : bt;
|
||||
if (bu && bu->kind == TY_TUPLE) {
|
||||
int idx = 0;
|
||||
for (const char *q = a->str; *q; q++)
|
||||
idx = idx * 10 + (*q - '0');
|
||||
Tparam *tp = bu->params;
|
||||
int foff = 0;
|
||||
while (idx > 0 && tp) {
|
||||
if (tp->type)
|
||||
foff += (int)tp->type->size;
|
||||
tp = tp->next;
|
||||
idx--;
|
||||
}
|
||||
int off = localfind(locals, a->lhs->str);
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, off + foff + 8),
|
||||
areg(D_AX));
|
||||
} else {
|
||||
cgexpr(c, a, locals);
|
||||
}
|
||||
} 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