wcc: tagged float-variant return packs float bits via X0-spill (#157)
The N_RETURN tagged-pack scalar-variant arm did MOVQ AX,DX, but a float variant's value is in X0 not AX -> packed stale int (broke stof64/stof32 return (f64|invalid|overflow)). Fix: float variant bridges X0->DX via a stack slot (SUBQ $8,SP; MOVQ $0,(SP); MOVSS|MOVSD X0,(SP); MOVQ (SP),DX; ADDQ $8,SP), gated type_isfloat/exprfloatkind. No MOVQ-xmm->gp form exists, hence the spill (715-class, cgreturn-register-pack twin of 715's store-to-slot). Zero-slot-first -> deterministic f32 high-4. AX-independent -> also resolves the multi-variant cs!=ww. Bootstrap-NEUTRAL (compiler has no float-tagged-return). Test 707 +3 rows (f64/f32/multi, slot+8 bit-exact; f32 no-f32-arg to isolate #143). Make test 184/184 incl 990-997 byte-id.
This commit is contained in:
@@ -22060,6 +22060,31 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\tCX, R8\n");
|
||||
emitline("\tMOVQ\tBX, CX\n");
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
} else { if (exprfloatkind(c, rhs) != 0) {
|
||||
// #157: float variant — cgexpr left the value
|
||||
// in X0, not AX. No MOVQ-xmm->gp encoding, so
|
||||
// bridge X0->DX through a stack slot (same arg-
|
||||
// push idiom). Zero the slot first so the f32
|
||||
// case (MOVSS writes only the low 4 bytes)
|
||||
// leaves a deterministic high-4 — cs==ww byte-
|
||||
// id, matching f64's MOVSD which fills all 8.
|
||||
// The AX-independent spill also removes the
|
||||
// stale-AX cs!=ww on multi-variant returns.
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
emitline("\tMOVQ\t$0, (SP)\n");
|
||||
let mov: str = "MOVSD";
|
||||
if (exprfloatkind(c, rhs) == 1) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, (SP)\n");
|
||||
emitline("\tMOVQ\t(SP), DX\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
if (rsz > 16) {
|
||||
emitline("\tMOVQ\t$0, CX\n");
|
||||
};
|
||||
if (rsz > 24) {
|
||||
emitline("\tMOVQ\t$0, R8\n");
|
||||
};
|
||||
} else {
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
// scalar fills DX only. Zero CX / R8 if dst
|
||||
@@ -22070,7 +22095,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
if (rsz > 24) {
|
||||
emitline("\tMOVQ\t$0, R8\n");
|
||||
};
|
||||
};};
|
||||
};};};
|
||||
emitline("\tMOVQ\t$");
|
||||
if (idx < 0) { idx = 0; };
|
||||
emitint(idx: i64);
|
||||
|
||||
@@ -422,6 +422,31 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\tCX, R8\n");
|
||||
emitline("\tMOVQ\tBX, CX\n");
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
} else { if (exprfloatkind(c, rhs) != 0) {
|
||||
// #157: float variant — cgexpr left the value
|
||||
// in X0, not AX. No MOVQ-xmm->gp encoding, so
|
||||
// bridge X0->DX through a stack slot (same arg-
|
||||
// push idiom). Zero the slot first so the f32
|
||||
// case (MOVSS writes only the low 4 bytes)
|
||||
// leaves a deterministic high-4 — cs==ww byte-
|
||||
// id, matching f64's MOVSD which fills all 8.
|
||||
// The AX-independent spill also removes the
|
||||
// stale-AX cs!=ww on multi-variant returns.
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
emitline("\tMOVQ\t$0, (SP)\n");
|
||||
let mov: str = "MOVSD";
|
||||
if (exprfloatkind(c, rhs) == 1) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, (SP)\n");
|
||||
emitline("\tMOVQ\t(SP), DX\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
if (rsz > 16) {
|
||||
emitline("\tMOVQ\t$0, CX\n");
|
||||
};
|
||||
if (rsz > 24) {
|
||||
emitline("\tMOVQ\t$0, R8\n");
|
||||
};
|
||||
} else {
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
// scalar fills DX only. Zero CX / R8 if dst
|
||||
@@ -432,7 +457,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
if (rsz > 24) {
|
||||
emitline("\tMOVQ\t$0, R8\n");
|
||||
};
|
||||
};};
|
||||
};};};
|
||||
emitline("\tMOVQ\t$");
|
||||
if (idx < 0) { idx = 0; };
|
||||
emitint(idx: i64);
|
||||
|
||||
@@ -22060,6 +22060,31 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\tCX, R8\n");
|
||||
emitline("\tMOVQ\tBX, CX\n");
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
} else { if (exprfloatkind(c, rhs) != 0) {
|
||||
// #157: float variant — cgexpr left the value
|
||||
// in X0, not AX. No MOVQ-xmm->gp encoding, so
|
||||
// bridge X0->DX through a stack slot (same arg-
|
||||
// push idiom). Zero the slot first so the f32
|
||||
// case (MOVSS writes only the low 4 bytes)
|
||||
// leaves a deterministic high-4 — cs==ww byte-
|
||||
// id, matching f64's MOVSD which fills all 8.
|
||||
// The AX-independent spill also removes the
|
||||
// stale-AX cs!=ww on multi-variant returns.
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
emitline("\tMOVQ\t$0, (SP)\n");
|
||||
let mov: str = "MOVSD";
|
||||
if (exprfloatkind(c, rhs) == 1) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, (SP)\n");
|
||||
emitline("\tMOVQ\t(SP), DX\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
if (rsz > 16) {
|
||||
emitline("\tMOVQ\t$0, CX\n");
|
||||
};
|
||||
if (rsz > 24) {
|
||||
emitline("\tMOVQ\t$0, R8\n");
|
||||
};
|
||||
} else {
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
// scalar fills DX only. Zero CX / R8 if dst
|
||||
@@ -22070,7 +22095,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
if (rsz > 24) {
|
||||
emitline("\tMOVQ\t$0, R8\n");
|
||||
};
|
||||
};};
|
||||
};};};
|
||||
emitline("\tMOVQ\t$");
|
||||
if (idx < 0) { idx = 0; };
|
||||
emitint(idx: i64);
|
||||
|
||||
Reference in New Issue
Block a user