Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge pull request #152 from Tilka/float_stuff

Fix IsQNAN() and reduce code duplication
  • Loading branch information...
commit f4012638672472afdbd9956229f273a18a77fd77 2 parents 2632db8 + 16885d0
Pierre Bourdon authored
39  Source/Core/Common/MathUtil.h
@@ -20,16 +20,18 @@ inline void Clamp(T* val, const T& min, const T& max)
20 20
 		*val = max;
21 21
 }
22 22
 
  23
+// The most significant bit of the fraction is an is-quiet bit on all architectures we care about.
23 24
 
24 25
 static const u64 DOUBLE_SIGN = 0x8000000000000000ULL,
25  
-	DOUBLE_EXP  = 0x7FF0000000000000ULL,
26  
-	DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL,
27  
-	DOUBLE_ZERO = 0x0000000000000000ULL;
  26
+                 DOUBLE_EXP  = 0x7FF0000000000000ULL,
  27
+                 DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL,
  28
+                 DOUBLE_ZERO = 0x0000000000000000ULL,
  29
+                 DOUBLE_QBIT = 0x0008000000000000ULL;
28 30
 
29 31
 static const u32 FLOAT_SIGN = 0x80000000,
30  
-	FLOAT_EXP  = 0x7F800000,
31  
-	FLOAT_FRAC = 0x007FFFFF,
32  
-	FLOAT_ZERO = 0x00000000;
  32
+                 FLOAT_EXP  = 0x7F800000,
  33
+                 FLOAT_FRAC = 0x007FFFFF,
  34
+                 FLOAT_ZERO = 0x00000000;
33 35
 
34 36
 union IntDouble {
35 37
 	double d;
@@ -40,34 +42,41 @@ inline void Clamp(T* val, const T& min, const T& max)
40 42
 	u32 i;
41 43
 };
42 44
 
  45
+inline bool IsINF(double d)
  46
+{
  47
+	IntDouble x; x.d = d;
  48
+	return (x.i & ~DOUBLE_SIGN) == DOUBLE_EXP;
  49
+}
  50
+
43 51
 inline bool IsNAN(double d)
44 52
 {
45 53
 	IntDouble x; x.d = d;
46  
-	return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
47  
-			 ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) );
  54
+	return ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
  55
+	       ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO);
48 56
 }
49 57
 
50 58
 inline bool IsQNAN(double d)
51 59
 {
52 60
 	IntDouble x; x.d = d;
53  
-	return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
54  
-		     ((x.i & 0x0007fffffffffffULL) == 0x000000000000000ULL) &&
55  
-		     ((x.i & 0x000800000000000ULL) == 0x000800000000000ULL) );
  61
+	return ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
  62
+	       ((x.i & DOUBLE_QBIT) == DOUBLE_QBIT);
56 63
 }
57 64
 
58 65
 inline bool IsSNAN(double d)
59 66
 {
60 67
 	IntDouble x; x.d = d;
61  
-	return( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
62  
-			((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) &&
63  
-			((x.i & 0x0008000000000000ULL) == DOUBLE_ZERO) );
  68
+	return ((x.i & DOUBLE_EXP) == DOUBLE_EXP) &&
  69
+	       ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) &&
  70
+	       ((x.i & DOUBLE_QBIT) == DOUBLE_ZERO);
64 71
 }
65 72
 
66 73
 inline float FlushToZero(float f)
67 74
 {
68 75
 	IntFloat x; x.f = f;
69 76
 	if ((x.i & FLOAT_EXP) == 0)
  77
+	{
70 78
 		x.i &= FLOAT_SIGN;  // turn into signed zero
  79
+	}
71 80
 	return x.f;
72 81
 }
73 82
 
@@ -75,7 +84,9 @@ inline double FlushToZero(double d)
75 84
 {
76 85
 	IntDouble x; x.d = d;
77 86
 	if ((x.i & DOUBLE_EXP) == 0)
  87
+	{
78 88
 		x.i &= DOUBLE_SIGN;  // turn into signed zero
  89
+	}
79 90
 	return x.d;
80 91
 }
81 92
 
3  Source/Core/Core/PowerPC/Gekko.h
@@ -410,7 +410,8 @@
410 410
 		u32 VXSOFT  : 1;
411 411
 		// reserved
412 412
 		u32         : 1;
413  
-		// Floating point result flags (not sticky)
  413
+		// Floating point result flags (includes FPCC) (not sticky)
  414
