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] PR target/32641: fix the C99 FP test macros on solaris 10


This patch fixes PR target/32641, which is a problem with FP exception
safety for the C99 FP test macros.

The solaris system headers expect compiler support for these macros and
define them accordingly. Since GCC doesn't have builtin support for these
(yet), the solution back then was to apply fixinclues to hack up some code
for each of these macros. However the fixincludes replacements weren't
designed with avoiding floating point exceptions in mind.  See:
http://gcc.gnu.org/ml/gcc-patches/2005-05/msg01119.html

This patch changes the fallback code applied into the header by fixinclues
so that these macros don't generate floating point exceptions for various
inputs.  E.g. isfinite uses a subtraction which converts Inf-Inf into NaN,
that raises an exception.  Then isfinite is used in the definition of
other macros which propagates the error to them too.  In another case, the
isnormal macro uses ordered comparisons which raise exceptions for quiet
NaN input.

I added many more edge/corner cases into the existing testcase, and then
wrapped it with a check to see if any FP exceptions were raised.


Notes:

1.  while in there I constified the variable used in the macros.

2.  This problem exists for all active branches (4.1, 4.2, & mainline).

3.  I had to make the testcase variables volatile because the optimizer
was folding everything away instead of letting the runtime behavior get
tested.

4.  You may have noticed I had posted some (unreviewed) patches last month
to add middle-end builtin support for this functionality.  However those
won't ever get into branches, so in the mean time this will fix GCC
behavior everywhere.  In addition, I believe I've found a problem with the
middle-end bits I posted so I'll have to resubmit anyway.  So this fix is
still needed even on mainline.  Later if I solve the problems with my
builtins patch, we can use builtins on the trunk, but this fix will be on
branches.

5.  This patch avoids exceptions for Inf & quiet NaNs, but signaling NaNs
still raise an exception.  This is because isless et al, only avoid
exceptions for quiet NaN.  Signaling NaN still throws when you use them.
The only way to avoid that is with bit manipulations/tests, however this
patch is a definite improvement from what we have.

6.  To apply cleanly, this patch relies on a previous addition to the
existing testcase which checks subnormal numbers as well:
http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00063.html
If this patch is approved, I'll apply that one as well.


Tested on mainline on sparc-sun-solaris2.10, no regressions and the
testcases (with the extra cases) all pass.  It also passes "make check" in
the fixinclues directory.

Okay for mainline, 4.2 and 4.1?

		Thanks,
		--Kaveh


2007-07-05  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

fixincludes:
	PR target/32641

	* inclhack.def (solaris_math_4, solaris_math_5, solaris_math_6,
	solaris_math_7): Constify and make FP exception-safe.
	* tests/base/iso/math_c99.h: Update.

	* fixincl.x: Regenerate.

gcc/testsuite:
	* gcc.dg/c99-math-double-1.c: Mark test variables as volatile.
	Test negative numbers also.
	* gcc.dg/c99-math-float-1.c: Likewise.
	* gcc.dg/c99-math-long-double-1.c: Likewise.
	* gcc.dg/c99-math.h: Check for FP exceptions.  Update for negative
	test inputs.

