w6c+wwstage: addr-of/slice struct array-field via dotbaseaddr (#252)
Taking &x.o[i] (address-of) or slicing x.o[lo:hi] / x.o[lo:] of a struct's [N]T-typed FIELD computed the field's VALUE as the base address (MOVL off(BP),AX) instead of its ADDRESS (LEAQ off(BP),AX) -> garbage pointer -> segfault. The index read/write path was fixed in #135; this is the unwired addr-of + slice sibling — both base-address paths fell to the generic cgexpr(base) auto-deref. Wire the #135 cg_dotbase_addr / dotbaseaddr helper into the addr-of N_INDEX complex-base arm and the N_SLICE base arm, symmetric on both stages (guarded if(!dotbase) cgexpr(base)). Extend the slice element stride (esz) and default-hi length to an N_DOT array-field base too, read from the field's element tinfo / array length via the type table (rule-13) — so non-u8 element slices scale correctly and s.obuf[lo:] gets the array's element count. cstage already derived default-hi via base->type (alen); only wwstage needed the N_DOT default-hi arm. cs==ww byte-identical on every shape. test/949_dotbase_addr_slice_run: 7 dual-stage rows (addr-of local + *struct param, explicit + default-hi u8 slice, non-u8 [4]i32 stride, bare-local control), run + cs==ww byte-id. Regen w6c/wwdump combined.ww.
This commit is contained in:
@@ -3255,9 +3255,14 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
break;
|
||||
}
|
||||
/* Complex base: eval to AX, swap into BX,
|
||||
* then add the saved scaled idx. */
|
||||
* then add the saved scaled idx. #252: an
|
||||
* N_DOT `[N]T`-field base needs the field
|
||||
* ADDRESS (cg_dotbase_addr LEAQ) — cgexpr would
|
||||
* auto-deref + load the field VALUE as a pointer
|
||||
* (segfault). Sibling of the #135 read-side wiring. */
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
cgexpr(c, base, locals);
|
||||
if (!cg_dotbase_addr(c, base, D_AX, locals))
|
||||
cgexpr(c, base, locals);
|
||||
ins1(c, A_POPQ, areg(D_BX));
|
||||
ins2(c, A_ADDQ, areg(D_BX), areg(D_AX));
|
||||
break;
|
||||
@@ -8168,10 +8173,14 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Node *hi = n->cond;
|
||||
Type *bt = base ? base->type : NULL;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
/* N_IDENT-gated: non-ident bases stay esz=1 (unscaled),
|
||||
* byte-id with wwstage which has no tnode there to resolve
|
||||
* esz (rule 10) -- #76 residual, non-ident cluster #74. */
|
||||
int esz = (base && base->kind == N_IDENT && bu && bu->sub)
|
||||
/* esz from the type table for an N_IDENT base (#76) or an
|
||||
* N_DOT array/slice-field base (#252: a struct-field slice
|
||||
* `s.obuf[lo:hi]` must scale by the field's element width, not
|
||||
* stay esz=1 — silently wrong for non-u8 elements). Other
|
||||
* non-ident bases stay esz=1 (unscaled) -- #76 residual,
|
||||
* non-ident cluster #74. */
|
||||
int esz = (base && (base->kind == N_IDENT
|
||||
|| base->kind == N_DOT) && bu && bu->sub)
|
||||
? (int)bu->sub->size : 1;
|
||||
if (base && base->kind == N_IDENT) {
|
||||
int boff = localfind(locals, base->str);
|
||||
@@ -8188,7 +8197,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, amem(D_BP, boff), areg(D_AX));
|
||||
}
|
||||
} else if (base) {
|
||||
cgexpr(c, base, locals);
|
||||
/* #252: N_DOT `[N]T`-field base → field ADDRESS via
|
||||
* cg_dotbase_addr (LEAQ), not the auto-deref VALUE load
|
||||
* cgexpr would emit. Sibling of the #135 read-side. */
|
||||
if (!cg_dotbase_addr(c, base, D_AX, locals))
|
||||
cgexpr(c, base, locals);
|
||||
}
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
if (lo) cgexpr(c, lo, locals);
|
||||
|
||||
Reference in New Issue
Block a user