summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2007-07-18 17:30:38 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2007-07-18 17:30:38 +0000
commit7faa1bbb5d0206cc83f20c1145f612f7754fdcf3 (patch)
treeeb2db58c64bbaba8f0181d8d24ef99a386911de5
parentb5d32c25372d1e0604bbd8471d735e46215dbe03 (diff)
downloadgcc-7faa1bbb5d0206cc83f20c1145f612f7754fdcf3.tar.gz
re PR target/30652 (SSE expansion is missing for isinf() and other fpclassify functions)
PR target/30652 PR middle-end/20558 * 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. From-SVN: r126724
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/builtins.c24
-rw-r--r--gcc/c-cppbuiltin.c27
-rw-r--r--gcc/real.c32
-rw-r--r--gcc/real.h4
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/pr28796-1.c31
-rw-r--r--gcc/testsuite/gcc.dg/pr28796-2.c72
8 files changed, 176 insertions, 31 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 94074ff9a72..87ae99a53e5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,17 @@
2007-07-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+ PR target/30652
+ PR middle-end/20558
+
+ * 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.
+
+2007-07-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
PR middle-end/32668
* builtin-attrs.def (ATTR_TYPEGENERIC,
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 44cfc0d48b2..e92e56fbff7 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2275,6 +2275,30 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
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 isgr_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 (isgr_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 --git a/gcc/c-cppbuiltin.c b/gcc/c-cppbuiltin.c
index 19bb47c1410..653c5e48442 100644
--- a/gcc/c-cppbuiltin.c
+++ b/gcc/c-cppbuiltin.c
@@ -200,31 +200,8 @@ builtin_define_float_constants (const char *name_prefix,
/* 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 --git a/gcc/real.c b/gcc/real.c
index b4d617f94d6..258ecf6635b 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -4835,3 +4835,35 @@ real_isinteger (const REAL_VALUE_TYPE *c, enum machine_mode mode)
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 --git a/gcc/real.h b/gcc/real.h
index 09b1e52fb2c..68ad362849d 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -438,4 +438,8 @@ extern void mpfr_from_real (mpfr_ptr, const REAL_VALUE_TYPE *, mp_rnd_t);
/* 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 --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e1a8f1ff828..1c48519a212 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2007-07-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gcc.dg/pr28796-1.c: Add more cases.
+ * gcc.dg/pr28796-2.c: Likewise.
+
2007-07-17 Janus Weil <jaydub66@gmail.com>
PR fortran/32535
diff --git a/gcc/testsuite/gcc.dg/pr28796-1.c b/gcc/testsuite/gcc.dg/pr28796-1.c
index a762becdafb..d200b1a682c 100644
--- a/gcc/testsuite/gcc.dg/pr28796-1.c
+++ b/gcc/testsuite/gcc.dg/pr28796-1.c
@@ -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 --git a/gcc/testsuite/gcc.dg/pr28796-2.c b/gcc/testsuite/gcc.dg/pr28796-2.c
index f76bfed35fa..25454849646 100644
--- a/gcc/testsuite/gcc.dg/pr28796-2.c
+++ b/gcc/testsuite/gcc.dg/pr28796-2.c
@@ -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;
}