wcc+w6c_ww: aggregate-field stores via cgplaceaddr (C1.25)
Wire struct/array/tuple field STORE through the C1 assign-resolver (task #23): structlit rhs materialises into a FRESH-per-use @placescr slot (the @slicescr discipline — a cached slot is the #31 multi-live trap) then word-copies to the resolved address; addressable rhs (ident/global/dot/deref) sources via aggarg_srcaddr with the dest spilled around the dispatch (#270-1b order). Kept loud: compound on aggregate, sret call rhs (#234-tail), <=24B call rhs (task #24), unaddressable literal rhs, ww-only anonymous-struct structinfo miss. test/wcc/805: +6 rows (40B structlit incl ... autofill, ident+deref source, nested literal, [3]u8 MOVW/MOVB and [3]u32 MOVL tails, two same-size stores in one fn pinning fresh-per-use) +3 exact-text reject rows. Tuple-field row blocked by the pre-existing tuple param/let-init word-2 drops (tasks #32/#33, documented in-row). p7b_capstore_only graduates byte-id and runs; p7_composed builds and runs on cstage, wwstage stays behind the pre-existing #29 asserttyped bail (verified identical at master with w6c_ww).
This commit is contained in:
108
cmd/w6c/cgen.c
108
cmd/w6c/cgen.c
@@ -6074,11 +6074,113 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (fu && fu->kind == TY_TAGGED)
|
||||
fatal("assign-resolver: tagged field not "
|
||||
"wired (rule-7)");
|
||||
/* C1.25 (#23): aggregate field STORE through the
|
||||
* resolver — run_thread's 40B capture store
|
||||
* `(*ts)[i].root_capture = capture{...}`. Dest address
|
||||
* from cgplaceaddr (BX), source address in SI per rhs
|
||||
* shape, then the #270-1b word-copy tail (SI)→(BX).
|
||||
* Pre-C1 this was a SILENT no-op; C1 made it loud;
|
||||
* this wires it (loud-first, wire-next). Compound on
|
||||
* an aggregate is meaningless and stays loud. */
|
||||
if (fu && (fu->kind == TY_STRUCT
|
||||
|| fu->kind == TY_ARRAY
|
||||
|| fu->kind == TY_TUPLE))
|
||||
fatal("assign-resolver: aggregate field not "
|
||||
"wired (rule-7)");
|
||||
|| fu->kind == TY_TUPLE)) {
|
||||
if (n->op != TK_ASSIGN)
|
||||
fatal("assign-resolver: compound on "
|
||||
"aggregate field not wired "
|
||||
"(rule-7)");
|
||||
if (n->rhs && n->rhs->kind == N_CALL) {
|
||||
/* sret-class needs a runtime-RDI dest
|
||||
* (the #234-tail deferral); the ≤24B
|
||||
* reg-return receive is task #24. */
|
||||
if (cg_sret_retsize(ft) > 0)
|
||||
fatal("assign-resolver: sret "
|
||||
"call into aggregate field "
|
||||
"unwired (#234-tail/"
|
||||
"rule-7)");
|
||||
fatal("assign-resolver: call result "
|
||||
"into aggregate field unwired "
|
||||
"(task #24/rule-7)");
|
||||
}
|
||||
int placed = 0;
|
||||
if (n->rhs && n->rhs->kind == N_STRUCTLIT
|
||||
&& fu->kind == TY_STRUCT) {
|
||||
/* @placescr — FRESH slot PER USE (the
|
||||
* @slicescr discipline, NOT the cached
|
||||
* @tagscr table: a cached slot is the
|
||||
* #31 multi-live corruption trap; rob
|
||||
* ruling). Funnel contract, #44
|
||||
* discipline: this arm is the ONLY
|
||||
* @placescr alloc site. Fill handles
|
||||
* nested literals (#18), tagged
|
||||
* fields, TK_ELLIPSIS autofill; the
|
||||
* value sits in memory, so the
|
||||
* resolver below may clobber AX/CX
|
||||
* freely. */
|
||||
int scr = local_alloc(c, &locals,
|
||||
"@placescr", fsz, cg_frame);
|
||||
cg_structlit_fill_bp(c, &locals, fu,
|
||||
n->rhs, scr);
|
||||
placed = cgplaceaddr(c, n->lhs, D_BX,
|
||||
locals);
|
||||
if (placed)
|
||||
ins2(c, A_LEAQ,
|
||||
amem(D_BP, scr),
|
||||
areg(D_SI));
|
||||
} else {
|
||||
/* Addressable source — ident / global
|
||||
* / N_DOT chain / deref — via the
|
||||
* closed #265/#268 dispatch. Its
|
||||
* N_INDEX arm clobbers BX, so the dest
|
||||
* spills around it (the #270-1b
|
||||
* order). Literal arrays/tuples have
|
||||
* no storage address and stay loud. */
|
||||
placed = cgplaceaddr(c, n->lhs, D_BX,
|
||||
locals);
|
||||
if (placed) {
|
||||
ins1(c, A_PUSHQ, areg(D_BX));
|
||||
if (!aggarg_srcaddr(c, n->rhs,
|
||||
D_SI, locals))
|
||||
fatal("assign-resolver"
|
||||
": aggregate rhs "
|
||||
"shape unwired "
|
||||
"(rule-7)");
|
||||
ins1(c, A_POPQ, areg(D_BX));
|
||||
}
|
||||
}
|
||||
if (!placed)
|
||||
fatal("unsupported assign target "
|
||||
"shape");
|
||||
int k = 0;
|
||||
for (; k + 8 <= fsz; 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 <= fsz) {
|
||||
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 <= fsz) {
|
||||
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 <= fsz) {
|
||||
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 (fu && (fu->kind == TY_STR
|
||||
|| fu->kind == TY_SLICE)) {
|
||||
if (n->op != TK_ASSIGN)
|
||||
|
||||
Reference in New Issue
Block a user