mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
VFPU: vsrt1-4 order NaN, denormals and signed zero like the hardware
The same ordering as vmin/vmax (sign and magnitude, denormals compare as zero), and on a tie vsrt1/2 keep the lower lane of each pair, vsrt3/4 the upper one. Recorded in cpu/vfpu/specials. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
ed6d13e15f
commit
2c801b8a31
1 file changed
+42
-20
@@ -102,6 +102,27 @@ inline float nanclamp(float f, float lower, float upper)
|
||||
return nanmin(nanmax(f, lower), upper);
|
||||
}
|
||||
|
||||
// The ordering the hardware's min/max family compares with: denormals count as zero, so ±0 and
|
||||
// every denormal tie with each other, and inf/NaN sort by sign and magnitude (-NaN < -inf < finite
|
||||
// < inf < NaN). A tie returns the second operand (cpu/vfpu/minmax_tie, minmax_zero, specials).
|
||||
inline s32 vfpu_order_key(float f) {
|
||||
u32 u;
|
||||
memcpy(&u, &f, sizeof(u));
|
||||
u32 mag = u & 0x7FFFFFFF;
|
||||
if (mag < 0x00800000) {
|
||||
mag = 0;
|
||||
}
|
||||
return (u & 0x80000000) ? -(s32)mag : (s32)mag;
|
||||
}
|
||||
|
||||
inline float vfpu_min(float a, float b) {
|
||||
return vfpu_order_key(a) < vfpu_order_key(b) ? a : b;
|
||||
}
|
||||
|
||||
inline float vfpu_max(float a, float b) {
|
||||
return vfpu_order_key(a) > vfpu_order_key(b) ? a : b;
|
||||
}
|
||||
|
||||
static void ApplyPrefixST(MIPSState *mips, float *r, u32 data, VectorSize size, float invalid = 0.0f) {
|
||||
// Check for no prefix.
|
||||
if (data == 0xe4)
|
||||
@@ -1319,11 +1340,12 @@ namespace MIPSInt
|
||||
u32 tprefixAdd = VFPU_SWIZZLE(1, 0, 3, 2);
|
||||
ApplyPrefixST(mips, t, VFPURewritePrefix(mips, VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
d[0] = std::min(s[0], t[0]);
|
||||
d[1] = std::max(s[1], t[1]);
|
||||
d[2] = std::min(s[2], t[2]);
|
||||
d[3] = std::max(s[3], t[3]);
|
||||
// Each pair is compared as (y, x) and (w, z), so a tie keeps the lower lane; vsrt3 and
|
||||
// vsrt4 compare the other way round and keep the upper one.
|
||||
d[0] = vfpu_min(t[0], s[0]);
|
||||
d[1] = vfpu_max(s[1], t[1]);
|
||||
d[2] = vfpu_min(t[2], s[2]);
|
||||
d[3] = vfpu_max(s[3], t[3]);
|
||||
RetainInvalidSwizzleST(mips, d, sz);
|
||||
ApplyPrefixD(mips, d, sz);
|
||||
WriteVector(mips, d, sz, vd);
|
||||
@@ -1345,11 +1367,11 @@ namespace MIPSInt
|
||||
u32 tprefixAdd = VFPU_SWIZZLE(3, 2, 1, 0);
|
||||
ApplyPrefixST(mips, t, VFPURewritePrefix(mips, VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
d[0] = std::min(s[0], t[0]);
|
||||
d[1] = std::min(s[1], t[1]);
|
||||
d[2] = std::max(s[2], t[2]);
|
||||
d[3] = std::max(s[3], t[3]);
|
||||
// Compared as (w, x) and (z, y), ties keep x and y.
|
||||
d[0] = vfpu_min(t[0], s[0]);
|
||||
d[1] = vfpu_min(t[1], s[1]);
|
||||
d[2] = vfpu_max(s[2], t[2]);
|
||||
d[3] = vfpu_max(s[3], t[3]);
|
||||
RetainInvalidSwizzleST(mips, d, sz);
|
||||
ApplyPrefixD(mips, d, sz);
|
||||
WriteVector(mips, d, sz, vd);
|
||||
@@ -1371,11 +1393,11 @@ namespace MIPSInt
|
||||
u32 tprefixAdd = VFPU_SWIZZLE(1, 0, 3, 2);
|
||||
ApplyPrefixST(mips, t, VFPURewritePrefix(mips, VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
d[0] = std::max(s[0], t[0]);
|
||||
d[1] = std::min(s[1], t[1]);
|
||||
d[2] = std::max(s[2], t[2]);
|
||||
d[3] = std::min(s[3], t[3]);
|
||||
// Compared as (x, y) and (z, w), ties keep y and w.
|
||||
d[0] = vfpu_max(s[0], t[0]);
|
||||
d[1] = vfpu_min(t[1], s[1]);
|
||||
d[2] = vfpu_max(s[2], t[2]);
|
||||
d[3] = vfpu_min(t[3], s[3]);
|
||||
RetainInvalidSwizzleST(mips, d, sz);
|
||||
ApplyPrefixD(mips, d, sz);
|
||||
WriteVector(mips, d, sz, vd);
|
||||
@@ -1397,11 +1419,11 @@ namespace MIPSInt
|
||||
u32 tprefixAdd = VFPU_SWIZZLE(3, 2, 1, 0);
|
||||
ApplyPrefixST(mips, t, VFPURewritePrefix(mips, VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
d[0] = std::max(s[0], t[0]);
|
||||
d[1] = std::max(s[1], t[1]);
|
||||
d[2] = std::min(s[2], t[2]);
|
||||
d[3] = std::min(s[3], t[3]);
|
||||
// Compared as (x, w) and (y, z), ties keep w and z.
|
||||
d[0] = vfpu_max(s[0], t[0]);
|
||||
d[1] = vfpu_max(s[1], t[1]);
|
||||
d[2] = vfpu_min(t[2], s[2]);
|
||||
d[3] = vfpu_min(t[3], s[3]);
|
||||
RetainInvalidSwizzleST(mips, d, sz);
|
||||
ApplyPrefixD(mips, d, sz);
|
||||
WriteVector(mips, d, sz, vd);
|
||||
|
||||
Reference in new issue
Block a user