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:
@@ -22593,6 +22593,51 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
// #235: len() of a tuple-element slice/str
|
||||
// (`len(t.N)`). The tuple-element read leaves
|
||||
// only AX=.ptr — no slice-header sibling (that
|
||||
// gap is #238) — so the 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 (cgenexpr.ww N_TTUPLE).
|
||||
if ((u.kind == tykind.TY_SLICE
|
||||
|| u.kind == tykind.TY_STR)
|
||||
&& a.kind == nkind.N_DOT
|
||||
&& a.lhs != nil
|
||||
&& a.lhs.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, a.lhs.str);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
for (tn != nil && tn.kind == nkind.N_TNAME) {
|
||||
tn = aliaslookup(c, tn.str);
|
||||
};
|
||||
if (tn != nil) {
|
||||
if (tn.kind == nkind.N_TTUPLE) {
|
||||
let idx: i32 = fldnumidx(a.str);
|
||||
if (idx >= 0) {
|
||||
let tp: *node = tn.list;
|
||||
let foff: i32 = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < idx) {
|
||||
if (tp == nil) { i = idx; }
|
||||
else {
|
||||
foff += slotsize(c, tp.lhs);
|
||||
tp = tp.next;
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
if (tp != nil) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + foff + 8): i64);
|
||||
emitline("(BP), AX\n");
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (u.kind == tykind.TY_ARRAY) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(u.alen: i64);
|
||||
|
||||
Reference in New Issue
Block a user