cgen: tuple receive spills f64 word from XMM, not integer reg (both stages, #105)
A (f64,i64)/(i64,f64) tuple returns its f64 word in X0 (the SSE return reg) and its integer word in an integer reg (tuple_rseq AX/DX). All three tuple-from-call receive forms — single-var (cglet), destructure (N_MLET), reassign (N_MASSIGN) — share the #83 tuple_rseq cursor and all spilled the f64 word via MOVQ from the integer cursor; that reg holds garbage (the float is in X0), and #103-FACE-Z's field read (MOVSD slot,X0) then reads it. A single-return callee masked it (a float-literal return leaves the f64 bits in AX, and X0 stays live); a branched callee with a non- literal f64 word has an inner CALL clobber AX, exposing the corruption. Make every receive spill class-aware: an f64/f32 word spills MOVSD/MOVSS from X0 (the single SSE return reg, which survives the reg->mem stores regardless of the word's position), an integer word spills MOVQ from its tuple_rseq reg as before. cstage applies this at all three inline sites (cglet, N_MLET, N_MASSIGN); wwstage at the cglet branch and in the shared tupstore helper (covering cgmlet and cgmassign). The integer/str/slice path is byte-identical to before, so bootstrap codegen is unperturbed. Multi-float tuples collide on X0 at the RETURN (#107), out of scope here.
This commit is contained in:
@@ -6672,13 +6672,33 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
ins2(c, A_MOVQ, areg(D_CX), amem(D_BP, off + 16));
|
||||
break;
|
||||
}
|
||||
/* 2-tuple initialiser from a function call: SysV returns
|
||||
* a 16-byte aggregate in (AX, DX). Store both into the
|
||||
* tuple slot. */
|
||||
/* 2-tuple initialiser from a function call. An integer word
|
||||
* rides its tuple_rseq[] reg (AX, DX); a single f64/f32 word
|
||||
* rides X0, the SSE return reg — the RETURN leaves the float
|
||||
* in X0 and pushes garbage through that word's integer slot,
|
||||
* so a blanket MOVQ-from-integer spill stores garbage and the
|
||||
* #103-FACE-Z field read (MOVSD-from-slot) reads it (#105).
|
||||
* Spill each word from its real class. Multi-float tuples
|
||||
* collide on X0 at the RETURN (#107), out of scope here. */
|
||||
if (n->rhs && lu && lu->kind == TY_TUPLE && sz == 16) {
|
||||
Tparam *p0 = lu->params;
|
||||
Tparam *p1 = p0 ? p0->next : NULL;
|
||||
int f0_f32 = 0, f1_f32 = 0;
|
||||
int e0_f = p0 && fld_isfloat(p0->type, &f0_f32);
|
||||
int e1_f = p1 && fld_isfloat(p1->type, &f1_f32);
|
||||
cgexpr(c, n->rhs, *locals);
|
||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off + 0));
|
||||
ins2(c, A_MOVQ, areg(D_DX), amem(D_BP, off + 8));
|
||||
if (e0_f)
|
||||
ins2(c, f0_f32 ? A_MOVSS : A_MOVSD,
|
||||
areg(D_X0), amem(D_BP, off + 0));
|
||||
else
|
||||
ins2(c, A_MOVQ, areg(tuple_rseq[0]),
|
||||
amem(D_BP, off + 0));
|
||||
if (e1_f)
|
||||
ins2(c, f1_f32 ? A_MOVSS : A_MOVSD,
|
||||
areg(D_X0), amem(D_BP, off + 8));
|
||||
else
|
||||
ins2(c, A_MOVQ, areg(tuple_rseq[1]),
|
||||
amem(D_BP, off + 8));
|
||||
break;
|
||||
}
|
||||
/* 32B tuple initialiser for `(scalar, str)` / `(str, scalar)`.
|
||||
@@ -7563,8 +7583,18 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
ins2(c, A_MOVQ, areg(tuple_rseq[cur + 2]),
|
||||
amem(D_BP, off + 16)); /* .cap */
|
||||
} else {
|
||||
ins2(c, A_MOVQ, areg(tuple_rseq[cur]),
|
||||
amem(D_BP, off));
|
||||
/* #105: an f64/f32 element rides X0, not its
|
||||
* integer cursor reg — MOVSD/MOVSS it, else
|
||||
* the slot gets garbage and the FACE-Z field
|
||||
* read sees it. X0 survives the reg->mem
|
||||
* stores. Single-float scope; #107 is multi. */
|
||||
int e_f32 = 0;
|
||||
if (fld_isfloat(t, &e_f32))
|
||||
ins2(c, e_f32 ? A_MOVSS : A_MOVSD,
|
||||
areg(D_X0), amem(D_BP, off));
|
||||
else
|
||||
ins2(c, A_MOVQ, areg(tuple_rseq[cur]),
|
||||
amem(D_BP, off));
|
||||
}
|
||||
cur += tuple_ebytes(wide);
|
||||
}
|
||||
@@ -7620,8 +7650,16 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
ins2(c, A_MOVQ, areg(tuple_rseq[cur + 2]),
|
||||
amem(D_BP, off + 16)); /* .cap */
|
||||
} else {
|
||||
ins2(c, A_MOVQ, areg(tuple_rseq[cur]),
|
||||
amem(D_BP, off));
|
||||
/* #105: f64/f32 element rides X0 (SSE),
|
||||
* not its integer cursor reg — see N_MLET. */
|
||||
int e_f32 = 0;
|
||||
if (fld_isfloat(et, &e_f32))
|
||||
ins2(c, e_f32 ? A_MOVSS : A_MOVSD,
|
||||
areg(D_X0), amem(D_BP, off));
|
||||
else
|
||||
ins2(c, A_MOVQ,
|
||||
areg(tuple_rseq[cur]),
|
||||
amem(D_BP, off));
|
||||
}
|
||||
}
|
||||
cur += tuple_ebytes(wide);
|
||||
|
||||
Reference in New Issue
Block a user