irjit: Handle vrot overlap more correctly.

Sine ignores overlap, cosine does not.
This commit is contained in:
Unknown W. Brackets committed 2022-10-29 22:25:25 -07:00
1 parent 1fb7fe02b0
commit 3f997518f3
3 files changed
+50 -8

No files matched your search

+28 -7
View File
@@ -1848,33 +1848,54 @@ namespace MIPSComp {
int imm = (op >> 16) & 0x1f;
VectorSize sz = GetVecSize(op);
int n = GetNumVectorElements(sz);
int sineLane = (imm >> 2) & 3;
int cosineLane = imm & 3;
bool negSin = (imm & 0x10) ? true : false;
bool broadcastSine = sineLane == cosineLane;
char d[4] = { '0', '0', '0', '0' };
if (((imm >> 2) & 3) == (imm & 3)) {
if (broadcastSine) {
for (int i = 0; i < 4; i++)
d[i] = 's';
}
d[(imm >> 2) & 3] = 's';
d[imm & 3] = 'c';
d[sineLane] = 's';
d[cosineLane] = 'c';
u8 dregs[4];
GetVectorRegs(dregs, sz, vd);
u8 sreg[1];
GetVectorRegs(sreg, V_Single, vs);
// If there's overlap, sin is calculated without it, but cosine uses the result.
// This corresponds with prefix handling, where cosine doesn't get in prefixes.
if (broadcastSine || !IsOverlapSafe(n, dregs, 1, sreg)) {
ir.Write(IROp::FSin, IRVTEMP_0, sreg[0]);
if (negSin)
ir.Write(IROp::FNeg, IRVTEMP_0, IRVTEMP_0);
}
for (int i = 0; i < n; i++) {
switch (d[i]) {
case '0':
ir.Write(IROp::SetConstF, dregs[i], ir.AddConstantFloat(0.0f));
break;
case 's':
ir.Write(IROp::FSin, dregs[i], sreg[0]);
if (negSin) {
ir.Write(IROp::FNeg, dregs[i], dregs[i]);
if (broadcastSine || !IsOverlapSafe(n, dregs, 1, sreg)) {
ir.Write(IROp::FMov, dregs[i], IRVTEMP_0);
} else {
ir.Write(IROp::FSin, dregs[i], sreg[0]);
if (negSin) {
ir.Write(IROp::FNeg, dregs[i], dregs[i]);
}
}
break;
case 'c':
ir.Write(IROp::FCos, dregs[i], sreg[0]);
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.Write(IROp::SetConstF, dregs[i], ir.AddConstantFloat(1.0f));
break;
}
}
+18 -1
View File
@@ -1607,7 +1607,24 @@ namespace MIPSInt
} else {
d[sineLane] = sine;
}
d[cosineLane] = cosine;
if (((vd >> 2) & 7) == ((vs >> 2) & 7)) {
u8 dregs[4]{};
GetVectorRegs(dregs, sz, vd);
// Calculate cosine based on sine/zero result.
bool written = false;
for (int i = 0; i < 4; i++) {
if (vs == dregs[i]) {
d[cosineLane] = vfpu_cos(d[i]);
written = true;
break;
}
}
if (!written)
d[cosineLane] = cosine;
} else {
d[cosineLane] = cosine;
}
// D prefix works, just not for x.
currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] &= 0xFFEFC;
+4
View File
@@ -343,6 +343,10 @@ void WriteMatrix(const float *rd, MatrixSize size, int reg) {
}
int GetVectorOverlap(int vec1, VectorSize size1, int vec2, VectorSize size2) {
// Different matrices? Can't overlap, return early.
if (((vec1 >> 2) & 7) != ((vec2 >> 2) & 7))
return 0;
int n1 = GetNumVectorElements(size1);
int n2 = GetNumVectorElements(size2);
u8 regs1[4];