This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] DFP runtime comparisons for NaN


Runtime comparisons of decimal float values are done via a call to
decNumberCompare, which returns a NaN if either operand was a NaN.
Code to translate the result from decNumberCompare didn't take a NaN
result into consideration.  Some operators got the right answers for
NaN comparisons by accident, but they were broken for greater than
and greater than or equal to.  This patch fixes that by explicit checks
for NaN results in cases where the existing check doesn't already
cover it for "false" results.

Bootstrapped and regtested (including dectest.exp) on powerpc64-linux.
OK for mainline?

2006-12-13  Janis Johnson  <janis187@us.ibm.com>

gcc/
	* config/dfp-bit.c (dfp_compare_op): Return separate value for NaN.
	(DFP_NE, DFP_LE, DFP_GE): Return false for NaN.

gcc/testsuite/
	* gcc.dg/dfp/compare-special.h: New file.
	* gcc.dg/dfp/compare-special-32.c: New test.
	* gcc.dg/dfp/compare-special-64.c: New test.
	* gcc.dg/dfp/compare-special-128.c: New test.

Index: gcc/config/dfp-bit.c
===================================================================
--- gcc/config/dfp-bit.c	(revision 119799)
+++ gcc/config/dfp-bit.c	(working copy)
@@ -146,6 +146,8 @@
     result = -1;
   else if (decNumberIsZero (&res))
     result = 0;
+  else if (decNumberIsNaN (&res))
+    result = -2;
   else
     result = 1;
 
@@ -302,7 +304,9 @@
 {
   int stat;
   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
-  /* For NE return nonzero for true, zero for false.  */
+  /* For NE return zero for true, nonzero for false.  */
+  if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
+    return 1;
   return stat != 0;
 }
 #endif /* L_ne */
@@ -336,6 +340,8 @@
   int stat;
   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
   /* For LE return 0 (<= 0) for true, 1 for false.  */
+  if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
+    return 1;
   return stat == 1;
 }
 #endif /* L_le */
@@ -347,6 +353,8 @@
   int stat;
   stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
   /* For GE return 1 (>=0) for true, -1 for false.  */
+  if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
+    return -1;
   return (stat != -1) ? 1 : -1;
 }
 #endif /* L_ge */
