[PATCH] middle-end: convert builtin finite -> MINUS/ORD

Kaveh R. GHAZI ghazi@caip.rutgers.edu
Tue Jun 12 06:03:00 GMT 2007


This patch adds a transformation of builtin finite(x) into:

	tmp = x - x;
	result = tmp ORD tmp;

We already do something similar (but simpler) for builtin isnan.

This particular transformation works because "x - x" turns Inf into NaN,
while preserving an existing NaN.  Then the ORD returns true if we don't
have NaN, i.e. a finite original value.  (I got the idea from libgcc2.c.)

One glich was that the "x - x" got folded to zero with only the flag
-funsafe-math-optimizations.  I added an additional check on !HONOR_NANS
and !HONOR_INFINITIES to those transformations.  These macros check (among
other things) for -ffinite-math-only before folding "x - x".  I had to
leave the "unsafe" check in there because the comments indicate that there
are some wierd corner cases where folding "x - x" to zero is actually
invalid for non-ieee finite values.

I also filled out the existing two tests with more cases to cover all
floating point types.

Tested on sparc-sun-solaris2.10, no regressions and all the testcases
pass.

Okay for mainline?

		Thanks,
		--Kaveh

2007-06-11  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* builtins.c (fold_builtin_classify): Transform builtin finite.

	* fold-const.c (fold_binary): Guard (X-X) -> 0 transformation
	with !HONOR_NANS and !HONOR_INFINITIES.
	* simplify-rtx.c (simplify_binary_operation_1): Likewise.

testsuite:
	* gcc.dg/pr28796-1.c: Add more cases.
	* gcc.dg/pr28796-2.c: Likewise.

diff -rup orig/egcc-SVN20070609/gcc/builtins.c egcc-SVN20070609/gcc/builtins.c
--- orig/egcc-SVN20070609/gcc/builtins.c	2007-05-22 23:03:30.000000000 -0400
+++ egcc-SVN20070609/gcc/builtins.c	2007-06-11 11:52:20.557323014 -0400
@@ -9485,7 +9485,12 @@ fold_builtin_classify (tree fndecl, tree
 		 ? integer_zero_node : integer_one_node;
 	}

-      return NULL_TREE;
+      /* First, "X - X" preserves NaN and converts +-Inf to Nan.  */
+      arg = builtin_save_expr (arg);
+      arg = fold_build2 (MINUS_EXPR, TREE_TYPE (arg), arg, arg);
+      /* Then "X ORD X" checks if we're not NaN.  */
+      arg = builtin_save_expr (arg);
+      return fold_build2 (ORDERED_EXPR, type, arg, arg);

     case BUILT_IN_ISNAN:
       if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg))))