+		// from more to less significand: class, <, >, =, ?
414 415
 		u32 FPRF    : 5;
415 416
 		// Fraction inexact (not sticky)
416 417
 		u32 FI      : 1;
3  Source/Core/Core/PowerPC/Interpreter/Interpreter.h
@@ -326,6 +326,9 @@ class Interpreter : public CPUCoreBase
326 326
 	Interpreter(const Interpreter &);
327 327
 	Interpreter & operator=(const Interpreter &);
328 328
 
  329
+	static void Helper_FloatCompareOrdered(UGeckoInstruction _inst, double a, double b);
  330
+	static void Helper_FloatCompareUnordered(UGeckoInstruction _inst, double a, double b);
  331
+
329 332
 	// TODO: These should really be in the save state, although it's unlikely to matter much.
330 333
 	// They are for lwarx and its friend stwcxd.
331 334
 	static bool g_bReserve;
15  Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h
@@ -33,22 +33,27 @@
33 33
 const u32 FPSCR_VXCVI      = (u32)1 << (31 - 23);
34 34
 
35 35
 const u32 FPSCR_VX_ANY     = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ |
36  
-							 FPSCR_VXIMZ | FPSCR_VXVC | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI;
  36
+                             FPSCR_VXIMZ | FPSCR_VXVC | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI;
37 37
 
38 38
 const u32 FPSCR_ANY_X      = FPSCR_OX | FPSCR_UX | FPSCR_ZX | FPSCR_XX | FPSCR_VX_ANY;
39 39
 
40 40
 const u64 PPC_NAN_U64      = 0x7ff8000000000000ull;
41 41
 const double PPC_NAN       = *(double* const)&PPC_NAN_U64;
42 42
 
43  
-inline bool IsINF(double x)
44  
-{
45  
-	return ((*(u64*)&x) & ~DOUBLE_SIGN) == DOUBLE_EXP;
46  
-}
  43
+// the 4 less-significand bits in FPSCR[FPRF]
  44
+enum FPCC {
  45
+	FL = 8, // <
  46
+	FG = 4, // >
  47
+	FE = 2, // =
  48
+	FU = 1, // ?
  49
+};
47 50
 
48 51
 inline void SetFPException(u32 mask)
49 52
 {
50 53
 	if ((FPSCR.Hex & mask) != mask)
  54
+	{
51 55
 		FPSCR.FX = 1;
  56
+	}
52 57
 	FPSCR.Hex |= mask;
53 58
 }
54 59
 
62  Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
@@ -33,29 +33,36 @@ void Interpreter::Helper_UpdateCR1(double _fValue)
33 33
 	SetCRField(1, (FPSCR.FX << 4) | (FPSCR.FEX << 3) | (FPSCR.VX << 2) | FPSCR.OX);
34 34
 }
35 35
 
36  
-void Interpreter::fcmpo(UGeckoInstruction _inst)
  36
+void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction _inst, double fa, double fb)
37 37
 {
38  
-	double fa = rPS0(_inst.FA);
39  
-	double fb = rPS0(_inst.FB);
40  
-
41 38
 	int compareResult;
42 39
 
43  
-	if (fa < fb)       compareResult = 8;
44  
-	else if (fa > fb)  compareResult = 4;
45  
-	else if (fa == fb) compareResult = 2;
46  
-	else
  40
+	if (fa < fb)
  41
+	{
  42
+		compareResult = FPCC::FL;
  43
+	}
  44
+	else if (fa > fb)
  45
+	{
  46
+		compareResult = FPCC::FG;
  47
+	}
  48
+	else if (fa == fb)
  49
+	{
  50
+		compareResult = FPCC::FE;
  51
+	}
  52
+	else // NaN
47 53
 	{
48 54
 		FPSCR.FX = 1;
49  
-		compareResult = 1;
  55
+		compareResult = FPCC::FU;
50 56
 		if (IsSNAN(fa) || IsSNAN(fb))
51 57
 		{
52 58
 			SetFPException(FPSCR_VXSNAN);
53 59
 			if (FPSCR.VE == 0)
  60
+			{
54 61
 				SetFPException(FPSCR_VXVC);
  62
+			}
55 63
 		}
56  
-		else
  64
+		else // QNaN
57 65
 		{
58  
-			//if (IsQNAN(fa) || IsQNAN(fb)) // this is always true
59 66
 			SetFPException(FPSCR_VXVC);
60 67
 		}
61 68
 	}
@@ -64,21 +71,28 @@ void Interpreter::fcmpo(UGeckoInstruction _inst)
64 71
 	SetCRField(_inst.CRFD, compareResult);
65 72
 }
