w6c+wwstage: receive over-cap tuple sret returns at the call site (#10 Fold B)
Fold A made the CALLEE emit an over-capacity tuple return (> 4 GP or > 2
SSE eightbytes) via sret, but every receive site stayed loud-stopped, so
such a fn was not yet usefully callable. Fold B wires the call/receive end
by aligning every receive gate UP to the shared cg_sret_retsize() /
callsretsize() > 0 predicate (never a kind), per Rob's (B) ruling:
- single-var-let `let t = f();` cstage gate generalised from
TY_STRUCT&&>24 to cg_sret_retsize(lt)>0; the let's slot IS the
sret dest, the callee writes the whole tuple there, t.0/t.1 read
by offset. wwstage already keyed callsretsize (verified).
- N_ASSIGN-ident `t = f();` same generalisation; global arm
kept TY_STRUCT-only (a tuple-global has no sret-to-symbol path in
either stage). wwstage grows a tuple-local arm (rettupleof gates
it apart from the >24B-struct recv, which keeps its own path).
- destructure `let (a,b) = f();` and `a,b = f();` — the genuinely
new wiring: the callee sret's into the @sretscr discard slot, then
a copy-out loop moves each element to its binding at the SAME
packed offset the SEND wrote (foff += element size), each at its
natural width (#169); a `_` binding skips its store but advances
foff. Both stages, byte-identical.
- return-forward `return f();` cstage forward gate generalised
to the predicate, reusing cg_sret_forward verbatim. wwstage
already keyed sretretsize (verified).
The escape boundary stays loud: arg-pass `g(f())` fatals identically in
both stages (tuple arg exceeds return-cursor ABI capacity).
Test 799 is the runtime net Fold A deferred (byte-id is blind to a
SEND/RECEIVE layout mismatch): the bytes.cut-shaped ([]u8,[]u8) round-trip
over destructure / single-var-let / reassign / return-forward, each both
RUN under cstage and asserted cs==ww byte-identical. Tests 945 (row F)
and 956 (f64x3) flip from asserting the old over-cap loud-stop to
asserting the now-working sret round-trip. combined.ww amalgams (w6c +
wwdump embed the wcc cgen) regenerated. Unblocks #4 bytes.cut/rcut.
This commit is contained in:
@@ -6971,6 +6971,26 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
// #10 Fold B: over-cap tuple reassign `t = f();`. t's
|
||||
// slot (off) IS the caller-prealloc dest; the callee
|
||||
// writes the whole tuple through hidden RDI. Keys on
|
||||
// callsretsize (the shared sret SSoT) for a tuple-
|
||||
// returning call — rettupleof distinguishes it from a
|
||||
// >24B struct, which keeps its own size-aware recv
|
||||
// below. Mirrors the cstage N_ASSIGN-ident over-cap arm.
|
||||
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
||||
&& n.rhs.kind == nkind.N_CALL) {
|
||||
let rtup: *node = rettupleof(c, n.rhs);
|
||||
if (rtup != nil) {
|
||||
let rscs: i32 = callsretsize(c, n.rhs);
|
||||
if (rscs > 0) {
|
||||
c.sretdestoff = off;
|
||||
cgexpr(c, n.rhs);
|
||||
c.sretdestoff = 0;
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
// Detect str/slice-typed local — assignment must store
|
||||
// both halves (AX=ptr at +0, BX=len at +8) for str,
|
||||
// plus the cap (CX at +16) for slice.
|
||||
|
||||
Reference in New Issue
Block a user