VFPU: Fix vrot with the angle in a destination lane

The cosine is then taken of what vrot wrote to that lane: the sine, or zero.
The IR looked at the sine lane instead of the lane holding the angle, and the
legacy JITs ignored the overlap. The assembler refuses such a vrot, so those
now leave it to the interpreter, and don't pair one with the vrot before it.

Covered by the new cpu/vfpu/vrot test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-09-24 16:22:41 -06:00
1 parent 4ebf9ed037
commit 6fc4eb19df
6 files changed
+45 -6

No files matched your search

+10
View File
@@ -2250,6 +2250,16 @@ namespace MIPSComp
if (vd2 >= 0)
GetVectorRegs(dregs2, sz, vd2);
GetVectorRegs(&sreg, V_Single, vs);
// With the angle in a destination lane, the cosine is taken of what was written there.
// The assembler refuses that, so leave it to the interpreter, and don't pair such a vrot.
for (int i = 0; i < n; i++) {
if (dregs[i] == sreg) {
DISABLE;
}
if (vd2 >= 0 && dregs2[i] == sreg) {
vd2 = -1;
}
}
int imm = (op >> 16) & 0x1f;
+10
View File
@@ -2231,6 +2231,16 @@ namespace MIPSComp {
if (vd2 >= 0)
GetVectorRegs(dregs2, sz, vd2);
GetVectorRegs(&sreg, V_Single, vs);
// With the angle in a destination lane, the cosine is taken of what was written there.
// The assembler refuses that, so leave it to the interpreter, and don't pair such a vrot.
for (int i = 0; i < n; i++) {
if (dregs[i] == sreg) {
DISABLE;
}
if (vd2 >= 0 && dregs2[i] == sreg) {
vd2 = -1;
}
}
int imm = (op >> 16) & 0x1f;
+13 -5
View File
@@ -2335,12 +2335,20 @@ namespace MIPSComp {
}
break;
case 'c':
if (IsOverlapSafe(n, dregs, 1, sreg))
if (IsOverlapSafe(n, dregs, 1, sreg)) {
ir.Write(IROp::FCos, dregs[i], sreg[0]);
else if (dregs[sineLane] == sreg[0])
ir.Write(IROp::FCos, dregs[i], IRVTEMP_0);
else
ir.WriteFC(IROp::SetConstF, dregs[i], 0, 0, 1.0f);
} else {
// The cosine is taken of what the source lane got: the sine, or zero.
int srcLane = 0;
while (dregs[srcLane] != sreg[0]) {
srcLane++;
}
if (broadcastSine || srcLane == sineLane) {
ir.Write(IROp::FCos, dregs[i], IRVTEMP_0);
} else {
ir.WriteFC(IROp::SetConstF, dregs[i], 0, 0, 1.0f);
}
}
break;
}
}
+10
View File
@@ -3759,6 +3759,16 @@ void Jit::Comp_VRot(MIPSOpcode op) {
if (vd2 >= 0)
GetVectorRegs(dregs2, sz, vd2);
GetVectorRegs(&sreg, V_Single, vs);
// With the angle in a destination lane, the cosine is taken of what was written there.
// The assembler refuses that, so leave it to the interpreter, and don't pair such a vrot.
for (int i = 0; i < n; i++) {
if (dregs[i] == sreg) {
DISABLE;
}
if (vd2 >= 0 && dregs2[i] == sreg) {
vd2 = -1;
}
}
// Flush SIMD.
fpr.SimpleRegsV(&sreg, V_Single, 0);
+1
View File
@@ -102,6 +102,7 @@ tests_good = [
"cpu/vfpu/matrix",
"cpu/vfpu/vavg",
"cpu/vfpu/exact",
"cpu/vfpu/vrot",
"cpu/icache/icache",
"cpu/lsu/lsu",
"cpu/lsu/llsc",