66 73
 
67  
-void Interpreter::fcmpu(UGeckoInstruction _inst)
  74
+void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction _inst, double fa, double fb)
68 75
 {
69  
-	double fa = rPS0(_inst.FA);
70  
-	double fb = rPS0(_inst.FB);
71  
-
72 76
 	int compareResult;
73 77
 
74  
-	if (fa < fb)       compareResult = 8;
75  
-	else if (fa > fb)  compareResult = 4;
76  
-	else if (fa == fb) compareResult = 2;
  78
+	if (fa < fb)
  79
+	{
  80
+		compareResult = FPCC::FL;
  81
+	}
  82
+	else if (fa > fb)
  83
+	{
  84
+		compareResult = FPCC::FG;
  85
+	}
  86
+	else if (fa == fb)
  87
+	{
  88
+		compareResult = FPCC::FE;
  89
+	}
77 90
 	else
78 91
 	{
79  
-		compareResult = 1;
  92
+		compareResult = FPCC::FU;
80 93
 		if (IsSNAN(fa) || IsSNAN(fb))
81 94
 		{
  95
+			FPSCR.FX = 1;
82 96
 			SetFPException(FPSCR_VXSNAN);
83 97
 		}
84 98
 	}
@@ -86,6 +100,16 @@ void Interpreter::fcmpu(UGeckoInstruction _inst)
86 100
 	SetCRField(_inst.CRFD, compareResult);
87 101
 }
88 102
 
  103
+void Interpreter::fcmpo(UGeckoInstruction _inst)
  104
+{
  105
+	Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
  106
+}
  107
+
  108
+void Interpreter::fcmpu(UGeckoInstruction _inst)
  109
+{
  110
+	Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
  111
+}
  112
+
89 113
 // Apply current rounding mode
90 114
 void Interpreter::fctiwx(UGeckoInstruction _inst)
