[PATCH take 2] middle-end: provide generic implementation for isinf
Kaveh R. GHAZI
ghazi@caip.rutgers.edu
Sat Jun 16 05:09:00 GMT 2007
This patch is my second attempt at generating generic code to handle
fpclassify functions. The original thread started here:
http://gcc.gnu.org/ml/gcc-patches/2007-06/msg00752.html
Although I'm calling this "take 2", this time I'm doing "isinf" instead of
"finite". However I intend to address as many of the fpclassify functions
as possible in later patches if this approach is approved. I followed
rth's recommendation in PR target/30652 which was to convert isinf(x) to
isgreater(fabs(x),MAX), where MAX is FLT_MAX, DBL_MAX or LDBL_MAX
depending on the type of 'x'. In order to grab those values, I moved the
MAX generation code from c-cppbuiltin.c to real.c so that the middle-end
could call it as well.
This method should be correct with regards to FP exceptions and
signaling NaNs. And the transformation occurs only after optabs in
case a particular target wants to provide a specific mechanism that's
better, smaller, faster... queue theme music from "$6M man". :-)
Tested on sparc-sun-solaris2.10, no regressions and the expanded
testcases pass.
Okay for mainline?
Thanks,
--Kaveh
2007-06-15 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
PR target/30652
* builtins.c (expand_builtin_interclass_mathfn): Provide a
generic fallback for isinf.
* c-cppbuiltin.c (builtin_define_float_constants): Move FP max
calculation code ...
* real.c (get_max_float): ... to here.
* real.h (get_max_float): New.
testsuite:
* gcc.dg/pr28796-1.c: Add more cases.
* gcc.dg/pr28796-2.c: Likewise.
diff -rup orig/egcc-SVN20070615/gcc/builtins.c egcc-SVN20070615/gcc/builtins.c
--- orig/egcc-SVN20070615/gcc/builtins.c 2007-06-12 14:38:41.000000000 -0400
+++ egcc-SVN20070615/gcc/builtins.c 2007-06-15 11:57:55.941544755 -0400
@@ -2271,6 +2271,30 @@ expand_builtin_interclass_mathfn (tree e
return target;
}
+ /* If there is no optab, try generic code. */
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ tree result;
+
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ {
+ /* isinf(x) -> isgreater(fabs(x),DBL_MAX). */
+ tree const isle_fn = built_in_decls[BUILT_IN_ISGREATER];
+ tree const type = TREE_TYPE (arg);
+ REAL_VALUE_TYPE r;
+ char buf[128];
+
+ get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+ real_from_string (&r, buf);
+ result = build_call_expr (isle_fn, 2,
+ fold_build1 (ABS_EXPR, type, arg),
+ build_real (type, r));
+ return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
+ }
+ default:
+ break;
+ }
+
target = expand_call (exp, target, target == const0_rtx);
return target;
diff -rup orig/egcc-SVN20070615/gcc/c-cppbuiltin.c egcc-SVN20070615/gcc/c-cppbuiltin.c
--- orig/egcc-SVN20070615/gcc/c-cppbuiltin.c 2007-06-07 23:05:51.000000000 -0400
+++ egcc-SVN20070615/gcc/c-cppbuiltin.c 2007-06-15 11:57:48.676026895 -0400
@@ -200,31 +200,8 @@ builtin_define_float_constants (const ch
/* Since, for the supported formats, B is always a power of 2, we
construct the following numbers directly as a hexadecimal
constants. */
-
- /* The maximum representable finite floating-point number,
- (1 - b**-p) * b**emax */
- {
- int i, n;
- char *p;
-
- strcpy (buf, "0x0.");
- n = fmt->p;
- for (i = 0, p = buf + 4; i + 3 < n; i += 4)
- *p++ = 'f';
- if (i < n)
- *p++ = "08ce"[n - i];
- sprintf (p, "p%d", fmt->emax);
- if (fmt->pnan < fmt->p)
- {
- /* This is an IBM extended double format made up of two IEEE
- doubles. The value of the long double is the sum of the
- values of the two parts. The most significant part is
- required to be the value of the long double rounded to the
- nearest double. Rounding means we need a slightly smaller
- value for LDBL_MAX. */
- buf[4 + fmt->pnan / 4] = "7bde"[fmt->pnan % 4];
- }
- }
+ get_max_float (fmt, buf, sizeof (buf));
+
sprintf (name, "__%s_MAX__", name_prefix);
builtin_define_with_hex_fp_value (name, type, decimal_dig, buf, fp_suffix, fp_cast);
diff -rup orig/egcc-SVN20070615/gcc/real.c egcc-SVN20070615/gcc/real.c
--- orig/egcc-SVN20070615/gcc/real.c 2007-06-12 14:38:41.000000000 -0400
+++ egcc-SVN20070615/gcc/real.c 2007-06-15 12:00:08.567831834 -0400
@@ -4835,3 +4835,35 @@ real_isinteger (const REAL_VALUE_TYPE *c
real_trunc (&cint, mode, c);
return real_identical (c, &cint);
}
+
+/* Write into BUF the maximum representable finite floating-point
+ number, (1 - b**-p) * b**emax for a given FP format FMT as a hex
+ float string. LEN is the size of BUF, and the buffer must be large
+ enough to contain the resulting string. */
+
+void
+get_max_float (const struct real_format *fmt, char *buf, size_t len)
+{
+ int i, n;
+ char *p;
+
+ strcpy (buf, "0x0.");
+ n = fmt->p;
+ for (i = 0, p = buf + 4; i + 3 < n; i += 4)
+ *p++ = 'f';
+ if (i < n)
+ *p++ = "08ce"[n - i];
+ sprintf (p, "p%d", fmt->emax);
+ if (fmt->pnan < fmt->p)
+ {
+ /* This is an IBM extended double format made up of two IEEE
+ doubles. The value of the long double is the sum of the
+ values of the two parts. The most significant part is
+ required to be the value of the long double rounded to the
+ nearest double. Rounding means we need a slightly smaller
+ value for LDBL_MAX. */
+ buf[4 + fmt->pnan / 4] = "7bde"[fmt->pnan % 4];
+ }
+
+ gcc_assert (strlen (buf) < len);
+}
diff -rup orig/egcc-SVN20070615/gcc/real.h egcc-SVN20070615/gcc/real.h
--- orig/egcc-SVN20070615/gcc/real.h 2007-06-12 14:38:41.000000000 -0400
+++ egcc-SVN20070615/gcc/real.h 2007-06-15 11:55:11.107721214 -0400
@@ -438,4 +438,8 @@ extern void mpfr_from_real (mpfr_ptr, co
/* Check whether the real constant value given is an integer. */
extern bool real_isinteger (const REAL_VALUE_TYPE *c, enum machine_mode mode);
+/* Write into BUF the maximum representable finite floating-point
+ number, (1 - b**-p) * b**emax for a given FP format FMT as a hex
+ float string. BUF must be large enough to contain the result. */
+extern void get_max_float (const struct real_format *, char *, size_t);
#endif /* ! GCC_REAL_H */
diff -rup orig/egcc-SVN20070615/gcc/testsuite/gcc.dg/pr28796-1.c egcc-SVN20070615/gcc/testsuite/gcc.dg/pr28796-1.c
--- orig/egcc-SVN20070615/gcc/testsuite/gcc.dg/pr28796-1.c 2006-10-24 13:50:51.000000000 -0400
+++ egcc-SVN20070615/gcc/testsuite/gcc.dg/pr28796-1.c 2007-06-15 11:22:18.709713436 -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-SVN20070615/gcc/testsuite/gcc.dg/pr28796-2.c egcc-SVN20070615/gcc/testsuite/gcc.dg/pr28796-2.c
--- orig/egcc-SVN20070615/gcc/testsuite/gcc.dg/pr28796-2.c 2007-04-20 20:02:27.000000000 -0400
+++ egcc-SVN20070615/gcc/testsuite/gcc.dg/pr28796-2.c 2007-06-15 11:43:50.265136348 -0400
@@ -4,19 +4,79 @@
extern void abort (void);
-void foo(float f)
+void __attribute__ ((__noinline__))
+foo_1 (float f, double d, long double ld,
+ int res_unord, int res_isnan, int res_isinf, int res_isfin)
{
- if (__builtin_isunordered (f, f) != 1)
+ if (__builtin_isunordered (f, 0) != res_unord)
abort ();
- if (__builtin_isnan (f) != 1)
+ if (__builtin_isunordered (0, f) != res_unord)
abort ();
- if (__builtin_finite (f) != 0)
+ if (__builtin_isunordered (d, 0) != res_unord)
+ abort ();
+ if (__builtin_isunordered (0, d) != res_unord)
+ abort ();
+ if (__builtin_isunordered (ld, 0) != res_unord)
+ abort ();
+ if (__builtin_isunordered (0, 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_isinf (f) != res_isinf)
+ abort ();
+ if (__builtin_isinf (d) != res_isinf)
+ abort ();
+ if (__builtin_isinf (ld) != res_isinf)
+ abort ();
+ if (__builtin_isinff (f) != res_isinf)
+ abort ();
+ if (__builtin_isinfl (ld) != res_isinf)
+ abort ();
+
+ if (__builtin_finite (f) != res_isfin)
+ abort ();
+ if (__builtin_finite (d) != res_isfin)
abort ();
}
+void __attribute__ ((__noinline__))
+foo (float f, double d, long double ld,
+ int res_unord, int res_isnan, int res_isinf, int res_isfin)
+{
+ foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isfin);
+ foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, res_isfin);
+}
+
int main()
{
- float f = __builtin_nanf("");
- foo(f);
+ float f;
+ double d;
+ long double ld;
+
+ f = __builtin_nanf(""); d = __builtin_nan(""); ld = __builtin_nanl("");
+ foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isinf=*/ 0, /*isfin=*/ 0);
+
+ f = __builtin_inff(); d = __builtin_inf(); ld = __builtin_infl();
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0);
+
+ f = 0; d = 0; ld = 0;
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1);
+
+ f = __FLT_MIN__; d = __DBL_MIN__; ld = __LDBL_MIN__;
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1);
+
+ f = __FLT_MAX__; d = __DBL_MAX__; ld = __LDBL_MAX__;
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1);
+
return 0;
}
More information about the Gcc-patches
mailing list