cgen: store all eightbytes when an in-cap aggregate call returns into a field of an indexed element (#11)
The arr[i].f=mk() assign arm had no aggregate-field sub-arm, so a by-value aggregate field receive fell to the scalar default (one MOVQ, dropping DX/CX) — silent on BOTH stages (byte-id blind). Add a dual-site symmetric in-cap N_CALL arm mirroring C2c (c83a340): scratch-first materialise AX/DX/CX, then word-copy to (fi.foff+k*8) within &arr[i], sizing from the natural field size fi.fsz (not slotsize). Rule-7 LOUD-STOP for the three cases the in-cap GP path cannot transport: over-cap sret (#11c/#234), a float-bearing field whose eightbyte classifies SSE (#11/#165), and a 3/5/6/7-byte sub-8 tail the single narrow tail MOV cannot express (the general cascade tail is the shared C2c/#11 follow-up, task #10). Value-asserting pins (poison-seeded, redden under each stage's independent revert) plus cfail pins for the three loud-stops.
Contained to the indexed base + in-cap call rhs; arr[i].f=src (#11b) and over-cap (#11c) are separate.
This commit is contained in:
172
cmd/w6c/cgen.c
172
cmd/w6c/cgen.c
@@ -5810,6 +5810,178 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
amem(D_BX, foff + 8));
|
||||
break;
|
||||
}
|
||||
/* #11: an in-cap aggregate-returning CALL into
|
||||
* an AGGREGATE field of an indexed element
|
||||
* `arr[i].f = mk()`. The scalar default below
|
||||
* stores only AX (eb0), dropping DX/CX — a SILENT
|
||||
* both-stage field-drop, the field-of-indexed twin
|
||||
* of C2c's whole-element arr[i]=mk() arm
|
||||
* (cgen.c :6764). Scratch-first materialise of the
|
||||
* AX/DX/CX return (not a PUSHQ spill — keeps the
|
||||
* CALL at the frame's 16B alignment and survives an
|
||||
* idx that itself contains a call), reuse the scalar
|
||||
* arm's &arr[i]->BX address computation verbatim,
|
||||
* then word-copy scratch to foff(BX). In-cap only
|
||||
* (cg_sret_retsize==0); over-cap sret-into-field
|
||||
* LOUD-STOPS (#11c/#234, task #8) and a float-
|
||||
* bearing aggregate LOUD-STOPS (#165/#171 — a pure-
|
||||
* float return eightbyte rides X0/X1 which the GP
|
||||
* AX/DX/CX cursor cannot read). Mirrors wwstage
|
||||
* cgenexpr.ww. */
|
||||
if (n->op == TK_ASSIGN && n->rhs
|
||||
&& n->rhs->kind == N_CALL) {
|
||||
if (cg_sret_retsize(ft) > 0)
|
||||
fatal("#11c/#234: over-cap "
|
||||
"(sret) aggregate field "
|
||||
"receive arr[i].f=mk() "
|
||||
"unwired (cs!=ww; task #8)");
|
||||
/* struct_float_class mirrors the
|
||||
* return-side SSE routing (#171a); a
|
||||
* field typed DIRECTLY as a tuple misses
|
||||
* it yet the bare-tuple return routes
|
||||
* floats to tuple_sse_seq — guard it too
|
||||
* so neither stage silently stores X0
|
||||
* garbage through the GP cursor. */
|
||||
int sclass11[2];
|
||||
int sse11 = struct_float_class(ft,
|
||||
sclass11) > 0;
|
||||
if (!sse11) {
|
||||
Type *tu11 =
|
||||
type_chase_named(ft);
|
||||
if (tu11 && tu11->kind
|
||||
== TY_TUPLE)
|
||||
for (Tparam *p11 =
|
||||
tu11->params; p11;
|
||||
p11 = p11->next) {
|
||||
int f32_11;
|
||||
if (fld_isfloat(
|
||||
p11->type,
|
||||
&f32_11))
|
||||
sse11 = 1;
|
||||
}
|
||||
}
|
||||
if (sse11)
|
||||
fatal("#11/#165: float-bearing "
|
||||
"aggregate field receive "
|
||||
"arr[i].f=mk() unwired (SSE "
|
||||
"return eightbyte; #171)");
|
||||
if (fsz > 8) {
|
||||
/* A 3/5/6/7-byte sub-8 tail cannot be
|
||||
* materialised by the single narrow MOV
|
||||
* below — it stores ONE byte while the
|
||||
* copy reads the full tail, dropping the
|
||||
* rest from uninitialised scratch (a
|
||||
* silent both-stage drop; empirically a
|
||||
* 14B 7xi16 field loses f/g). The whole-
|
||||
* element C2c sibling (:6764) shares this
|
||||
* single-tail gap; until a general
|
||||
* register->scratch tail (shift cascade)
|
||||
* lands across BOTH sites, LOUD-STOP
|
||||
* rather than silently drop — rule 7, the
|
||||
* sibling of the over-cap/float stops
|
||||
* above. Tails 0/1/2/4 are exact and flow
|
||||
* through. Mirrors wwstage cgenexpr.ww. */
|
||||
int tl11 = fsz % 8;
|
||||
if (tl11 == 3 || tl11 == 5
|
||||
|| tl11 == 6 || tl11 == 7)
|
||||
fatal("#11: aggregate field receive "
|
||||
"arr[i].f=mk() with a 3/5/6/7-byte "
|
||||
"sub-8 tail unwired (materialise "
|
||||
"single-MOV under-stores; "
|
||||
"C2c-shared)");
|
||||
int scr11 = cg_tagscr_slot(c,
|
||||
&locals, fsz);
|
||||
cgexpr(c, n->rhs, locals);
|
||||
int regs11[3] = { D_AX, D_DX,
|
||||
D_CX };
|
||||
int full11 = fsz / 8;
|
||||
int tail11 = fsz % 8;
|
||||
for (int i11 = 0;
|
||||
i11 < full11; i11++)
|
||||
ins2(c, A_MOVQ,
|
||||
areg(regs11[i11]),
|
||||
amem(D_BP, scr11
|
||||
+ i11 * 8));
|
||||
if (tail11 > 0) {
|
||||
int op11 = (tail11 == 4)
|
||||
? A_MOVL : (tail11
|
||||
== 2) ? A_MOVW
|
||||
: A_MOVB;
|
||||
ins2(c, op11,
|
||||
areg(regs11[full11]),
|
||||
amem(D_BP, scr11
|
||||
+ full11 * 8));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
ins2(c, A_ADDQ,
|
||||
areg(D_AX), areg(D_BX));
|
||||
if (viaptr)
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BX, 0),
|
||||
areg(D_BX));
|
||||
int k11 = 0;
|
||||
for (; k11 + 8 <= fsz;
|
||||
k11 += 8) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, scr11
|
||||
+ k11), areg(D_AX));
|
||||
ins2(c, A_MOVQ,
|
||||
areg(D_AX),
|
||||
amem(D_BX,
|
||||
foff + k11));
|
||||
}
|
||||
if (k11 + 4 <= fsz) {
|
||||
ins2(c, A_MOVL,
|
||||
amem(D_BP, scr11
|
||||
+ k11), areg(D_AX));
|
||||
ins2(c, A_MOVL,
|
||||
areg(D_AX),
|
||||
amem(D_BX,
|
||||
foff + k11));
|
||||
k11 += 4;
|
||||
}
|
||||
if (k11 + 2 <= fsz) {
|
||||
ins2(c, A_MOVW,
|
||||
amem(D_BP, scr11
|
||||
+ k11), areg(D_AX));
|
||||
ins2(c, A_MOVW,
|
||||
areg(D_AX),
|
||||
amem(D_BX,
|
||||
foff + k11));
|
||||
k11 += 2;
|
||||
}
|
||||
if (k11 + 1 <= fsz) {
|
||||
ins2(c, A_MOVB,
|
||||
amem(D_BP, scr11
|
||||
+ k11), areg(D_AX));
|
||||
ins2(c, A_MOVB,
|
||||
areg(D_AX),
|
||||
amem(D_BX,
|
||||
foff + k11));
|
||||
k11 += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* fsz<=8 in-cap aggregate returns
|
||||
* wholly in AX; the scalar default's
|
||||
* single store is the correct receive. */
|
||||
}
|
||||
if (n->op == TK_ASSIGN) {
|
||||
cgexpr(c, n->rhs, locals);
|
||||
ins1(c, A_PUSHQ,
|
||||
|
||||
Reference in New Issue
Block a user