w6c+wwstage: &aggregate-array-element addressing + store/copy (#270-1)
The array-of-struct element store/copy family — one primitive (&(array element) for an AGGREGATE element, used as address, never deref/truncate) across three consumers. Both stages were symmetric-broken; converge on the runtime-correct full-address/full-copy (#263). (1a) `a[i].m[j] = v` (a:[N]struct) segfaulted: the `arr[i].field` arm computed &a[i] then DEREF'd it (loaded the struct's first 8 bytes as a value) for an `[N]T`-typed field → garbage base. Now an array-typed field of an array element leaves the field ADDRESS (the #135 read-side, applied to the array-element base). cgen.c arm + cgenexpr.ww cgdot N_INDEX-lhs branch. (1b) `a[i] = aggregateval` truncated the copy to an 8B MOVQ. New aggregate (struct/array/tuple >8B) element-store branch word-copies the element from the rhs source address (ident / N_DOT field / `*p` deref) — the WRITE-twin of the #268 let-init loop. cgen.c N_INDEX store + cgenexpr.ww cgassign. (3a) `let c = x.arr[i]` (N_DOT base) / `let c = a[i][j]` (nested) dropped the copy: the #268 let-init N_INDEX source-addr arm was N_IDENT-base- gated. Now computes &base[idx] via cg_dotbase_addr (N_DOT field) or the &abase[bidx] spine (nested N_IDENT-array base). cgen.c N_LET + cgenstmt.ww cglet. 949 rows: elemfield_store, elem_struct_store, elem_arr_store, letcopy_{dot,nest}_prim, letcopy_subarr (byteid=1); letcopy_{dot,nest}_ struct (byteid=0 — run-correct, byte-id blocked by the orthogonal value-nested-struct frame divergence #254). All 94 pass; test-unit 241 green.
This commit is contained in:
190
cmd/w6c/cgen.c
190
cmd/w6c/cgen.c
@@ -5020,6 +5020,108 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
cg_sret_dest_off = 0;
|
||||
break;
|
||||
}
|
||||
/* #270-1b: aggregate (struct/array/tuple >8B) element
|
||||
* STORE `a[i] = val`. The scalar store path below copies
|
||||
* only the first 8 bytes (fldstoreop MOVQ) — a silent
|
||||
* truncation. Compute &a[i] (dest) and the rhs SOURCE
|
||||
* address, then word-copy esz bytes: the WRITE-twin of the
|
||||
* #268 let-init copy loop. Source shapes mirror that loop
|
||||
* (ident local/global, N_DOT field via cg_dotchain_addr,
|
||||
* `*p` deref); a by-value call result is the deferred #271,
|
||||
* so N_CALL/literal sources fall through unchanged. */
|
||||
if ((is_arr || is_sl || is_ptr) && n->op == TK_ASSIGN
|
||||
&& esubu && (esubu->kind == TY_STRUCT
|
||||
|| esubu->kind == TY_ARRAY
|
||||
|| esubu->kind == TY_TUPLE)
|
||||
&& esz > 8
|
||||
&& ((n->rhs->kind == N_IDENT)
|
||||
|| (n->rhs->kind == N_DOT)
|
||||
|| (n->rhs->kind == N_UN
|
||||
&& n->rhs->op == TK_STAR))) {
|
||||
/* dest &a[i] → BX */
|
||||
cgexpr(c, n->lhs->rhs, locals); /* idx → AX */
|
||||
if (esz > 1) {
|
||||
ins2(c, A_MOVQ, aimm(esz), areg(D_CX));
|
||||
ins2(c, A_IMULQ, areg(D_CX), areg(D_AX));
|
||||
}
|
||||
ins1(c, A_PUSHQ, areg(D_AX)); /* scaled idx */
|
||||
if (base->kind == N_IDENT) {
|
||||
int off = localfind(locals, base->str);
|
||||
int isglobal = (off == 0)
|
||||
&& let_islet(base->str);
|
||||
if (isglobal && is_arr)
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, base->str),
|
||||
areg(D_BX));
|
||||
else if (isglobal)
|
||||
ins2(c, A_MOVQ,
|
||||
masym(c, base->str),
|
||||
areg(D_BX));
|
||||
else if (is_arr)
|
||||
ins2(c, A_LEAQ,
|
||||
amem(D_BP, off), areg(D_BX));
|
||||
else
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, off), areg(D_BX));
|
||||
} else if (cg_dotbase_addr(c, base, D_BX, locals)) {
|
||||
/* N_DOT array-field base resolved inline. */
|
||||
} else {
|
||||
cgexpr(c, base, locals);
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_BX));
|
||||
}
|
||||
ins1(c, A_POPQ, areg(D_AX)); /* scaled idx */
|
||||
ins2(c, A_ADDQ, areg(D_AX), areg(D_BX));
|
||||
ins1(c, A_PUSHQ, areg(D_BX)); /* spill dest */
|
||||
/* rhs source address → SI */
|
||||
if (n->rhs->kind == N_UN
|
||||
&& n->rhs->op == TK_STAR) {
|
||||
cgexpr(c, n->rhs->lhs, locals);
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_SI));
|
||||
} else if (n->rhs->kind == N_IDENT) {
|
||||
int soff = localfind(locals,
|
||||
n->rhs->str);
|
||||
if (soff != 0)
|
||||
ins2(c, A_LEAQ,
|
||||
amem(D_BP, soff),
|
||||
areg(D_SI));
|
||||
else
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, n->rhs->str),
|
||||
areg(D_SI));
|
||||
} else {
|
||||
cg_dotchain_addr(c, n->rhs, D_SI, locals);
|
||||
}
|
||||
ins1(c, A_POPQ, areg(D_BX)); /* dest */
|
||||
int k = 0;
|
||||
for (; k + 8 <= esz; k += 8) {
|
||||
ins2(c, A_MOVQ, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
}
|
||||
if (k + 4 <= esz) {
|
||||
ins2(c, A_MOVL, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVL, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
k += 4;
|
||||
}
|
||||
if (k + 2 <= esz) {
|
||||
ins2(c, A_MOVW, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVW, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
k += 2;
|
||||
}
|
||||
if (k + 1 <= esz) {
|
||||
ins2(c, A_MOVB, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVB, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
k += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((is_arr || is_sl || is_ptr) && n->op == TK_ASSIGN) {
|
||||
cgexpr(c, n->rhs, locals); /* AX=ptr (BX=len,CX=cap if str) */
|
||||
/* str/slice: stash cap+len so all three store
|
||||
@@ -8024,6 +8126,23 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Type *ft = f->type;
|
||||
Type *fu = (ft && ft->kind == TY_NAMED)
|
||||
? ft->under : ft;
|
||||
/* #270-1a: an `[N]T`-typed field of an
|
||||
* array element (`a[i].m[j]`) — leave the
|
||||
* field's ADDRESS, a base for the outer
|
||||
* index, NEVER deref. AX holds &a[i]; the
|
||||
* field address is &a[i]+foff. The #135
|
||||
* read-side for `d.m[i]`, applied to an
|
||||
* array-element base. Without this an array
|
||||
* field fell to fldloadop below and loaded
|
||||
* its first 8 bytes as a value → garbage
|
||||
* base → SEGFAULT in the outer index. */
|
||||
if (fu && fu->kind == TY_ARRAY) {
|
||||
if (foff != 0)
|
||||
ins2(c, A_ADDQ,
|
||||
aimm(foff),
|
||||
areg(D_AX));
|
||||
goto dot_done;
|
||||
}
|
||||
if (fu && (fu->kind == TY_STR
|
||||
|| fu->kind == TY_SLICE)) {
|
||||
/* str/slice: the 3-word {ptr,len,cap}
|
||||
@@ -8847,6 +8966,77 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
areg(D_SI));
|
||||
havesrc = 1;
|
||||
} else if (base && (base->kind == N_DOT
|
||||
|| base->kind == N_INDEX)) {
|
||||
/* #270-3a: the index BASE is an N_DOT
|
||||
* array-field (`x.arr[i]`) or a nested
|
||||
* N_INDEX (`a[i][j]`); the N_IDENT-base arm
|
||||
* above missed both, so the copy fell to the
|
||||
* 8B truncation below. Compute &base[idx]:
|
||||
* scaled idx on the stack, then &base via
|
||||
* cg_dotbase_addr (N_DOT field address) or
|
||||
* the &abase[bidx] spine (nested N_IDENT-
|
||||
* array base), then add. */
|
||||
int esz = (bu && bu->sub)
|
||||
? (int)bu->sub->size : 1;
|
||||
cgexpr(c, idx, *locals);
|
||||
if (esz > 1) {
|
||||
ins2(c, A_MOVQ, aimm(esz),
|
||||
areg(D_CX));
|
||||
ins2(c, A_IMULQ, areg(D_CX),
|
||||
areg(D_AX));
|
||||
}
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
int baseok = 0;
|
||||
if (base->kind == N_DOT) {
|
||||
baseok = cg_dotbase_addr(c, base,
|
||||
D_AX, *locals);
|
||||
} else {
|
||||
Node *ab = base->lhs;
|
||||
Node *bidx = base->rhs;
|
||||
Type *abt = ab ? ab->type : NULL;
|
||||
Type *abu = type_chase_named(abt);
|
||||
if (ab && ab->kind == N_IDENT
|
||||
&& abu
|
||||
&& abu->kind == TY_ARRAY) {
|
||||
int aesz = (abu->sub)
|
||||
? (int)abu->sub->size
|
||||
: 1;
|
||||
cgexpr(c, bidx, *locals);
|
||||
if (aesz > 1) {
|
||||
ins2(c, A_MOVQ,
|
||||
aimm(aesz),
|
||||
areg(D_CX));
|
||||
ins2(c, A_IMULQ,
|
||||
areg(D_CX),
|
||||
areg(D_AX));
|
||||
}
|
||||
int aoff = localfind(
|
||||
*locals, ab->str);
|
||||
if (aoff != 0)
|
||||
ins2(c, A_LEAQ,
|
||||
amem(D_BP,
|
||||
aoff),
|
||||
areg(D_BX));
|
||||
else
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c,
|
||||
ab->str),
|
||||
areg(D_BX));
|
||||
ins2(c, A_ADDQ,
|
||||
areg(D_BX),
|
||||
areg(D_AX));
|
||||
baseok = 1;
|
||||
}
|
||||
}
|
||||
ins1(c, A_POPQ, areg(D_BX));
|
||||
if (baseok) {
|
||||
ins2(c, A_ADDQ, areg(D_BX),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
areg(D_SI));
|
||||
havesrc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (havesrc) {
|
||||
|
||||
Reference in New Issue
Block a user