mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-30 18:49:13 +02:00
Merge pull request #6382 from unknownbrackets/armjit-minor
Fix vmin/vmax to follow the PSP's rules
This commit is contained in:
@@ -742,25 +742,51 @@ namespace MIPSComp
|
||||
case 27: //VFPU3
|
||||
switch ((op >> 23) & 7) {
|
||||
case 2: // vmin
|
||||
{
|
||||
VCMP(fpr.V(sregs[i]), fpr.V(tregs[i]));
|
||||
VMRS_APSR();
|
||||
// TODO: Technically should use NaN sign bit.
|
||||
FixupBranch skipNAN = B_CC(CC_VC);
|
||||
VMOV(SCRATCHREG1, fpr.V(sregs[i]));
|
||||
VMOV(SCRATCHREG2, fpr.V(tregs[i]));
|
||||
// If both are negative, we reverse the comparison. We want the highest mantissa then.
|
||||
// Also, between -NAN and -5.0, we want -NAN to be less.
|
||||
TST(SCRATCHREG1, SCRATCHREG2);
|
||||
SetCC(CC_MI);
|
||||
CMP(SCRATCHREG2, SCRATCHREG1);
|
||||
SetCC(CC_PL);
|
||||
CMP(SCRATCHREG1, SCRATCHREG2);
|
||||
SetCC(CC_AL);
|
||||
SetJumpTarget(skipNAN);
|
||||
SetCC(CC_LT);
|
||||
VMOV(fpr.V(tempregs[i]), fpr.V(sregs[i]));
|
||||
SetCC(CC_GE);
|
||||
VMOV(fpr.V(tempregs[i]), fpr.V(tregs[i]));
|
||||
SetCC(CC_AL);
|
||||
break;
|
||||
}
|
||||
case 3: // vmax
|
||||
{
|
||||
VCMP(fpr.V(tregs[i]), fpr.V(sregs[i]));
|
||||
VMRS_APSR();
|
||||
// TODO: Technically should use NaN sign bit.
|
||||
FixupBranch skipNAN = B_CC(CC_VC);
|
||||
VMOV(SCRATCHREG1, fpr.V(sregs[i]));
|
||||
VMOV(SCRATCHREG2, fpr.V(tregs[i]));
|
||||
// If both are negative, we reverse the comparison. We want the lowest mantissa then.
|
||||
// Also, between -NAN and -5.0, we want -5.0 to be greater.
|
||||
TST(SCRATCHREG2, SCRATCHREG1);
|
||||
SetCC(CC_MI);
|
||||
CMP(SCRATCHREG1, SCRATCHREG2);
|
||||
SetCC(CC_PL);
|
||||
CMP(SCRATCHREG2, SCRATCHREG1);
|
||||
SetCC(CC_AL);
|
||||
SetJumpTarget(skipNAN);
|
||||
SetCC(CC_LT);
|
||||
VMOV(fpr.V(tempregs[i]), fpr.V(sregs[i]));
|
||||
SetCC(CC_GE);
|
||||
VMOV(fpr.V(tempregs[i]), fpr.V(tregs[i]));
|
||||
SetCC(CC_AL);
|
||||
break;
|
||||
}
|
||||
case 6: // vsge
|
||||
DISABLE; // pending testing
|
||||
VCMP(fpr.V(tregs[i]), fpr.V(sregs[i]));
|
||||
|
||||
+12
-1
@@ -893,7 +893,18 @@ namespace MIPSInt
|
||||
switch (op & 0x3f)
|
||||
{
|
||||
case 12: FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
|
||||
case 13: FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s
|
||||
case 13: //trunc.w.s
|
||||
if (F(fs) >= 0.0f) {
|
||||
FsI(fd) = (int)floorf(F(fs));
|
||||
// Overflow, but it was positive.
|
||||
if (FsI(fd) == -2147483648) {
|
||||
FsI(fd) = 2147483647;
|
||||
}
|
||||
} else {
|
||||
// Overflow happens to be the right value anyway.
|
||||
FsI(fd) = (int)ceilf(F(fs));
|
||||
}
|
||||
break;
|
||||
case 14: FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s
|
||||
case 15: FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s
|
||||
}
|
||||
|
||||
+41
-13
@@ -1530,26 +1530,54 @@ namespace MIPSInt
|
||||
int cond = op&15;
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int numElements = GetNumVectorElements(sz);
|
||||
float s[4];
|
||||
float t[4];
|
||||
float d[4];
|
||||
ReadVector(s, sz, vs);
|
||||
ApplySwizzleS(s, sz);
|
||||
ReadVector(t, sz, vt);
|
||||
ApplySwizzleT(t, sz);
|
||||
|
||||
union FloatBits {
|
||||
float f[4];
|
||||
u32 u[4];
|
||||
int i[4];
|
||||
};
|
||||
|
||||
FloatBits s;
|
||||
FloatBits t;
|
||||
FloatBits d;
|
||||
ReadVector(s.f, sz, vs);
|
||||
ApplySwizzleS(s.f, sz);
|
||||
ReadVector(t.f, sz, vt);
|
||||
ApplySwizzleT(t.f, sz);
|
||||
|
||||
// If both are zero, take t's sign.
|
||||
// TODO: Otherwise: -NAN < -INF < real < INF < NAN
|
||||
// Otherwise: -NAN < -INF < real < INF < NAN (higher mantissa is farther from 0.)
|
||||
|
||||
switch ((op >> 23) & 3) {
|
||||
case 2: // vmin
|
||||
for (int i = 0; i < numElements; i++) {
|
||||
d[i] = my_isnan(t[i]) ? s[i] : (my_isnan(s[i]) ? t[i] : std::min(t[i], s[i]));
|
||||
if (my_isnanorinf(s.f[i]) || my_isnanorinf(t.f[i])) {
|
||||
// If both are negative, we flip the comparison (not two's compliment.)
|
||||
if (s.i[i] < 0 && t.i[i] < 0) {
|
||||
// If at least one side is NAN, we take the highest mantissa bits.
|
||||
d.i[i] = std::max(t.i[i], s.i[i]);
|
||||
} else {
|
||||
// Otherwise, we take the lowest value (negative or lowest mantissa.)
|
||||
d.i[i] = std::min(t.i[i], s.i[i]);
|
||||
}
|
||||
} else {
|
||||
d.f[i] = std::min(t.f[i], s.f[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: // vmax
|
||||
for (int i = 0; i < numElements; i++)
|
||||
d[i] = my_isnan(t[i]) ? t[i] : (my_isnan(s[i]) ? s[i] : std::max(t[i], s[i]));
|
||||
for (int i = 0; i < numElements; i++) {
|
||||
// This is the same logic as vmin, just reversed.
|
||||
if (my_isnanorinf(s.f[i]) || my_isnanorinf(t.f[i])) {
|
||||
if (s.i[i] < 0 && t.i[i] < 0) {
|
||||
d.i[i] = std::min(t.i[i], s.i[i]);
|
||||
} else {
|
||||
d.i[i] = std::max(t.i[i], s.i[i]);
|
||||
}
|
||||
} else {
|
||||
d.f[i] = std::max(t.f[i], s.f[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(CPU,0,"unknown min/max op %d", cond);
|
||||
@@ -1557,8 +1585,8 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
return;
|
||||
}
|
||||
ApplyPrefixD(d, sz);
|
||||
WriteVector(d, sz, vd);
|
||||
ApplyPrefixD(d.f, sz);
|
||||
WriteVector(d.f, sz, vd);
|
||||
PC += 4;
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user