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:
@@ -20015,7 +20015,8 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
};
|
||||
|
||||
// Thin wrapper preserving the BP-rel call shape used by cglet,
|
||||
// cgreturn, and cgassign N_IDENT-lhs N_STRUCTLIT.
|
||||
// cgreturn, cgassign N_IDENT-lhs N_STRUCTLIT, and the C1.25
|
||||
// @placescr materialise (cg_structlit_fill_bp's named twin).
|
||||
fn cgstructlitfillbp(c: *cgen, si: *structinfo, lit: *node, bpoff: i32) void = {
|
||||
if (si == nil) { return; };
|
||||
cgstructlitfill(c, si, lit, 0, 0, "", bpoff);
|
||||
@@ -29029,12 +29030,152 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
os.write(2, mt.ptr, mt.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// 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 a SILENT
|
||||
// no-op; C1 made it loud; this wires it
|
||||
// (loud-first, wire-next). Compound on an
|
||||
// aggregate is meaningless and stays loud.
|
||||
// Mirror of the cstage cgen.c C1.25 arm.
|
||||
if (fu.kind == tykind.TY_STRUCT
|
||||
|| fu.kind == tykind.TY_ARRAY
|
||||
|| fu.kind == tykind.TY_TUPLE) {
|
||||
let ma: str = "assign-resolver: aggregate field not wired (rule-7)\n";
|
||||
os.write(2, ma.ptr, ma.len: u64);
|
||||
os.exit(1);
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
let mac: str = "assign-resolver: compound on aggregate field not wired (rule-7)\n";
|
||||
os.write(2, mac.ptr, mac.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_CALL) {
|
||||
// sret-class needs a runtime-RDI dest
|
||||
// (the #234-tail deferral); the ≤24B
|
||||
// reg-return receive is task #24. The
|
||||
// callee return type equals the field
|
||||
// type (checker-guaranteed), so
|
||||
// callsretsize gives cstage's
|
||||
// cg_sret_retsize(ft) verdict.
|
||||
if (callsretsize(c, n.rhs) > 0) {
|
||||
let mas: str = "assign-resolver: sret call into aggregate field unwired (#234-tail/rule-7)\n";
|
||||
os.write(2, mas.ptr, mas.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let ma24: str = "assign-resolver: call result into aggregate field unwired (task #24/rule-7)\n";
|
||||
os.write(2, ma24.ptr, ma24.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
let placed: bool = false;
|
||||
let isslit: bool = false;
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_STRUCTLIT
|
||||
&& fu.kind == tykind.TY_STRUCT) {
|
||||
isslit = true;
|
||||
};
|
||||
};
|
||||
if (isslit) {
|
||||
// @placescr — FRESH slot PER USE (the
|
||||
// @slicescr discipline via localalloc,
|
||||
// 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.
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (ft.kind == tykind.TY_NAMED) {
|
||||
sname = ft.name;
|
||||
};
|
||||
let si: *structinfo = nil;
|
||||
if (sname.len > 0) {
|
||||
si = structlookup(c, sname);
|
||||
};
|
||||
if (si == nil) {
|
||||
// wwstage-only bail: the fill is
|
||||
// structinfo-keyed, so an anonymous-
|
||||
// struct field type has no registry
|
||||
// entry (cstage fills from Type
|
||||
// directly). Loud, rule 7.
|
||||
let man: str = "assign-resolver: structlit field layout unresolved (rule-7)\n";
|
||||
os.write(2, man.ptr, man.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let scr: i32 = localalloc(c, "@placescr", fsz, nil);
|
||||
cgstructlitfillbp(c, si, n.rhs, scr);
|
||||
placed = cgplaceaddr(c, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(scr: i64);
|
||||
emitline("(BP), SI\n");
|
||||
};
|
||||
} 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, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
if (!aggargsrcaddr(c, n.rhs, "SI")) {
|
||||
let mar: str = "assign-resolver: aggregate rhs shape unwired (rule-7)\n";
|
||||
os.write(2, mar.ptr, mar.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
};
|
||||
};
|
||||
if (!placed) {
|
||||
let mau: str = "unsupported assign target shape\n";
|
||||
os.write(2, mau.ptr, mau.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= fsz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= fsz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= fsz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= fsz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 1;
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
let fstrsl: bool = false;
|
||||
|
||||
Reference in New Issue
Block a user