cstage+test: store .len/.cap on every variadic-pack element (#16)
cstage variadic gather stored only AX (.ptr) per element; .len and .cap read stack residue at the callee. Tagged-union variadic path escaped because cg_widen_tagged_store wrote the full slot — but primitive-type variadics (str..., slice...) silently dropped the trailing fields. Selfhost only uses tagged-union variadics (formattable...) so bootstrap byte-id ww2==ww3==ww4 stayed green; the bug surfaced in worker-strings pre-flight (session 5) on the Hare-faithful concat(strs: str...) shape. Per-element store branch now mirrors selfhost/cmd/wcc/cgenexpr.ww velemstr (AX→slot+0, BX→slot+8) and velemslice (AX→slot+0, BX→slot+8, CX→slot+16). Also swap dname-before-sname allocation order in the variadic-pack frame layout to match wwstage scanlocals + localadd order (cgendecl.ww:507-516 and cgenexpr.ww:2949-2954); without the swap post-fix asm has correct stores at mismatched offsets vs wwstage. Rule-10 alignment: cstage UP to wwstage's already-correct primitive variadic path. 743_variadic_pack pins the contract: asm-presence ≥3 ptr-stores + ≥3 len-stores in caller TEXT on both stages, plus cs-vs-ws cmp -s byte-id per row. 117/117 ok. Bootstrap byte-id ww2==ww3==ww4 holds. Unblocks: lib/bytes contains-variadic, lib/strings sub variadic, and the concat/trim/contains family that c1 shipped non-variadic.
This commit is contained in:
@@ -4302,16 +4302,24 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
? vsu->sub : NULL;
|
||||
int esz = (velem && velem->size)
|
||||
? (int)velem->size : 8;
|
||||
const char *slname = mklabel(c, "vararg_sl");
|
||||
int sloff = localoff(c, &locals,
|
||||
slname, 24, cg_frame);
|
||||
/* Allocate dname BEFORE sname so the
|
||||
* descriptor lives below the element
|
||||
* buffer, matching the wwstage scanlocals
|
||||
* reservation order (rule 10). */
|
||||
int doff = 0;
|
||||
if (nvar > 0) {
|
||||
const char *dname = mklabel(c, "vararg_d");
|
||||
doff = localoff(c, &locals,
|
||||
dname, nvar * esz, cg_frame);
|
||||
}
|
||||
const char *slname = mklabel(c, "vararg_sl");
|
||||
int sloff = localoff(c, &locals,
|
||||
slname, 24, cg_frame);
|
||||
if (nvar > 0) {
|
||||
int v_is_tagged = velem &&
|
||||
tagged_arg_size(velem) > 0;
|
||||
int v_is_str = type_isstr(velem);
|
||||
int v_is_slice = type_isslice(velem);
|
||||
for (int j = 0; j < nvar; j++) {
|
||||
Node *a = args[nfixed + j];
|
||||
int slot = doff + j * esz;
|
||||
@@ -4322,6 +4330,28 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
continue;
|
||||
}
|
||||
cgexpr(c, a, locals);
|
||||
/* str / slice element: cgexpr
|
||||
* returns the full descriptor in
|
||||
* AX/(BX)/(CX); a bare MOVQ AX
|
||||
* stores .ptr only and the
|
||||
* trailing fields read stack
|
||||
* garbage at the callee. */
|
||||
if (v_is_str) {
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, slot));
|
||||
ins2(c, A_MOVQ, areg(D_BX),
|
||||
amem(D_BP, slot + 8));
|
||||
continue;
|
||||
}
|
||||
if (v_is_slice) {
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, slot));
|
||||
ins2(c, A_MOVQ, areg(D_BX),
|
||||
amem(D_BP, slot + 8));
|
||||
ins2(c, A_MOVQ, areg(D_CX),
|
||||
amem(D_BP, slot + 16));
|
||||
continue;
|
||||
}
|
||||
int op = A_MOVQ;
|
||||
if (esz == 1) op = A_MOVB;
|
||||
else if (esz == 4) op = A_MOVL;
|
||||
|
||||
Reference in New Issue
Block a user