diff options
author | Alan Modra <amodra@gmail.com> | 2016-04-08 11:41:52 +0930 |
---|---|---|
committer | Alan Modra <amodra@gcc.gnu.org> | 2016-04-08 11:41:52 +0930 |
commit | 02cf2861fc129e08f39f951d083713e2646e91b2 (patch) | |
tree | 0b388abae31ee926c4acf1f22caf2d032c9e84cd /gcc | |
parent | 1f3955796c066142e3f796353b0e1b4688b38597 (diff) | |
download | gcc-02cf2861fc129e08f39f951d083713e2646e91b2.zip gcc-02cf2861fc129e08f39f951d083713e2646e91b2.tar.gz gcc-02cf2861fc129e08f39f951d083713e2646e91b2.tar.bz2 |
PR70117, ppc long double isinf
gcc/
PR target/70117
* builtins.c (fold_builtin_classify): For IBM extended precision,
look at just the high-order double to test for NaN.
(fold_builtin_interclass_mathfn): Similarly for Inf. For isnormal
test just the high double for Inf but both doubles for subnormal
limit.
gcc/testsuite/
* gcc.target/powerpc/pr70117.c: New.
From-SVN: r234821
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/builtins.c | 100 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/pr70117.c | 92 |
4 files changed, 194 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8e36e50..980ae25 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2016-04-08 Alan Modra <amodra@gmail.com> + + PR target/70117 + * builtins.c (fold_builtin_classify): For IBM extended precision, + look at just the high-order double to test for NaN. + (fold_builtin_interclass_mathfn): Similarly for Inf. For isnormal + test just the high double for Inf but both doubles for subnormal + limit. + 2016-04-07 Jakub Jelinek <jakub@redhat.com> * cgraph.h (struct cgraph_simd_clone): Add mask_mode field. diff --git a/gcc/builtins.c b/gcc/builtins.c index 9368ed0..3d89baf 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -7529,6 +7529,8 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) mode = TYPE_MODE (TREE_TYPE (arg)); + bool is_ibm_extended = MODE_COMPOSITE_P (mode); + /* If there is no optab, try generic code. */ switch (DECL_FUNCTION_CODE (fndecl)) { @@ -7538,10 +7540,18 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) { /* isinf(x) -> isgreater(fabs(x),DBL_MAX). */ tree const isgr_fn = builtin_decl_explicit (BUILT_IN_ISGREATER); - tree const type = TREE_TYPE (arg); + tree type = TREE_TYPE (arg); REAL_VALUE_TYPE r; char buf[128]; + if (is_ibm_extended) + { + /* NaN and Inf are encoded in the high-order double value + only. The low-order value is not significant. */ + type = double_type_node; + mode = DFmode; + arg = fold_build1_loc (loc, NOP_EXPR, type, arg); + } get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); real_from_string (&r, buf); result = build_call_expr (isgr_fn, 2, @@ -7554,10 +7564,18 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) { /* isfinite(x) -> islessequal(fabs(x),DBL_MAX). */ tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL); - tree const type = TREE_TYPE (arg); + tree type = TREE_TYPE (arg); REAL_VALUE_TYPE r; char buf[128]; + if (is_ibm_extended) + { + /* NaN and Inf are encoded in the high-order double value + only. The low-order value is not significant. */ + type = double_type_node; + mode = DFmode; + arg = fold_build1_loc (loc, NOP_EXPR, type, arg); + } get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); real_from_string (&r, buf); result = build_call_expr (isle_fn, 2, @@ -7577,21 +7595,72 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) & islessequal(fabs(x),DBL_MAX). */ tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL); - tree const isge_fn = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL); - tree const type = TREE_TYPE (arg); + tree type = TREE_TYPE (arg); + tree orig_arg, max_exp, min_exp; + machine_mode orig_mode = mode; REAL_VALUE_TYPE rmax, rmin; char buf[128]; + orig_arg = arg = builtin_save_expr (arg); + if (is_ibm_extended) + { + /* Use double to test the normal range of IBM extended + precision. Emin for IBM extended precision is + different to emin for IEEE double, being 53 higher + since the low double exponent is at least 53 lower + than the high double exponent. */ + type = double_type_node; + mode = DFmode; + arg = fold_build1_loc (loc, NOP_EXPR, type, arg); + } + arg = fold_build1_loc (loc, ABS_EXPR, type, arg); + get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); real_from_string (&rmax, buf); - sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1); + sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (orig_mode)->emin - 1); real_from_string (&rmin, buf); - arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg)); - result = build_call_expr (isle_fn, 2, arg, - build_real (type, rmax)); - result = fold_build2 (BIT_AND_EXPR, integer_type_node, result, - build_call_expr (isge_fn, 2, arg, - build_real (type, rmin))); + max_exp = build_real (type, rmax); + min_exp = build_real (type, rmin); + + max_exp = build_call_expr (isle_fn, 2, arg, max_exp); + if (is_ibm_extended) + { + /* Testing the high end of the range is done just using + the high double, using the same test as isfinite(). + For the subnormal end of the range we first test the + high double, then if its magnitude is equal to the + limit of 0x1p-969, we test whether the low double is + non-zero and opposite sign to the high double. */ + tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS); + tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER); + tree gt_min = build_call_expr (isgt_fn, 2, arg, min_exp); + tree eq_min = fold_build2 (EQ_EXPR, integer_type_node, + arg, min_exp); + tree as_complex = build1 (VIEW_CONVERT_EXPR, + complex_double_type_node, orig_arg); + tree hi_dbl = build1 (REALPART_EXPR, type, as_complex); + tree lo_dbl = build1 (IMAGPART_EXPR, type, as_complex); + tree zero = build_real (type, dconst0); + tree hilt = build_call_expr (islt_fn, 2, hi_dbl, zero); + tree lolt = build_call_expr (islt_fn, 2, lo_dbl, zero); + tree logt = build_call_expr (isgt_fn, 2, lo_dbl, zero); + tree ok_lo = fold_build1 (TRUTH_NOT_EXPR, integer_type_node, + fold_build3 (COND_EXPR, + integer_type_node, + hilt, logt, lolt)); + eq_min = fold_build2 (TRUTH_ANDIF_EXPR, integer_type_node, + eq_min, ok_lo); + min_exp = fold_build2 (TRUTH_ORIF_EXPR, integer_type_node, + gt_min, eq_min); + } + else + { + tree const isge_fn + = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL); + min_exp = build_call_expr (isge_fn, 2, arg, min_exp); + } + result = fold_build2 (BIT_AND_EXPR, integer_type_node, + max_exp, min_exp); return result; } default: @@ -7664,6 +7733,15 @@ fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index) if (!HONOR_NANS (arg)) return omit_one_operand_loc (loc, type, integer_zero_node, arg); + { + bool is_ibm_extended = MODE_COMPOSITE_P (TYPE_MODE (TREE_TYPE (arg))); + if (is_ibm_extended) + { + /* NaN and Inf are encoded in the high-order double value + only. The low-order value is not significant. */ + arg = fold_build1_loc (loc, NOP_EXPR, double_type_node, arg); + } + } arg = builtin_save_expr (arg); return fold_build2_loc (loc, UNORDERED_EXPR, type, arg, arg); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7d1f696..7c3af0d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2016-04-08 Alan Modra <amodra@gmail.com> + + * gcc.target/powerpc/pr70117.c: New. + 2016-04-07 Jakub Jelinek <jakub@redhat.com> PR testsuite/70581 diff --git a/gcc/testsuite/gcc.target/powerpc/pr70117.c b/gcc/testsuite/gcc.target/powerpc/pr70117.c new file mode 100644 index 0000000..f1fdedb --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr70117.c @@ -0,0 +1,92 @@ +/* { dg-do run { target { powerpc*-*-linux* powerpc*-*-darwin* powerpc*-*-aix* rs6000-*-* } } } */ +/* { dg-options "-std=c99 -mlong-double-128 -O2" } */ + +#include <float.h> + +union gl_long_double_union +{ + struct { double hi; double lo; } dd; + long double ld; +}; + +/* This is gnulib's LDBL_MAX which, being 107 bits in precision, is + slightly larger than gcc's 106 bit precision LDBL_MAX. */ +volatile union gl_long_double_union gl_LDBL_MAX = + { { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL } }; + +volatile double min_denorm = 0x1p-1074; +volatile double ld_low = 0x1p-969; +volatile double dinf = 1.0/0.0; +volatile double dnan = 0.0/0.0; + +int +main (void) +{ + long double ld; + + ld = gl_LDBL_MAX.ld; + if (__builtin_isinfl (ld)) + __builtin_abort (); + ld = -gl_LDBL_MAX.ld; + if (__builtin_isinfl (ld)) + __builtin_abort (); + + ld = gl_LDBL_MAX.ld; + if (!__builtin_isfinite (ld)) + __builtin_abort (); + ld = -gl_LDBL_MAX.ld; + if (!__builtin_isfinite (ld)) + __builtin_abort (); + + ld = ld_low; + if (!__builtin_isnormal (ld)) + __builtin_abort (); + ld = -ld_low; + if (!__builtin_isnormal (ld)) + __builtin_abort (); + + ld = -min_denorm; + ld += ld_low; + if (__builtin_isnormal (ld)) + __builtin_abort (); + ld = min_denorm; + ld -= ld_low; + if (__builtin_isnormal (ld)) + __builtin_abort (); + + ld = 0.0; + if (__builtin_isnormal (ld)) + __builtin_abort (); + ld = -0.0; + if (__builtin_isnormal (ld)) + __builtin_abort (); + + ld = LDBL_MAX; + if (!__builtin_isnormal (ld)) + __builtin_abort (); + ld = -LDBL_MAX; + if (!__builtin_isnormal (ld)) + __builtin_abort (); + + ld = gl_LDBL_MAX.ld; + if (!__builtin_isnormal (ld)) + __builtin_abort (); + ld = -gl_LDBL_MAX.ld; + if (!__builtin_isnormal (ld)) + __builtin_abort (); + + ld = dinf; + if (__builtin_isnormal (ld)) + __builtin_abort (); + ld = -dinf; + if (__builtin_isnormal (ld)) + __builtin_abort (); + + ld = dnan; + if (__builtin_isnormal (ld)) + __builtin_abort (); + ld = -dnan; + if (__builtin_isnormal (ld)) + __builtin_abort (); + return 0; +} |