wcc: struct-return float fields via SSE return regs (#171a)
The RETURN twin of #165: a qualifying float-struct was returned GP-only (struct{f64,f64} in AX/DX instead of X0/X1) — value-correct via GP transport but not SysV register-class conformant. Route each float eightbyte through the SSE return cursor (X0/X1) and each integer eightbyte through GP (AX/DX) via independent cursors, at the struct-return SEND and RECV, both stages, reusing struct_float_class verbatim. Closes the temporary tuple-SSE/struct-GP divergence opened across #164/#165. A qualifying struct has >=1 lone f64 so maxalign is 8 and the ABI slot is an 8-multiple — no sub-8 tail — so #169's sized tail is unreachable here and the integer eightbyte uses a full MOVQ (cstage agrees, proven by the f64i32 cs==ww byte-id). f32 / multi-float-per-eightbyte stays GP (deferred #171b); >16B stays sret. Gate-blind and value-correct, so the discriminator is the SEND/RECV register class (MOVSD X0/X1 vs MOVQ AX/DX) — covered by probe 946_structret_run.
This commit is contained in:
@@ -7717,6 +7717,40 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
* excludes them so they fall through to the existing scalar
|
||||
* path rather than emit a stomping MOVQ tail. Sizes >24B also
|
||||
* fall through (sret deferred, same constraint as #4). */
|
||||
/* #171a: float-bearing struct RECEIVE (the return twin of
|
||||
* #165's param recv). cgexpr leaves each float eightbyte in
|
||||
* its SSE return reg (X0,X1 = tuple_sse_seq) and each INT
|
||||
* eightbyte in its INTEGER return reg (AX,DX = tuple_rseq),
|
||||
* on INDEPENDENT cursors per SysV (ref/qbe/amd64/sysv.c retr)
|
||||
* — so a float is read from the next XMM regardless of its
|
||||
* positional eightbyte (struct{f64,i32}: e0←X0, e1←AX). A
|
||||
* qualifying struct's size is maxalign-rounded to a multiple
|
||||
* of 8 (an f64 forces align 8), so every eightbyte is a full
|
||||
* word — the #169 sized tail (MOVL/MOVB) is unreachable here.
|
||||
* struct_float_class gates to qualifying structs; all-int +
|
||||
* f32 fall through to the GP recv below (byte-id / #171b). */
|
||||
if (n->rhs && n->rhs->kind == N_CALL && lu
|
||||
&& lu->kind == TY_STRUCT) {
|
||||
int sclass[2], snb;
|
||||
if ((snb = struct_float_class(lu, sclass)) > 0) {
|
||||
cgexpr(c, n->rhs, *locals);
|
||||
int gpcur = 0, ssecur = 0;
|
||||
for (int e = 0; e < snb; e++) {
|
||||
if (sclass[e]) {
|
||||
ins2(c, A_MOVSD,
|
||||
areg(tuple_sse_seq[ssecur]),
|
||||
amem(D_BP, off + e * 8));
|
||||
ssecur++;
|
||||
} else {
|
||||
ins2(c, A_MOVQ,
|
||||
areg(tuple_rseq[gpcur]),
|
||||
amem(D_BP, off + e * 8));
|
||||
gpcur++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n->rhs && n->rhs->kind == N_CALL && lu
|
||||
&& lu->kind == TY_STRUCT && sz <= 24
|
||||
&& (sz % 8 == 0 || sz % 8 == 1
|
||||
@@ -8290,12 +8324,44 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
ins2(c, A_MOVQ, amem(D_BP, scr + 0),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, scr + 8),
|
||||
areg(D_DX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, scr + 16),
|
||||
areg(D_CX));
|
||||
/* #171a: float-bearing struct RETURN (the return
|
||||
* twin of #165's param recv). A qualifying struct's
|
||||
* float eightbytes ride the SSE return row (X0,X1 =
|
||||
* tuple_sse_seq), its INT eightbytes the INTEGER
|
||||
* return row (AX,DX = tuple_rseq), on INDEPENDENT
|
||||
* cursors per SysV (ref/qbe/amd64/sysv.c retr) — so a
|
||||
* float lands in the next XMM regardless of its
|
||||
* positional eightbyte (struct{f64,i32}: e0→X0, e1→AX,
|
||||
* NOT DX). The scr slot is zero-padded to 24B, so a
|
||||
* full MOVQ on a trailing INT eightbyte reads no
|
||||
* garbage — the #169 sized tail is a RECV-only concern.
|
||||
* struct_float_class gates to qualifying structs (>=1
|
||||
* f64, every eightbyte lone-f64 or pure-INT); all-int +
|
||||
* f32 keep the AX/DX/CX transport (byte-id / #171b). */
|
||||
int sclass[2], snb;
|
||||
if ((snb = struct_float_class(rt, sclass)) > 0) {
|
||||
int gpcur = 0, ssecur = 0;
|
||||
for (int e = 0; e < snb; e++) {
|
||||
if (sclass[e]) {
|
||||
ins2(c, A_MOVSD,
|
||||
amem(D_BP, scr + e * 8),
|
||||
areg(tuple_sse_seq[ssecur]));
|
||||
ssecur++;
|
||||
} else {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, scr + e * 8),
|
||||
areg(tuple_rseq[gpcur]));
|
||||
gpcur++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ins2(c, A_MOVQ, amem(D_BP, scr + 0),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, scr + 8),
|
||||
areg(D_DX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, scr + 16),
|
||||
areg(D_CX));
|
||||
}
|
||||
ins2(c, A_MOVQ, areg(D_BP), areg(D_SP));
|
||||
ins1(c, A_POPQ, areg(D_BP));
|
||||
ins0(c, A_RET);
|
||||
|
||||
Reference in New Issue
Block a user