diff -rup orig/egcc-SVN20070704/fixincludes/inclhack.def egcc-SVN20070704/fixincludes/inclhack.def
--- orig/egcc-SVN20070704/fixincludes/inclhack.def	2007-06-07 23:14:33.000000000 -0400
+++ egcc-SVN20070704/fixincludes/inclhack.def	2007-07-05 16:52:24.563225999 -0400
@@ -3070,7 +3070,7 @@ fix = {
     files = iso/math_c99.h;
     c_fix = format;
     c_fix_arg = "#define\tfpclassify(x) \\\n"
-                "  __extension__ ({ __typeof(x) __x_fp = (x); \\\n"
+                "  __extension__ ({ const __typeof(x) __x_fp = (x); \\\n"
                 "\t\t   isnan(__x_fp) \\\n"
                 "\t\t     ? FP_NAN \\\n"
                 "\t\t     : isinf(__x_fp) \\\n"
@@ -3094,8 +3094,12 @@ fix = {
     files = iso/math_c99.h;
     c_fix = format;
     c_fix_arg = "#define\tisfinite(x) \\\n"
-                "  __extension__ ({ __typeof (x) __x_f = (x); \\\n"
-                "\t\t   __builtin_expect(!isnan(__x_f - __x_f), 1); })";
+                "  __extension__ ({ const __typeof (x) __x_f = (x); \\\n"
+                "\t\t    __builtin_expect(sizeof(__x_f) == sizeof(float) \\\n"
+                "\t\t\t  ? islessequal(__builtin_fabsf(__x_f),__FLT_MAX__) \\\n"
+                "\t\t\t  : sizeof(__x_f) == sizeof(long double) \\\n"
+                "\t\t\t    ? islessequal(__builtin_fabsl(__x_f),__LDBL_MAX__) \\\n"
+                "\t\t\t    : islessequal(__builtin_fabs(__x_f),__DBL_MAX__), 1); })";
     c_fix_arg = "^#define[ \t]+isfinite\\(x\\)[ \t]+__builtin_isfinite\\(x\\)";
     test_text =
     '#ident	"@(#)math_c99.h	1.9	04/11/01 SMI"'"\n"
@@ -3110,8 +3114,12 @@ fix = {
     files = iso/math_c99.h;
     c_fix = format;
     c_fix_arg = "#define\tisinf(x) \\\n"
-                "  __extension__ ({ __typeof (x) __x_i = (x); \\\n"
-                "\t\t   __builtin_expect(!isnan(__x_i) && !isfinite(__x_i), 0); })";
+                "  __extension__ ({ const __typeof (x) __x_i = (x); \\\n"
+                "\t\t    __builtin_expect(sizeof(__x_i) == sizeof(float) \\\n"
+                "\t\t\t  ? isgreater(__builtin_fabsf(__x_i),__FLT_MAX__) \\\n"
+                "\t\t\t  : sizeof(__x_i) == sizeof(long double) \\\n"
+                "\t\t\t    ? isgreater(__builtin_fabsl(__x_i),__LDBL_MAX__) \\\n"
+                "\t\t\t    : isgreater(__builtin_fabs(__x_i),__DBL_MAX__), 0); })";
     c_fix_arg = "^#define[ \t]+isinf\\(x\\)[ \t]+__builtin_isinf\\(x\\)";
     test_text =
     '#ident	"@(#)math_c99.h	1.9	04/11/01 SMI"'"\n"
@@ -3126,14 +3134,13 @@ fix = {
     files = iso/math_c99.h;
     c_fix = format;
     c_fix_arg = "#define\tisnormal(x) \\\n"
-                "  __extension__ ({ __typeof(x) __x_n = (x); \\\n"
-                "\t\t   if (__x_n < 0.0) __x_n = -__x_n; \\\n"
+                "  __extension__ ({ const __typeof(x) __x_n = (x); \\\n"
                 "\t\t   __builtin_expect(isfinite(__x_n) \\\n"
                 "\t\t\t\t    && (sizeof(__x_n) == sizeof(float) \\\n"
-                "\t\t\t\t\t  ? __x_n >= __FLT_MIN__ \\\n"
+                "\t\t\t\t\t  ? isgreaterequal(__builtin_fabsf(__x_n),__FLT_MIN__) \\\n"
                 "\t\t\t\t\t  : sizeof(__x_n) == sizeof(long double) \\\n"
-                "\t\t\t\t\t    ? __x_n >= __LDBL_MIN__ \\\n"
-                "\t\t\t\t\t    : __x_n >= __DBL_MIN__), 1); })";
+                "\t\t\t\t\t    ? isgreaterequal(__builtin_fabsl(__x_n),__LDBL_MIN__) \\\n"
+                "\t\t\t\t\t    : isgreaterequal(__builtin_fabs(__x_n),__DBL_MIN__)), 1); })";
     c_fix_arg = "^#define[ \t]+isnormal\\(x\\)[ \t]+__builtin_isnormal\\(x\\)";
     test_text =
     '#ident	"@(#)math_c99.h	1.9	04/11/01 SMI"'"\n"
diff -rup orig/egcc-SVN20070704/fixincludes/tests/base/iso/math_c99.h egcc-SVN20070704/fixincludes/tests/base/iso/math_c99.h
--- orig/egcc-SVN20070704/fixincludes/tests/base/iso/math_c99.h	2006-01-23 00:54:49.000000000 -0500
+++ egcc-SVN20070704/fixincludes/tests/base/iso/math_c99.h	2007-07-05 16:52:24.565326671 -0400
@@ -38,7 +38,7 @@
 #ident	"@(#)math_c99.h	1.9	04/11/01 SMI"
 #undef	fpclassify
 #define	fpclassify(x) \
-  __extension__ ({ __typeof(x) __x_fp = (x); \
+  __extension__ ({ const __typeof(x) __x_fp = (x); \
 		   isnan(__x_fp) \
 		     ? FP_NAN \
 		     : isinf(__x_fp) \
@@ -55,8 +55,12 @@
 #ident	"@(#)math_c99.h	1.9	04/11/01 SMI"
 #undef	isfinite
 #define	isfinite(x) \
-  __extension__ ({ __typeof (x) __x_f = (x); \
-		   __builtin_expect(!isnan(__x_f - __x_f), 1); })
+  __extension__ ({ const __typeof (x) __x_f = (x); \
+		    __builtin_expect(sizeof(__x_f) == sizeof(float) \
+			  ? islessequal(__builtin_fabsf(__x_f),__FLT_MAX__) \
+			  : sizeof(__x_f) == sizeof(long double) \
+			    ? islessequal(__builtin_fabsl(__x_f),__LDBL_MAX__) \
+			    : islessequal(__builtin_fabs(__x_f),__DBL_MAX__), 1); })
 #endif  /* SOLARIS_MATH_5_CHECK */


@@ -64,8 +68,12 @@
 #ident	"@(#)math_c99.h	1.9	04/11/01 SMI"
 #undef	isinf
 #define	isinf(x) \
-  __extension__ ({ __typeof (x) __x_i = (x); \
-		   __builtin_expect(!isnan(__x_i) && !isfinite(__x_i), 0); })
+  __extension__ ({ const __typeof (x) __x_i = (x); \
+		    __builtin_expect(sizeof(__x_i) == sizeof(float) \
+			  ? isgreater(__builtin_fabsf(__x_i),__FLT_MAX__) \
+			  : sizeof(__x_i) == sizeof(long double) \
+			    ? isgreater(__builtin_fabsl(__x_i),__LDBL_MAX__) \
+			    : isgreater(__builtin_fabs(__x_i),__DBL_MAX__), 0); })
 #endif  /* SOLARIS_MATH_6_CHECK */


@@ -73,14 +81,13 @@
 #ident	"@(#)math_c99.h	1.9	04/11/01 SMI"
 #undef	isnormal
 #define	isnormal(x) \
-  __extension__ ({ __typeof(x) __x_n = (x); \
-		   if (__x_n < 0.0) __x_n = -__x_n; \
+  __extension__ ({ const __typeof(x) __x_n = (x); \
 		   __builtin_expect(isfinite(__x_n) \
 				    && (sizeof(__x_n) == sizeof(float) \
-					  ? __x_n >= __FLT_MIN__ \
+					  ? isgreaterequal(__builtin_fabsf(__x_n),__FLT_MIN__) \
 					  : sizeof(__x_n) == sizeof(long double) \
-					    ? __x_n >= __LDBL_MIN__ \
-					    : __x_n >= __DBL_MIN__), 1); })
+					    ? isgreaterequal(__builtin_fabsl(__x_n),__LDBL_MIN__) \
+					    : isgreaterequal(__builtin_fabs(__x_n),__DBL_MIN__)), 1); })
 #endif  /* SOLARIS_MATH_7_CHECK */


diff -rup orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-double-1.c egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-double-1.c
--- orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-double-1.c	2007-07-05 16:54:45.724590428 -0400
+++ egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-double-1.c	2007-07-05 16:52:24.566293474 -0400
@@ -6,14 +6,17 @@

 int main(void)
 {
-  double nan = NAN;
-  double inf = INFINITY;
-  double huge = HUGE_VAL;
-  double norm = __DBL_MIN__;
-  double sub = __DBL_MIN__ / 2;
-  double zero = 0.0;
+  volatile double nan = NAN;
+  volatile double inf = INFINITY;
+  volatile double huge = HUGE_VAL;
+  volatile double norm1 = __DBL_MIN__;
+  volatile double norm2 = 1;
+  volatile double norm3 = __DBL_MAX__;
+  volatile double sub = __DBL_MIN__ / 2;
+  volatile double zero = 0.0;

-  C99_MATH_TESTS (nan, inf, huge, norm, sub, zero)
+  C99_MATH_TESTS (nan, inf, huge, norm1, norm2, norm3, sub, zero, /*neg=*/0)
+  C99_MATH_TESTS (-nan, -inf, -huge, -norm1, -norm2, -norm3, -sub, -zero, /*neg=*/1)

   return 0;
 }
diff -rup orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-float-1.c egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-float-1.c
--- orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-float-1.c	2007-07-05 16:54:45.725743342 -0400
+++ egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-float-1.c	2007-07-05 16:52:24.567740277 -0400
@@ -6,14 +6,17 @@

 int main(void)
 {
-  float nan = NAN;
-  float inf = INFINITY;
-  float huge = HUGE_VALF;
-  float norm = __FLT_MIN__;
-  float sub = __FLT_MIN__ / 2;
-  float zero = 0.0f;
+  volatile float nan = NAN;
+  volatile float inf = INFINITY;
+  volatile float huge = HUGE_VALF;
+  volatile float norm1 = __FLT_MIN__;
+  volatile float norm2 = 1;
+  volatile float norm3 = __FLT_MAX__;
+  volatile float sub = __FLT_MIN__ / 2;
+  volatile float zero = 0.0f;

-  C99_MATH_TESTS (nan, inf, huge, norm, sub, zero)
+  C99_MATH_TESTS (nan, inf, huge, norm1, norm2, norm3, sub, zero, /*neg=*/0)
+  C99_MATH_TESTS (-nan, -inf, -huge, -norm1, -norm2, -norm3, -sub, -zero, /*neg=*/1)

   return 0;
 }
diff -rup orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-long-double-1.c egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-long-double-1.c
--- orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-long-double-1.c	2007-07-05 16:54:45.726580442 -0400
+++ egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math-long-double-1.c	2007-07-05 16:52:24.568631946 -0400
@@ -6,14 +6,17 @@

 int main(void)
 {
-  long double nan = NAN;
-  long double inf = INFINITY;
-  long double huge = HUGE_VALL;
-  long double norm = __LDBL_MIN__;
-  long double sub = __LDBL_MIN__ / 2;
-  long double zero = 0.0l;
+  volatile long double nan = NAN;
+  volatile long double inf = INFINITY;
+  volatile long double huge = HUGE_VALL;
+  volatile long double norm1 = __LDBL_MIN__;
+  volatile long double norm2 = 1;
+  volatile long double norm3 = __LDBL_MAX__;
+  volatile long double sub = __LDBL_MIN__ / 2;
+  volatile long double zero = 0.0l;

-  C99_MATH_TESTS (nan, inf, huge, norm, sub, zero)
+  C99_MATH_TESTS (nan, inf, huge, norm1, norm2, norm3, sub, zero, /*neg=*/0)
+  C99_MATH_TESTS (-nan, -inf, -huge, -norm1, -norm2, -norm3, -sub, -zero, /*neg=*/1)

   return 0;
 }
diff -rup orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math.h egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math.h
--- orig/egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math.h	2007-07-05 16:54:45.727898584 -0400
+++ egcc-SVN20070704/gcc/testsuite/gcc.dg/c99-math.h	2007-07-05 16:52:24.570472495 -0400
@@ -1,9 +1,14 @@
 #include <math.h>
+#include <fenv.h>

 extern void abort(void);

-#define C99_MATH_TESTS(nan, inf, huge, norm, sub, zero)	\
+#define C99_MATH_TESTS(nan, inf, huge, norm1, norm2, norm3, sub, zero, neg) \
 {							\
+  if (feclearexcept (FE_ALL_EXCEPT) != 0)		\
+    abort();						\
+							\
+							\
   if (fpclassify (nan) != FP_NAN)			\
     abort ();						\
 							\
@@ -13,7 +18,13 @@ extern void abort(void);
   if (fpclassify (huge) != FP_INFINITE)			\
     abort ();						\
 							\
-  if (fpclassify (norm) != FP_NORMAL)			\
+  if (fpclassify (norm1) != FP_NORMAL)			\
+    abort ();						\
+							\
+  if (fpclassify (norm2) != FP_NORMAL)			\
+    abort ();						\
+							\
+  if (fpclassify (norm3) != FP_NORMAL)			\
     abort ();						\
 							\
   if (fpclassify (sub) != FP_SUBNORMAL)			\
@@ -32,7 +43,13 @@ extern void abort(void);
   if (isnan (huge))					\
     abort ();						\
 							\
-  if (isnan (norm))					\
+  if (isnan (norm1))					\
+    abort ();						\
+							\
+  if (isnan (norm2))					\
+    abort ();						\
+							\
+  if (isnan (norm3))					\
     abort ();						\
 							\
   if (isnan (sub))					\
@@ -51,7 +68,13 @@ extern void abort(void);
   if (!isinf (huge))					\
     abort ();						\
 							\
-  if (isinf (norm))					\
+  if (isinf (norm1))					\
+    abort ();						\
+							\
+  if (isinf (norm2))					\
+    abort ();						\
+							\
+  if (isinf (norm3))					\
     abort ();						\
 							\
   if (isinf (sub))					\
@@ -70,7 +93,13 @@ extern void abort(void);
   if (isfinite (huge))					\
     abort ();						\
 							\
-  if (!isfinite (norm))					\
+  if (!isfinite (norm1))				\
+    abort ();						\
+							\
+  if (!isfinite (norm2))				\
+    abort ();						\
+							\
+  if (!isfinite (norm3))				\
     abort ();						\
 							\
   if (!isfinite (sub))					\
@@ -89,7 +118,13 @@ extern void abort(void);
   if (isnormal (huge))					\
     abort ();						\
 							\
-  if (!isnormal (norm))					\
+  if (!isnormal (norm1))				\
+    abort ();						\
+							\
+  if (!isnormal (norm2))				\
+    abort ();						\
+							\
+  if (!isnormal (norm3))				\
     abort ();						\
 							\
   if (isnormal (sub))					\
@@ -99,28 +134,103 @@ extern void abort(void);
     abort ();						\
 							\
 							\
-  if (signbit (norm))					\
+  if (!!signbit (nan) != neg)				\
     abort ();						\
 							\
-  if (!signbit (-(norm)))				\
+  if (!!signbit (inf) != neg)				\
     abort ();						\
 							\
+  if (!!signbit (huge) != neg)				\
+    abort ();						\
 							\
-  if (!isgreater ((inf), (norm)))			\
+  if (!!signbit (norm1) != neg)				\
     abort ();						\
 							\
-  if (!isgreaterequal ((inf), (huge)))			\
+  if (!!signbit (norm2) != neg)				\
     abort ();						\
 							\
-  if (!isless ((norm), (inf)))				\
+  if (!!signbit (norm3) != neg)				\
     abort ();						\
 							\
-  if (!islessequal ((huge), (inf)))			\
+  if (!!signbit (sub) != neg)				\
     abort ();						\
 							\
-  if (!islessgreater ((inf), (norm)))			\
+  if (!!signbit (zero) != neg)				\
     abort ();						\
 							\
-  if (!isunordered ((nan), (norm)))			\
+							\
+  if (neg)						\
+  {							\
+    if (!isless ((inf), (norm1)))			\
+      abort ();						\
+							\
+    if (!isless ((inf), (norm2)))			\
+      abort ();						\
+							\
+    if (!isless ((inf), (norm3)))			\
+      abort ();						\
+							\
+    if (!islessequal ((inf), (huge)))			\
+      abort ();						\
+							\
+    if (!isgreater ((norm1), (inf)))			\
+      abort ();						\
+							\
+    if (!isgreater ((norm2), (inf)))			\
+      abort ();						\
+							\
+    if (!isgreater ((norm3), (inf)))			\
+      abort ();						\
+							\
+    if (!isgreaterequal ((huge), (inf)))		\
+      abort ();						\
+  }							\
+  else							\
+  {							\
+    if (!isgreater ((inf), (norm1)))			\
+      abort ();						\
+							\
+    if (!isgreater ((inf), (norm2)))			\
+      abort ();						\
+							\
+    if (!isgreater ((inf), (norm3)))			\
+      abort ();						\
+							\
+    if (!isgreaterequal ((inf), (huge)))		\
+      abort ();						\
+							\
+    if (!isless ((norm1), (inf)))			\
+      abort ();						\
+							\
+    if (!isless ((norm2), (inf)))			\
+      abort ();						\
+							\
+    if (!isless ((norm3), (inf)))			\
+      abort ();						\
+							\
+    if (!islessequal ((huge), (inf)))			\
+      abort ();						\
+  }							\
+							\
+  if (!islessgreater ((inf), (norm1)))			\
     abort ();						\
+							\
+  if (!islessgreater ((inf), (norm2)))			\
+    abort ();						\
+							\
+  if (!islessgreater ((inf), (norm3)))			\
+    abort ();						\
+							\
+  if (!isunordered ((nan), (norm1)))			\
+    abort ();						\
+							\
+  if (!isunordered ((nan), (norm2)))			\
+    abort ();						\
+							\
+  if (!isunordered ((nan), (norm3)))			\
+    abort ();						\
+							\
+							\
+  if (fetestexcept (FE_ALL_EXCEPT) != 0)		\
+    abort();						\
 }


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