Index: gcc/testsuite/gcc.dg/dfp/compare-special.h
===================================================================
--- gcc/testsuite/gcc.dg/dfp/compare-special.h	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/compare-special.h	(revision 0)
@@ -0,0 +1,287 @@
+/* Basic test of runtime relational comparisons using NaNs and infinities.  */
+
+#include <stdlib.h>
+
+static int failcnt;
+
+#define PASTE2(A,B) A ## B
+#define PASTE(A,B) PASTE2(A,B)
+
+#ifdef DBG
+#include <stdio.h>
+#define FAILURE(OP,KIND) \
+  { printf ("failed at line %d: %s for %s values\n", __LINE__, OP, KIND); \
+    failcnt++; }
+#else
+#define FAILURE(OP,KIND) abort ();
+#endif
+
+#ifndef WIDTH
+#error define WIDTH as decimal float size in bytes
+#endif
+
+#if WIDTH == 32
+#define DTYPE _Decimal32
+#define SUFFIX DF
+#define SUFFIX2 d32
+#elif WIDTH == 64
+#define DTYPE _Decimal64
+#define SUFFIX DD
+#define SUFFIX2 d64
+#elif WIDTH == 128
+#define DTYPE _Decimal128
+#define SUFFIX DL
+#define SUFFIX2 d128
+#elif WIDTH == 0
+/* This is for testing the test using a type known to work.  */
+#define DTYPE double
+#define SUFFIX
+#define SUFFIX2
+#else
+#error invalid width for decimal float type
+#endif
+
+DTYPE m_two = PASTE(-2.0, SUFFIX);
+DTYPE m_one = PASTE(-1.0, SUFFIX);
+DTYPE zero  = PASTE(0.0, SUFFIX);
+DTYPE one   = PASTE(1.0, SUFFIX);
+DTYPE two   = PASTE(2.0, SUFFIX);
+
+volatile DTYPE x, y, z, nan, inf, m_inf;
+
+void
+test_compares (void)
+{
+  nan = PASTE(__builtin_nan, SUFFIX2) ("");
+  inf = PASTE(__builtin_inf, SUFFIX2) ();
+  m_inf = - PASTE(__builtin_inf, SUFFIX2) ();
+
+  x = PASTE(__builtin_nan, SUFFIX2) ("");
+  y = PASTE(__builtin_inf, SUFFIX2) ();
+  z = - PASTE(__builtin_inf, SUFFIX2) ();
+
+  /* Less than or equal to with NaN.  */
+
+  if (x <= two)   FAILURE ("<=", "NaN")
+  if (x <= zero)  FAILURE ("<=", "NaN")
+  if (x <= m_one) FAILURE ("<=", "NaN")
+  if (x <= nan)   FAILURE ("<=", "NaN")
+  if (x <= inf)   FAILURE ("<=", "NaN")
+  if (x <= m_inf) FAILURE ("<=", "NaN")
+
+  if (two <= x)   FAILURE ("<=", "NaN")
+  if (zero <= x)  FAILURE ("<=", "NaN")
+  if (m_one <= x) FAILURE ("<=", "NaN")
+  if (nan <= x)   FAILURE ("<=", "NaN")
+  if (inf <= x)   FAILURE ("<=", "NaN")
+  if (m_inf <= x) FAILURE ("<=", "NaN")
+
+  /* Less than or equal to with infinities, no NaNs.  */
+
+  if (y <= two)      FAILURE ("<=", "inf")
+  if (y <= zero)     FAILURE ("<=", "inf")
+  if (y <= m_one)    FAILURE ("<=", "inf")
+  if (!(two <= y))   FAILURE ("<=", "inf")
+  if (!(zero <= y))  FAILURE ("<=", "inf")
+  if (!(m_one <= y)) FAILURE ("<=", "inf")
+
+  if (!(z <= two))   FAILURE ("<=", "-inf")
+  if (!(z <= zero))  FAILURE ("<=", "-inf")
+  if (!(z <= m_one)) FAILURE ("<=", "-inf")
+  if (two <= z)      FAILURE ("<=", "-inf")
+  if (zero <= z)     FAILURE ("<=", "-inf")
+  if (m_one <= z)    FAILURE ("<=", "-inf")
+
+  if (!(y <= inf))   FAILURE ("<=", "inf")
+  if (y <= m_inf)    FAILURE ("<=", "inf")
+  if (!(z <= inf))   FAILURE ("<=", "inf")
+  if (!(z <= m_inf)) FAILURE ("<=", "inf")
+
+  /* Less than with NaN.  */
+
+  if (x < two)       FAILURE ("<", "NaN")
+  if (x < zero)      FAILURE ("<", "NaN")
+  if (x < m_one)     FAILURE ("<", "NaN")
+  if (x < nan)       FAILURE ("<", "NaN")
+  if (x < inf)       FAILURE ("<", "NaN")
+  if (x < m_inf)     FAILURE ("<", "NaN")
+
+  if (two < x)       FAILURE ("<", "NaN")
+  if (zero < x)      FAILURE ("<", "NaN")
+  if (m_one < x)     FAILURE ("<", "NaN")
+  if (nan < x)       FAILURE ("<", "NaN")
+  if (inf < x)       FAILURE ("<", "NaN")
+  if (m_inf < x)     FAILURE ("<", "NaN")
+
+  /* Less than with infinities, no NaNs.  */
+
+  if (y < two)       FAILURE ("<", "inf")
+  if (y < zero)      FAILURE ("<", "inf")
+  if (y < m_one)     FAILURE ("<", "inf")
+  if (!(two < y))    FAILURE ("<", "inf")
+  if (!(zero < y))   FAILURE ("<", "inf")
+  if (!(m_one < y))  FAILURE ("<", "inf")
+
+  if (!(z < two))    FAILURE ("<", "-inf")
+  if (!(z < zero))   FAILURE ("<", "-inf")
+  if (!(z < m_one))  FAILURE ("<", "-inf")
+  if (two < z)       FAILURE ("<", "-inf")
+  if (zero < z)      FAILURE ("<", "-inf")
+  if (m_one < z)     FAILURE ("<", "-inf")
+
+  if (y < inf)       FAILURE ("<=", "inf")
+  if (y < m_inf)     FAILURE ("<=", "inf")
+  if (!(z < inf))    FAILURE ("<=", "inf")
+  if (z < m_inf)     FAILURE ("<=", "inf")
+
+  /* Greater than or equal to with NaN.  */
+
+  if (x >= two)      FAILURE (">=", "NaN")
+  if (x >= zero)     FAILURE (">=", "NaN")
+  if (x >= m_one)    FAILURE (">=", "NaN")
+  if (x >= nan)      FAILURE (">=", "NaN")
+  if (x >= inf)      FAILURE (">=", "NaN")
+  if (x >= m_inf)    FAILURE (">=", "NaN")
+
+  if (two >= x)      FAILURE (">=", "NaN")
+  if (zero >= x)     FAILURE (">=", "NaN")
+  if (m_one >= x)    FAILURE (">=", "NaN")
+  if (nan >= x)      FAILURE (">=", "NaN")
+  if (inf >= x)      FAILURE (">=", "NaN")
+  if (m_inf >= x)    FAILURE (">=", "NaN")
+
+  /* Greater than or equal to with infinities, no NaNs.  */
+
+  if (!(y >= two))   FAILURE (">=", "inf")
+  if (!(y >= zero))  FAILURE (">=", "inf")
+  if (!(y >= m_one)) FAILURE (">=", "inf")
+  if (two >= y)      FAILURE (">=", "inf")
+  if (zero >= y)     FAILURE (">=", "inf")
+  if (m_one >= y)    FAILURE (">=", "inf")
+
+  if (z >= two)      FAILURE (">=", "-inf")
+  if (z >= zero)     FAILURE (">=", "-inf")
+  if (z >= m_one)    FAILURE (">=", "-inf")
+  if (!(two >= z))   FAILURE (">=", "-inf")
+  if (!(zero >= z))  FAILURE (">=", "-inf")
+  if (!(m_one >= z)) FAILURE (">=", "-inf")
+
+  if (!(y >= inf))   FAILURE ("<=", "inf")
+  if (!(y >= m_inf)) FAILURE ("<=", "inf")
+  if (z >= inf)      FAILURE ("<=", "inf")
+  if (!(z >= m_inf)) FAILURE ("<=", "inf")
+
+  /* Greater than with NaN.  */
+
+  if (x > two)       FAILURE (">", "NaN")
+  if (x > zero)      FAILURE (">", "NaN")
+  if (x > m_one)     FAILURE (">", "NaN")
+  if (x > nan)       FAILURE (">", "NaN")
+  if (x > inf)       FAILURE (">", "NaN")
+  if (x > m_inf)     FAILURE (">", "NaN")
+
+  if (two > x)       FAILURE (">", "NaN")
+  if (zero > x)      FAILURE (">", "NaN")
+  if (m_one > x)     FAILURE (">", "NaN")
+  if (nan > x)       FAILURE (">", "NaN")
+  if (inf > x)       FAILURE (">", "NaN")
+  if (m_inf > x)     FAILURE (">", "NaN")
+
+  /* Greater than with infinities, no NaNs.  */
+
+  if (!(y > two))    FAILURE (">", "inf")
+  if (!(y > zero))   FAILURE (">", "inf")
+  if (!(y > m_one))  FAILURE (">", "inf")
+  if (two > y)       FAILURE (">", "inf")
+  if (zero > y)      FAILURE (">", "inf")
+  if (m_one > y)     FAILURE (">", "inf")
+
+  if (z > two)       FAILURE (">", "-inf")
+  if (z > zero)      FAILURE (">", "-inf")
+  if (z > m_one)     FAILURE (">", "-inf")
+  if (!(two > z))    FAILURE (">", "-inf")
+  if (!(zero > z))   FAILURE (">", "-inf")
+  if (!(m_one > z))  FAILURE (">", "-inf")
+
+  if (y > inf)       FAILURE (">", "inf")
+  if (!(y > m_inf))  FAILURE (">", "inf")
+  if (z > inf)       FAILURE (">", "inf")
+  if (z > m_inf)     FAILURE (">", "inf")
+
+  /* Equal with NaN.  */
+
+  if (x == two)      FAILURE ("==", "NaN")
+  if (x == zero)     FAILURE ("==", "NaN")
+  if (x == m_one)    FAILURE ("==", "NaN")
+  if (x == nan)      FAILURE ("==", "NaN")
+  if (x == inf)      FAILURE ("==", "NaN")
+  if (x == m_inf)    FAILURE ("==", "NaN")
+
+  if (two == x)      FAILURE ("==", "NaN")
+  if (zero == x)     FAILURE ("==", "NaN")
+  if (m_one == x)    FAILURE ("==", "NaN")
+  if (nan == x)      FAILURE ("==", "NaN")
+  if (inf == x)      FAILURE ("==", "NaN")
+  if (m_inf == x)    FAILURE ("==", "NaN")
+
+  /* Equal with infinities, no NaNs.  */
+
+  if (y == two)      FAILURE ("==", "inf")
+  if (y == zero)     FAILURE ("==", "inf")
+  if (y == m_one)    FAILURE ("==", "inf")
+  if (two == y)      FAILURE ("==", "inf")
+  if (zero == y)     FAILURE ("==", "inf")
+  if (m_one == y)    FAILURE ("==", "inf")
+
+  if (z == two)      FAILURE ("==", "-inf")
+  if (z == zero)     FAILURE ("==", "-inf")
+  if (z == m_one)    FAILURE ("==", "-inf")
+  if (two == z)      FAILURE ("==", "-inf")
+  if (zero == z)     FAILURE ("==", "-inf")
+  if (m_one == z)    FAILURE ("==", "-inf")
+
+  if (!(y == inf))   FAILURE ("==", "inf")
+  if (y == m_inf)    FAILURE ("==", "inf")
+  if (z == inf)      FAILURE ("==", "inf")
+  if (!(z == m_inf)) FAILURE ("==", "inf")
+
+  /* Not equal with NaN.  */
+
+  if (!(x != two))   FAILURE ("!=", "NaN")
+  if (!(x != zero))  FAILURE ("!=", "NaN")
+  if (!(x != m_one)) FAILURE ("!=", "NaN")
+  if (!(x != nan))   FAILURE ("!=", "NaN")
+  if (!(x != inf))   FAILURE ("!=", "NaN")
+  if (!(x != m_inf)) FAILURE ("!=", "NaN")
+
+  if (!(two != x))   FAILURE ("!=", "NaN")
+  if (!(zero != x))  FAILURE ("!=", "NaN")
+  if (!(m_one != x)) FAILURE ("!=", "NaN")
+  if (!(nan != x))   FAILURE ("!=", "NaN")
+  if (!(inf != x))   FAILURE ("!=", "NaN")
+  if (!(m_inf != x)) FAILURE ("!=", "NaN")
+
+  /* Not equal with infinities, no NaNs.  */
+
+  if (!(y != two))   FAILURE ("!=", "inf")
+  if (!(y != zero))  FAILURE ("!=", "inf")
+  if (!(y != m_one)) FAILURE ("!=", "inf")
+  if (!(two != y))   FAILURE ("!=", "inf")
+  if (!(zero != y))  FAILURE ("!=", "inf")
+  if (!(m_one != y)) FAILURE ("!=", "inf")
+
+  if (!(z != two))   FAILURE ("!=", "-inf")
+  if (!(z != zero))  FAILURE ("!=", "-inf")
+  if (!(z != m_one)) FAILURE ("!=", "-inf")
+  if (!(two != z))   FAILURE ("!=", "-inf")
+  if (!(zero != z))  FAILURE ("!=", "-inf")
+  if (!(m_one != z)) FAILURE ("!=", "-inf")
+
+  if (y != inf)      FAILURE ("!=", "inf")
+  if (!(y != m_inf)) FAILURE ("!=", "inf")
+  if (!(z != inf))   FAILURE ("!=", "inf")
+  if (z != m_inf)    FAILURE ("!=", "inf")
+
+  if (failcnt)
+    abort ();
+}
Index: gcc/testsuite/gcc.dg/dfp/compare-special-d32.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/compare-special-d32.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/compare-special-d32.c	(revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "-std=gnu99 -O0" } */
+
+/* C99 6.5.8 Relational operators.
+   C99 6.5.9 Equality operators.
+   Compare decimal float special values at runtime.  */
+
+#define WIDTH 32
+#include "compare-special.h"
+
+int
+main ()
+{
+  test_compares ();
+  return 0;
+}
Index: gcc/testsuite/gcc.dg/dfp/compare-special-d64.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/compare-special-d64.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/compare-special-d64.c	(revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "-std=gnu99 -O0" } */
+
+/* C99 6.5.8 Relational operators.
+   C99 6.5.9 Equality operators.
+   Compare decimal float special values at runtime.  */
+
+#define WIDTH 64
+#include "compare-special.h"
+
+int
+main ()
+{
+  test_compares ();
+  return 0;
+}
Index: gcc/testsuite/gcc.dg/dfp/compare-special-d128.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/compare-special-d128.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/compare-special-d128.c	(revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "-std=gnu99 -O0" } */
+
+/* C99 6.5.8 Relational operators.
+   C99 6.5.9 Equality operators.
+   Compare decimal float special values at runtime.  */
+
+#define WIDTH 128
+#include "compare-special.h"
+
+int
+main ()
+{
+  test_compares ();
+  return 0;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]