[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