cgen: slice-elem store/read -> 3-word via kind-OR (both stages)
The G-cluster gave str its 3-word {ptr,len,cap} store/read at indexed/field/chained sites, but each arm was gated on str only; the slice arm fell through to the 1-word fldstoreop default, dropping len+cap. A []T value stored through arr[i]=, arr[i].f=, *struct.f=, or value-spine o.i.f= (and read back via arr[i] / arr[i].f) silently lost length and capacity.
Widen all six arms (4 stores + 2 read mirrors) with a kind-OR (TY_STR||TY_SLICE / typeisstr||typeisslice), never a size test: str and slice are both 24B, so a width gate would fire on both and mask the missing slice arm. The str kind stays distinct and nominal -- the arm is widened, the kinds are not collapsed. cstage and wwstage mirrored.
Gate-blind class: store and read were both short, so byte-identity and cstage==wwstage stayed green on self-consistent garbage; only a runtime len/cap round-trip exposes it (test 941, table-driven, 4 shapes x 2 stages, fail-before/pass-after on both ww and ww_ww).
Deref store (*p=) and tuple-elem store (N_MLET/N_MASSIGN, distinct DX,CX,R8 return-ABI) are the same bug class but separate folds.
This commit is contained in:
@@ -2887,8 +2887,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
break;
|
||||
}
|
||||
if (n->op == TK_ASSIGN
|
||||
&& fu && fu->kind == TY_STR) {
|
||||
/* str IS []u8: rhs leaves
|
||||
&& fu && (fu->kind == TY_STR
|
||||
|| fu->kind == TY_SLICE)) {
|
||||
/* str/slice: rhs leaves
|
||||
* AX=ptr, BX=len, CX=cap
|
||||
* (#1/Phase 3). Spill all
|
||||
* three across the index/
|
||||
@@ -3111,8 +3112,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
amem(D_BX, foff));
|
||||
break;
|
||||
}
|
||||
if (fu && fu->kind == TY_STR) {
|
||||
/* str IS []u8: rhs leaves AX=ptr,
|
||||
if (fu && (fu->kind == TY_STR
|
||||
|| fu->kind == TY_SLICE)) {
|
||||
/* str/slice: rhs leaves AX=ptr,
|
||||
* BX=len, CX=cap (#1/Phase 3). Spill
|
||||
* all three across the base-expr eval
|
||||
* (it may clobber any reg), stage the
|
||||
@@ -3310,8 +3312,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
int fsz = (int)(leaf_type
|
||||
? leaf_type->size : 8);
|
||||
int store_op = fldstoreop(leaf_type, fsz);
|
||||
if (fu && fu->kind == TY_STR) {
|
||||
/* str IS []u8: store ptr/len/cap. cgexpr
|
||||
if (fu && (fu->kind == TY_STR
|
||||
|| fu->kind == TY_SLICE)) {
|
||||
/* str/slice: store ptr/len/cap. cgexpr
|
||||
* leaves CX=cap, so the via_cx base goes in
|
||||
* DX (not CX) to avoid clobbering it — same
|
||||
* as the single-dot str field store
|
||||
@@ -3578,6 +3581,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Type *eff = idx_eff(bt);
|
||||
int esz = (eff && eff->sub) ? (int)eff->sub->size : 1;
|
||||
int elem_is_str = eff && eff->sub && type_isstr(eff->sub);
|
||||
int elem_is_slice = eff && eff->sub && type_isslice(eff->sub);
|
||||
Type *esub = eff ? eff->sub : NULL;
|
||||
Type *esubu = (esub && esub->kind == TY_NAMED)
|
||||
? esub->under : esub;
|
||||
@@ -3645,9 +3649,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
if (is_arr || is_sl || is_ptr) {
|
||||
cgexpr(c, n->rhs, locals); /* AX=ptr (BX=len,CX=cap if str) */
|
||||
/* str IS []u8: stash cap+len so all three store
|
||||
/* str/slice: stash cap+len so all three store
|
||||
* (#1/Phase 3). */
|
||||
if (elem_is_str) {
|
||||
if (elem_is_str || elem_is_slice) {
|
||||
ins1(c, A_PUSHQ, areg(D_CX)); /* cap */
|
||||
ins1(c, A_PUSHQ, areg(D_BX)); /* len */
|
||||
}
|
||||
@@ -3689,8 +3693,8 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins1(c, A_POPQ, areg(D_AX)); /* scaled idx */
|
||||
ins2(c, A_ADDQ, areg(D_AX), areg(D_BX));
|
||||
ins1(c, A_POPQ, areg(D_AX)); /* value (ptr if str) */
|
||||
if (elem_is_str) {
|
||||
/* str IS []u8: store ptr/len/cap (#1/Phase 3). */
|
||||
if (elem_is_str || elem_is_slice) {
|
||||
/* str/slice: store ptr/len/cap (#1/Phase 3, #7). */
|
||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_BX, 0));
|
||||
ins1(c, A_POPQ, areg(D_CX));
|
||||
ins2(c, A_MOVQ, areg(D_CX), amem(D_BX, 8));
|
||||
@@ -6141,8 +6145,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Type *ft = f->type;
|
||||
Type *fu = (ft && ft->kind == TY_NAMED)
|
||||
? ft->under : ft;
|
||||
if (fu && fu->kind == TY_STR) {
|
||||
/* str IS the 3-word {ptr,len,cap}
|
||||
if (fu && (fu->kind == TY_STR
|
||||
|| fu->kind == TY_SLICE)) {
|
||||
/* str/slice: the 3-word {ptr,len,cap}
|
||||
* slice header (#1). AX holds the
|
||||
* element base, so load .ptr (which
|
||||
* targets AX) LAST. Matches the
|
||||
@@ -6232,12 +6237,13 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, amem(D_BP, off), areg(D_BX));
|
||||
}
|
||||
ins2(c, A_ADDQ, areg(D_AX), areg(D_BX));
|
||||
/* str element: load the full (ptr, len, cap) header
|
||||
* into (AX, BX, CX) — str is 24B since #1, so the cap
|
||||
* word must survive. Kind-gate on type_isstr, never
|
||||
* size==24 (slices are 24B too; a size gate bleeds into
|
||||
* the general >16B struct path, #10). Base is BX. */
|
||||
if (u->sub && type_isstr(u->sub)) {
|
||||
/* str/slice element: load the full (ptr, len, cap) header
|
||||
* into (AX, BX, CX) — both are 24B since #1, so the cap
|
||||
* word must survive. Kind-gate on type_isstr||type_isslice,
|
||||
* never size==24: a >16B struct is 24B+ too but takes the
|
||||
* struct-copy path, not this 3-word header load (#10).
|
||||
* Base is BX. */
|
||||
if (u->sub && (type_isstr(u->sub) || type_isslice(u->sub))) {
|
||||
cgslicehdr(c, D_BX);
|
||||
break;
|
||||
}
|
||||
@@ -6281,10 +6287,10 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
cgexpr(c, n->lhs, locals);
|
||||
ins1(c, A_POPQ, areg(D_BX));
|
||||
ins2(c, A_ADDQ, areg(D_BX), areg(D_AX));
|
||||
/* str element via fallback base: load the full (ptr, len,
|
||||
* cap) header into (AX, BX, CX). Kind-gate on type_isstr,
|
||||
* never size==24 (see Site A). Base is AX. */
|
||||
if (u && u->sub && type_isstr(u->sub)) {
|
||||
/* str/slice element via fallback base: load the full (ptr, len,
|
||||
* cap) header into (AX, BX, CX). Kind-gate on type_isstr||
|
||||
* type_isslice, never size==24 (see Site A). Base is AX. */
|
||||
if (u && u->sub && (type_isstr(u->sub) || type_isslice(u->sub))) {
|
||||
cgslicehdr(c, D_AX);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user