diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index ab987cf0..e41bcab9 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -6768,6 +6768,29 @@ cgexpr(Cg *c, Node *n, Local *locals) } break; } + /* #234: over-cap sret STORE into a chained + * value-struct leaf — `o.a.b = wide();` + * (cg_sret_retsize > 0: a >24B struct OR an + * over-cap tuple). Point the callee's hidden + * RDI dest at the leaf slot so it writes the + * WHOLE value there; pre-#234 this fell to + * the scalar tail and stored ONE word (the + * sret dest pointer). cg_sret_dest_off is + * BP-relative ONLY, so a ptr-root/global + * chain needs the runtime RDI-pointer dest + * variant deferred to #234-tail and HARD- + * STOPS loud (rule 7). */ + if (n->rhs && n->rhs->kind == N_CALL + && cg_sret_retsize(leaf_type) > 0) { + if (via_cx) + fatal("#234-tail: over-cap tuple " + "sret store to chained " + "ptr/global dest unsupported"); + cg_sret_dest_off = base_disp + total_off; + cgexpr(c, n->rhs, locals); + cg_sret_dest_off = 0; + break; + } /* TY_STRUCT terminal in the chained-DOT walker: * three rhs shapes — mirror of the single-dot * branch. diff --git a/internal/wwfixture/types.ww b/internal/wwfixture/types.ww index f2e31b01..1fd12037 100644 --- a/internal/wwfixture/types.ww +++ b/internal/wwfixture/types.ww @@ -1,13 +1,13 @@ package wwfixture; def protocolversion: i32 = 1; -def corpuscount: i32 = 1745; +def corpuscount: i32 = 1746; def errorcount: i32 = 346; def compilecount: i32 = 21; def runcount: i32 = 209; -def runexitcount: i32 = 1169; -def nativecount: i32 = 3490; -def corpushash: str = "472974a00552c6b3f5db1fc6b0c1ed128d7554e134880196c833f11f99370f21"; +def runexitcount: i32 = 1170; +def nativecount: i32 = 3492; +def corpushash: str = "6afbab274e0c6d1479a2f0cb6e575b14f5e4ffd25a9cb8a3701307db97d3c489"; type directive = enum i32 { ERROR = 0, diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index b014db1f..cb18c19f 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -12052,6 +12052,31 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { }; return; }; + // #234: over-cap sret STORE into a chained + // value-struct leaf — `o.a.b = wide();` + // (sretretsize > 0: a >24B struct OR an + // over-cap tuple). Point the callee's hidden + // RDI dest at the leaf slot so it writes the + // WHOLE value there; pre-#234 this fell to + // the scalar tail and stored ONE word (the + // sret dest pointer). c.sretdestoff is + // BP-relative ONLY, so a ptr-root/global + // chain needs the runtime RDI-pointer dest + // variant deferred to #234-tail and HARD- + // STOPS loud (rule 7). + if (n.rhs != nil + && n.rhs.kind == syntax.nkind.N_CALL + && sretretsizetn(c, leaftype) > 0) { + if (viacx) { + let m234: str = "#234-tail: over-cap tuple sret store to chained ptr/global dest unsupported\n"; + os.write(2, m234.ptr, m234.len: u64); + os.exit(1); + }; + c.sretdestoff = rootoff + totaloff; + cgexpr(c, n.rhs); + c.sretdestoff = 0; + return; + }; // TY_STRUCT terminal: three rhs shapes: // - N_IDENT: word-copy from the rhs local slot // (cgexpr is skipped — no whole-struct register diff --git a/test/wcc/data/r234_chain_leaf_sret/case.ww b/test/wcc/data/r234_chain_leaf_sret/case.ww new file mode 100644 index 00000000..0d807fd2 --- /dev/null +++ b/test/wcc/data/r234_chain_leaf_sret/case.ww @@ -0,0 +1,29 @@ +//ww:run-exit 0 +// #234 chained-leaf arm: `o.a.b = f()` with a >24B sret-class return +// routes the callee's hidden RDI at the leaf slot. Pre-fix both stages +// fell to the scalar tail and stored ONE word (the sret dest pointer). +package main; +type big = struct { x: i64, y: i64, z: i64, w: i64 }; +type mid = struct { pad: i64, b: big }; +type outer = struct { a: mid }; + +fn f() big = { + let r: big; + r.x = 11; + r.y = 22; + r.z = 33; + r.w = 44; + return r; +}; + +export fn main() i32 = { + let o: outer; + o.a.pad = 7; + o.a.b = f(); + if (o.a.pad != 7) { return 1; }; + if (o.a.b.x != 11) { return 2; }; + if (o.a.b.y != 22) { return 3; }; + if (o.a.b.z != 33) { return 4; }; + if (o.a.b.w != 44) { return 5; }; + return 0; +};