wcc: float array-element loads to X0 + indexed-float consumer (#119)
cgindex's element-load sites ended in the integer loadopsz (MOVQ/MOVL into AX), with no float branch — so an f32/f64 array element landed in a GPR while the consumer's ADDSD/MOVSD read a stale X0. Add a float- element branch (MOVSS f32 / MOVSD f64 into X0) at all three wwstage cgindex sites (global, baselocal, fallback) and both cstage N_INDEX element-load sites, deriving float-ness from the SAME stamped element tinfo the esz already reads: new elemisfloatc/elemisf32c helpers (mirroring elemissignedc) for ident bases, typeisfloat/typeisf32(n.type_) for N_DOT/N_INDEX bases — never a fresh node-stamp that could hit an unstamped base (#121). The load fix cannot land alone: the wwstage consumer (cgbin/cgcast) classified an indexed float operand as INTEGER (no exprfloatkind N_INDEX arm) and fell to PUSHQ/ADDQ/MOVSXD, while the cstage read the stamped operand type and used ADDSD/CVTTSD2SI. That divergence is pre-existing on master (proven: master cs vs ww already differ on `a[0]+a[1]`), contradicting the original "consumer already expects X0, cs==ww" premise; load-only would leave the wwstage incoherent (value in X0, consumed from AX) and still cs!=ww. So this also adds the exprfloatkind N_INDEX arm — safe because the index-result type_ IS checker-stamped (cgindex reads it for esz), unlike the unstamped-N_MLET case deferred under #121. With both, f64 arrays are runtime-correct and both stages emit byte-identical asm. 946_floatarr_run: f64 element add / trunc / non-adjacent index assert the value + cs==ww; the f32 row asserts cs==ww only — its runtime value is blocked by a SEPARATE store-side bug (f32 array-element store writes AX raw double low-bits instead of CVTSD2SS-narrowed X0), filed as #119-store. Regen w6c/wwdump combined.ww (cgenexpr.ww + cgenutil.ww embedded).
This commit is contained in:
@@ -6414,6 +6414,17 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
||||
break;
|
||||
}
|
||||
/* float element → MOVSS/MOVSD into X0: the consumer's
|
||||
* ADDSD/MOVSD spill machinery already expects X0, but the
|
||||
* integer fldloadop below would leave it in AX and the SSE
|
||||
* side reads stale (#119). Float-ness from esub — the same
|
||||
* type the esz above reads. Twin of the scalar-float global
|
||||
* load at cgen.c:2014. */
|
||||
if (type_isfloat(esub)) {
|
||||
int op = type_isf32(esub) ? A_MOVSS : A_MOVSD;
|
||||
ins2(c, op, amem(D_BX, 0), areg(D_X0));
|
||||
break;
|
||||
}
|
||||
int load_op = fldloadop(esub, esz);
|
||||
ins2(c, load_op, amem(D_BX, 0), areg(D_AX));
|
||||
break;
|
||||
@@ -6456,6 +6467,13 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
||||
break;
|
||||
}
|
||||
/* float element via fallback base → X0 (see Site A, #119). The
|
||||
* base address is in AX; MOVSS/MOVSD reads the element into X0. */
|
||||
if (type_isfloat(esub)) {
|
||||
int op = type_isf32(esub) ? A_MOVSS : A_MOVSD;
|
||||
ins2(c, op, amem(D_AX, 0), areg(D_X0));
|
||||
break;
|
||||
}
|
||||
{
|
||||
int load_op = fldloadop(esub, esz);
|
||||
ins2(c, load_op, amem(D_AX, 0), areg(D_AX));
|
||||
|
||||
Reference in New Issue
Block a user