diff -rup orig/egcc-SVN20070609/gcc/fold-const.c egcc-SVN20070609/gcc/fold-const.c
--- orig/egcc-SVN20070609/gcc/fold-const.c	2007-06-07 23:05:51.000000000 -0400
+++ egcc-SVN20070609/gcc/fold-const.c	2007-06-11 14:54:59.157437259 -0400
@@ -9585,7 +9585,10 @@ fold_binary (enum tree_code code, tree t
 	 Also note that operand_equal_p is always false if an operand
 	 is volatile.  */

-      if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
+      if ((! FLOAT_TYPE_P (type)
+	   || (flag_unsafe_math_optimizations
+	       && !HONOR_NANS (TYPE_MODE (type))
+	       && !HONOR_INFINITIES (TYPE_MODE (type))))
 	  && operand_equal_p (arg0, arg1, 0))
 	return fold_convert (type, integer_zero_node);

diff -rup orig/egcc-SVN20070609/gcc/simplify-rtx.c egcc-SVN20070609/gcc/simplify-rtx.c
--- orig/egcc-SVN20070609/gcc/simplify-rtx.c	2007-04-11 20:02:30.000000000 -0400
+++ egcc-SVN20070609/gcc/simplify-rtx.c	2007-06-11 14:55:28.231325841 -0400
@@ -1772,10 +1772,14 @@ simplify_binary_operation_1 (enum rtx_co
     case MINUS:
       /* We can't assume x-x is 0 even with non-IEEE floating point,
 	 but since it is zero except in very strange circumstances, we
-	 will treat it as zero with -funsafe-math-optimizations.  */
+	 will treat it as zero with -funsafe-math-optimizations and
+	 -ffinite-math-only.  */
       if (rtx_equal_p (trueop0, trueop1)
 	  && ! side_effects_p (op0)
-	  && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
+	  && (! FLOAT_MODE_P (mode)
+	      || (flag_unsafe_math_optimizations
+		  && !HONOR_NANS (mode)
+		  && !HONOR_INFINITIES (mode))))
 	return CONST0_RTX (mode);

       /* Change subtraction from zero into negation.  (0 - x) is the
diff -rup orig/egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-1.c egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-1.c
--- orig/egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-1.c	2006-10-24 13:50:51.000000000 -0400
+++ egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-1.c	2007-06-11 12:49:28.237400824 -0400
@@ -1,17 +1,48 @@
 /* { dg-do link } */
 /* { dg-options "-ffinite-math-only" } */

+extern void link_error(void);
+
 float f;
+double d;
+long double ld;

 int main()
 {
   if (__builtin_isunordered (f, f) != 0)
     link_error ();
+  if (__builtin_isunordered (d, d) != 0)
+    link_error ();
+  if (__builtin_isunordered (ld, ld) != 0)
+    link_error ();
+
   if (__builtin_isnan (f) != 0)
     link_error ();
+  if (__builtin_isnan (d) != 0)
+    link_error ();
+  if (__builtin_isnan (ld) != 0)
+    link_error ();
+  if (__builtin_isnanf (f) != 0)
+    link_error ();
+  if (__builtin_isnanl (ld) != 0)
+    link_error ();
+
   if (__builtin_finite (f) != 1)
     link_error ();
+  if (__builtin_finite (d) != 1)
+    link_error ();
+  if (__builtin_finite (ld) != 1)
+    link_error ();
+  if (__builtin_finitef (f) != 1)
+    link_error ();
+  if (__builtin_finitel (ld) != 1)
+    link_error ();
+
   if (f != f)
     link_error ();
+  if (d != d)
+    link_error ();
+  if (ld != ld)
+    link_error ();
   return 0;
 }
diff -rup orig/egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-2.c egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-2.c
--- orig/egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-2.c	2007-04-20 20:02:27.000000000 -0400
+++ egcc-SVN20070609/gcc/testsuite/gcc.dg/pr28796-2.c	2007-06-12 01:24:31.844756570 -0400
@@ -4,19 +4,65 @@

 extern void abort (void);

-void foo(float f)
+void __attribute__ ((__noinline__))
+foo(float f, double d, long double ld,
+    int res_unord, int res_isnan, int res_isfin)
 {
-  if (__builtin_isunordered (f, f) != 1)
+  if (__builtin_isunordered (f, f) != res_unord)
     abort ();
-  if (__builtin_isnan (f) != 1)
+  if (__builtin_isunordered (d, d) != res_unord)
     abort ();
-  if (__builtin_finite (f) != 0)
+  if (__builtin_isunordered (ld, ld) != res_unord)
+    abort ();
+
+  if (__builtin_isnan (f) != res_isnan)
+    abort ();
+  if (__builtin_isnan (d) != res_isnan)
+    abort ();
+  if (__builtin_isnan (ld) != res_isnan)
+    abort ();
+  if (__builtin_isnanf (f) != res_isnan)
+    abort ();
+  if (__builtin_isnanl (ld) != res_isnan)
+    abort ();
+
+  if (__builtin_finite (f) != res_isfin)
+    abort ();
+  if (__builtin_finite (d) != res_isfin)
+    abort ();
+  if (__builtin_finite (ld) != res_isfin)
+    abort ();
+  if (__builtin_finitef (f) != res_isfin)
+    abort ();
+  if (__builtin_finitel (ld) != res_isfin)
     abort ();
 }

 int main()
 {
   float f = __builtin_nanf("");
-  foo(f);
+  double d = __builtin_nan("");
+  long double ld = __builtin_nanl("");
+
+  foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isfin=*/ 0);
+
+  f = __builtin_inff();
+  d = __builtin_inf();
+  ld = __builtin_infl();
+
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isfin=*/ 0);
+
+  f = -__builtin_inff();
+  d = -__builtin_inf();
+  ld = -__builtin_infl();
+
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isfin=*/ 0);
+
+  f = 0;
+  d = 0;
+  ld = 0;
+
+  foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isfin=*/ 1);
+
   return 0;
 }



More information about the Gcc-patches mailing list