91 115
 {
86  Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp
@@ -354,100 +354,22 @@ void Interpreter::ps_madds1(UGeckoInstruction _inst)
354 354
 
355 355
 void Interpreter::ps_cmpu0(UGeckoInstruction _inst)
356 356
 {
357  
-	double fa = rPS0(_inst.FA);
358  
-	double fb = rPS0(_inst.FB);
359  
-	int compareResult;
360  
-
361  
-	if (fa < fb)       compareResult = 8;
362  
-	else if (fa > fb)  compareResult = 4;
363  
-	else if (fa == fb) compareResult = 2;
364  
-	else
365  
-	{
366  
-		compareResult = 1;
367  
-		if (IsSNAN(fa) || IsSNAN(fb))
368  
-		{
369  
-			SetFPException(FPSCR_VXSNAN);
370  
-		}
371  
-	}
372  
-	FPSCR.FPRF = compareResult;
373  
-	SetCRField(_inst.CRFD, compareResult);
  357
+	Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
374 358
 }
375 359
 
376 360
 void Interpreter::ps_cmpo0(UGeckoInstruction _inst)
377 361
 {
378  
-	double fa = rPS0(_inst.FA);
379  
-	double fb = rPS0(_inst.FB);
380  
-	int compareResult;
381  
-
382  
-	if (fa < fb)       compareResult = 8;
383  
-	else if (fa > fb)  compareResult = 4;
384  
-	else if (fa == fb) compareResult = 2;
385  
-	else
386  
-	{
387  
-		compareResult = 1;
388  
-		if (IsSNAN(fa) || IsSNAN(fb))
389  
-		{
390  
-			SetFPException(FPSCR_VXSNAN);
391  
-			if (!FPSCR.VE)
392  
-				SetFPException(FPSCR_VXVC);
393  
-		}
394  
-		else
395  
-		{
396  
-			//if (IsQNAN(fa) || IsQNAN(fb)) // this is always true
397  
-			SetFPException(FPSCR_VXVC);
398  
-		}
399  
-	}
400  
-	FPSCR.FPRF = compareResult;
401  
-	SetCRField(_inst.CRFD, compareResult);
  362
+	Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
402 363
 }
403 364
 
404 365
 void Interpreter::ps_cmpu1(UGeckoInstruction _inst)
405 366
 {
406  
-	double fa = rPS1(_inst.FA);
407  
-	double fb = rPS1(_inst.FB);
408  
-	int compareResult;
409  
-
410  
-	if (fa < fb)       compareResult = 8;
411  
-	else if (fa > fb)  compareResult = 4;
412  
-	else if (fa == fb) compareResult = 2;
413  
-	else
414  
-	{
415  
-		compareResult = 1;
416  
-		if (IsSNAN(fa) || IsSNAN(fb))
417  
-		{
418  
-			SetFPException(FPSCR_VXSNAN);
419  
-		}
420  
-	}
421  
-	FPSCR.FPRF = compareResult;
422  
-	SetCRField(_inst.CRFD, compareResult);
  367
+	Helper_FloatCompareUnordered(_inst, rPS1(_inst.FA), rPS1(_inst.FB));
423 368
 }
424 369
 
425 370
 void Interpreter::ps_cmpo1(UGeckoInstruction _inst)
426 371
 {
427  
-	double fa = rPS1(_inst.FA);
428  
-	double fb = rPS1(_inst.FB);
429  
-	int compareResult;
430  
-
431  
-	if (fa < fb)       compareResult = 8;
432  
-	else if (fa > fb)  compareResult = 4;
433  
-	else if (fa == fb) compareResult = 2;
434  
-	else
435  
-	{
436  
-		compareResult = 1;
437  
-		if (IsSNAN(fa) || IsSNAN(fb))
438  
-		{
439  
-			SetFPException(FPSCR_VXSNAN);
440  
-			if (!FPSCR.VE)
441  
-				SetFPException(FPSCR_VXVC);
442  
-		}
443  
-		else
444  
-		{
445  
-			//if (IsQNAN(fa) || IsQNAN(fb)) // this is always true
446  
-			SetFPException(FPSCR_VXVC);
447  
-		}
448  
-	}
449  
-	FPSCR.FPRF = compareResult;
450  
-	SetCRField(_inst.CRFD, compareResult);
  372
+	Helper_FloatCompareOrdered(_inst, rPS1(_inst.FA), rPS1(_inst.FB));
451 373
 }
452 374
 
453 375
 // __________________________________________________________________________________________________
17  Source/UnitTests/Common/MathUtilTest.cpp
@@ -2,8 +2,8 @@
2 2
 // Licensed under GPLv2
3 3
 // Refer to the license.txt file included.
4 4
 
5  
-#include <cmath>
6 5
 #include <gtest/gtest.h>
  6
+#include <limits>
7 7
 
8 8
 #include "Common/MathUtil.h"
9 9
 
@@ -27,19 +27,28 @@ T ClampAndReturn(const T& val, const T& min, const T& max)
27 27
 	EXPECT_EQ(0.0, ClampAndReturn(-1.0, 0.0, 2.0));
28 28
 }
29 29
 
  30
+TEST(MathUtil, IsINF)
  31
+{
  32
+	EXPECT_TRUE(MathUtil::IsINF( std::numeric_limits<double>::infinity()));
  33
+	EXPECT_TRUE(MathUtil::IsINF(-std::numeric_limits<double>::infinity()));
  34
+}
  35
+
30 36
 TEST(MathUtil, IsNAN)
31 37
 {
32  
-	EXPECT_TRUE(MathUtil::IsNAN(nan("")));
  38
+	EXPECT_TRUE(MathUtil::IsNAN(std::numeric_limits<double>::quiet_NaN()));
  39
+	EXPECT_TRUE(MathUtil::IsNAN(std::numeric_limits<double>::signaling_NaN()));
33 40
 }
34 41
 
35 42
 TEST(MathUtil, IsQNAN)
36 43
 {
37  
-	// TODO
  44
+	EXPECT_TRUE(MathUtil::IsQNAN(std::numeric_limits<double>::quiet_NaN()));
  45
+	EXPECT_FALSE(MathUtil::IsQNAN(std::numeric_limits<double>::signaling_NaN()));
38 46
 }
39 47
 
40 48
 TEST(MathUtil, IsSNAN)
41 49
 {
42  
-	// TODO
  50
+	EXPECT_FALSE(MathUtil::IsSNAN(std::numeric_limits<double>::quiet_NaN()));
  51
+	EXPECT_TRUE(MathUtil::IsSNAN(std::numeric_limits<double>::signaling_NaN()));
43 52
 }
44 53
 
45 54
 TEST(MathUtil, Log2)

0 notes on commit f401263

Please sign in to comment.
Something went wrong with that request. Please try again.