w6c+wwstage: store over-cap tuple sret into local field/index (#234)
The STORE-twin of the Fold-B over-cap-tuple sret RECEIVE (a937d67). Fold B
wired single-var-let / destructure / reassign / return-forward to receive a
> 4-eightbyte (sret) tuple-returning call, but a FIELD or INDEXED-lvalue
dest stayed unwired: the store dropped the callee's sret body (a truncated
MOVQ through a stale RDI) — a silent miscompile, gate-blind because the
bootstrap never field-stores a wide tuple.
Per Rob's ruling A (one class, one commit): convert the silent miscompile
into either a CORRECT store or a LOUD stop, never a fall-through.
- cstage cmd/w6c/cgen.c: the struct-field N_DOT store and the N_INDEX
lvalue store each gain an arm keyed on cg_sret_retsize(dest) > 0 &&
rhs == N_CALL. A LOCAL dest (BP-relative, not via_ptr / global) sets
cg_sret_dest_off so the callee's hidden RDI writes the WHOLE tuple
straight into the slot — field: boff + foff; indexed: boff + cidx*esz
(a CONSTANT index into a local value array, the only indexed form whose
dest is a static BP offset). Every other dest fatals "#234-tail".
- wwstage selfhost/cmd/wcc/cgenexpr.ww: symmetric (rule 10). The direct
struct-local field branch sets c.sretdestoff = lc.off + fi.foff; the
via_ptr branch, the global branch, and the N_INDEX arm hard-stop loud
with the same #234-tail diagnostic. The field branches key on
sretretsize(fi.tnode) > 0 (fi.tnode is a real type-AST node). The
N_INDEX arm keys its ENTRY on callsretsize(c, n.rhs) > 0 — the
callee-return-type SSoT (cgenutil.ww) the receive sites use — NOT on
sretretsize(elemtn): elemtn is only a type node for an N_IDENT base, a
VALUE node for an N_DOT base (`s.arr[i]`) / chained (`a[i][k]`), which
fell to sretretsize=0 and let those forms drop SILENTLY through to the
truncating store. The callee return type equals the dest-element type
(checker-guaranteed), so the verdict is byte-identical to cstage's
cg_sret_retsize, and the base-shape split then loud-stops every
non-local-array form, base-kind-independent.
Deferred (#234-tail): a via_ptr field (`p.f`), a global field (`g.f`), an
N_DOT-base index (`s.arr[i]`), a chained index (`a[i][k]`), and a runtime /
slice / pointer index all need a runtime RDI-pointer dest, which
cg_sret_dest_off (BP-relative only) can't express — they hard-error loud
(rule 7), never a truncating store.
Depends on #237 (committed first): the wwstage struct-field slot for a
tuple field is only correctly sized with that fix, so the struct-field arm
is byte-id-symmetric here.
Test 940: indexed-on-local and local-struct-field rows RUN on both stages
(exit 0) AND assert cs==ww byte-id; readback via a raw pointer
(`(&dest):*int; p[i]`) since a tuple-element read `dest.N` is a separate gap
(#238). Builderr rows assert the via_ptr / global / runtime-index /
N_DOT-base / chained-index forms loud-stop with #234-tail on BOTH drivers
(the N_DOT-base + chained rows are the regression witnesses for the wwstage
silent-store gap closed by the callsretsize re-key). The bootstrap exercises
no such store, so the w6c/wwdump combined amalgams regen with no asm change
(byte-id-neutral bootstrap; the new hard-error never fires self-compiling).
This commit is contained in:
@@ -3468,6 +3468,32 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* #234: over-cap sret STORE into a struct field —
|
||||
* `s.f = wide();` where f's type returns via sret
|
||||
* (cg_sret_retsize > 0: a >24B struct OR an over-cap
|
||||
* tuple — Fold A made the callee sret it). The STORE-
|
||||
* twin of the Fold-B sret RECEIVE (a937d67): point the
|
||||
* callee's hidden RDI dest straight at the field slot
|
||||
* (cg_sret_dest_off) so it writes the WHOLE value there.
|
||||
* Without this the generic scalar store below emits a
|
||||
* truncated `MOVQ AX, off(BP)` and silently drops the
|
||||
* sret body. cg_sret_dest_off is BP-relative ONLY, so
|
||||
* this covers a LOCAL struct base; a via_ptr (`p.f`) or
|
||||
* global base needs the runtime RDI-pointer dest variant
|
||||
* deferred to #234-tail and HARD-STOPS loud (rule 7 —
|
||||
* never fall through to the truncating store). */
|
||||
if (n->op == TK_ASSIGN && n->rhs
|
||||
&& n->rhs->kind == N_CALL
|
||||
&& cg_sret_retsize(f->type) > 0) {
|
||||
if (via_ptr || is_global || boff == 0)
|
||||
fatal("#234-tail: over-cap tuple "
|
||||
"sret store to non-local dest "
|
||||
"unsupported");
|
||||
cg_sret_dest_off = boff + foff;
|
||||
cgexpr(c, n->rhs, locals);
|
||||
cg_sret_dest_off = 0;
|
||||
break;
|
||||
}
|
||||
/* struct-typed field, three rhs shapes:
|
||||
* - N_IDENT: word-copy from the rhs slot directly
|
||||
* onto the destination field. cgexpr cannot
|
||||
@@ -4560,6 +4586,32 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* #234: over-cap sret STORE into an indexed lvalue —
|
||||
* `arr[i] = wide();` STORE-twin of the Fold-B sret RECEIVE
|
||||
* (a937d67). cg_sret_dest_off is a STATIC BP-relative
|
||||
* offset, so only a CONSTANT index into a LOCAL value array
|
||||
* yields a static dest slot (boff + idx*esz) the callee can
|
||||
* sret straight into. Every other indexed form — runtime
|
||||
* index, slice/ptr base, global base — needs the runtime
|
||||
* RDI-pointer dest variant deferred to #234-tail and HARD-
|
||||
* STOPS loud (rule 7 — never the truncating store below). */
|
||||
if (n->op == TK_ASSIGN && n->rhs
|
||||
&& n->rhs->kind == N_CALL
|
||||
&& esub && cg_sret_retsize(esub) > 0) {
|
||||
int cidx = (n->lhs->rhs
|
||||
&& n->lhs->rhs->kind == N_INTLIT)
|
||||
? (int)n->lhs->rhs->uval : -1;
|
||||
int sboff = (base->kind == N_IDENT)
|
||||
? localfind(locals, base->str) : 0;
|
||||
if (!is_arr || cidx < 0 || sboff == 0)
|
||||
fatal("#234-tail: over-cap tuple sret "
|
||||
"store to non-local dest "
|
||||
"unsupported");
|
||||
cg_sret_dest_off = sboff + cidx * esz;
|
||||
cgexpr(c, n->rhs, locals);
|
||||
cg_sret_dest_off = 0;
|
||||
break;
|
||||
}
|
||||
if ((is_arr || is_sl || is_ptr) && n->op == TK_ASSIGN) {
|
||||
cgexpr(c, n->rhs, locals); /* AX=ptr (BX=len,CX=cap if str) */
|
||||
/* str/slice: stash cap+len so all three store
|
||||
|
||||
Reference in New Issue
Block a user