cgen: sub-slice ptr = base + lo*esz (both stages, #76)
A sub-slice base[lo:hi] advanced its data pointer by lo (element COUNT) instead of lo*esz (BYTES), so the base pointer was wrong for any esz>1 element. Pointer arithmetic is membsz-unit per the rt invariant (ref/hare/rt/ensure.ha:30); esz==1 (u8/str) is unchanged. Four emission sites, fixed byte-identically across stages (rule 10): - value path: cmd/w6c/cgen.c N_SLICE <-> cgenexpr.ww cgslice - call-arg: cmd/w6c/cgen.c:4646 <-> cgenutil.ww pushargsrev Scaling mirrors the cgindex idiom: esz from the type table (rule 13; cstage bu->sub->size, wwstage elemsizeofc) gated to an N_IDENT base, uniform IMULQ (no SHL special-case, no immediate form -- w6a is reg-reg only). The live lo reg is the multiplicand so the one free GP (DX value / BX arg) holds esz*lo; lo is preserved for len (hi-lo) and cap (base_cap-lo, #20). The esz==1 path keeps the single ADDQ, byte-identical to before (#75/#20/str unaffected). Non-ident bases stay unscaled in both stages (wwstage has no tnode there), tracked as a #76 residual alongside #74. New 943_subslice_ptresz_run: table-driven, dual-driver (ww/ww_ww), esz in {2,4,8} array+slice base, lo>0, let-form + call-arg form; asserts s[0]==base[lo] & s[1]==base[lo+1]. Fails on every fixture pre-fix on both stages, passes post-fix. Registered in Makefile (TESTS + target) so test/run builds and runs it.
This commit is contained in:
@@ -4590,6 +4590,13 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
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 (rule 10) -- #76 residual, non-
|
||||
* ident cluster #74. */
|
||||
int esz = (base && base->kind == N_IDENT
|
||||
&& bu && bu->sub)
|
||||
? (int)bu->sub->size : 1;
|
||||
/* base addr → push */
|
||||
if (base->kind == N_IDENT) {
|
||||
int boff = localfind(locals, base->str);
|
||||
@@ -4642,8 +4649,16 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
/* len = hi - lo (DX) */
|
||||
ins2(c, A_MOVQ, areg(D_BX), areg(D_DX));
|
||||
ins2(c, A_SUBQ, areg(D_AX), areg(D_DX));
|
||||
/* ptr = base + lo */
|
||||
ins2(c, A_ADDQ, areg(D_AX), areg(D_CX));
|
||||
/* ptr = base + lo*esz (#76; ensure.ha:30
|
||||
* membsz-unit). BX=lo*esz; AX=lo PRESERVED
|
||||
* for cap. BX (dead hi) reloaded by cap below. */
|
||||
if (esz > 1) {
|
||||
ins2(c, A_MOVQ, aimm(esz), areg(D_BX));
|
||||
ins2(c, A_IMULQ, areg(D_AX), areg(D_BX));
|
||||
ins2(c, A_ADDQ, areg(D_BX), areg(D_CX));
|
||||
} else {
|
||||
ins2(c, A_ADDQ, areg(D_AX), areg(D_CX));
|
||||
}
|
||||
/* push cap, len, ptr (top). cap = base_cap - lo
|
||||
* (#20); AX=lo, BX free. */
|
||||
if (cg_base_cap(c, base, bu, locals, D_BX)) {
|
||||
@@ -6361,17 +6376,22 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
case N_SLICE: {
|
||||
/* base[lo:hi] as a slice value. Leaves the triple in
|
||||
* (AX=base+lo, BX=hi-lo, CX=base_cap-lo) so callers can
|
||||
* (AX=base+lo*esz, BX=hi-lo, CX=base_cap-lo) so callers can
|
||||
* route to a slice slot, return, or arg with the same ABI.
|
||||
* cap is the storage remaining to the base's end (#20,
|
||||
* Go/Hare-identical), via cg_base_cap. Element scaling on
|
||||
* the ptr isn't wired (lo*esz is #76), so non-u8 slices
|
||||
* need that follow-up before their ptr is correct. */
|
||||
* Go/Hare-identical), via cg_base_cap. ptr advances by BYTES
|
||||
* (lo*esz, #76; ref/hare/rt/ensure.ha:30 membsz-unit); esz
|
||||
* from the type table, mirroring the N_INDEX idiom. */
|
||||
Node *base = n->lhs;
|
||||
Node *lo = n->rhs;
|
||||
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)
|
||||
? (int)bu->sub->size : 1;
|
||||
if (base && base->kind == N_IDENT) {
|
||||
int boff = localfind(locals, base->str);
|
||||
int isglobal = (boff == 0) && let_islet(base->str);
|
||||
@@ -6415,7 +6435,15 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_BX));
|
||||
ins1(c, A_POPQ, areg(D_CX));
|
||||
ins1(c, A_POPQ, areg(D_AX));
|
||||
ins2(c, A_ADDQ, areg(D_CX), areg(D_AX));
|
||||
/* ptr = base + lo*esz (#76; ensure.ha:30 membsz-unit).
|
||||
* DX=lo*esz; CX=lo PRESERVED for len + cap (#20). */
|
||||
if (esz > 1) {
|
||||
ins2(c, A_MOVQ, aimm(esz), areg(D_DX));
|
||||
ins2(c, A_IMULQ, areg(D_CX), areg(D_DX));
|
||||
ins2(c, A_ADDQ, areg(D_DX), areg(D_AX));
|
||||
} else {
|
||||
ins2(c, A_ADDQ, areg(D_CX), areg(D_AX));
|
||||
}
|
||||
ins2(c, A_SUBQ, areg(D_CX), areg(D_BX));
|
||||
/* cap = base_cap - lo (#20); CX=lo, BX=len here. */
|
||||
if (cg_base_cap(c, base, bu, locals, D_DX)) {
|
||||
|
||||
Reference in New Issue
Block a user