]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR70117, ppc long double isinf
authorAlan Modra <amodra@gmail.com>
Mon, 11 Apr 2016 13:47:40 +0000 (23:17 +0930)
committerAlan Modra <amodra@gcc.gnu.org>
Mon, 11 Apr 2016 13:47:40 +0000 (23:17 +0930)
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: r234881

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/pr70117.c [new file with mode: 0644]

index fd415c9487a46dc2bad974569ae974260f26204b..e8c7f2d6be1b71ae178b14ec1e84634b7e14f031 100644 (file)
@@ -1,3 +1,12 @@
+2016-04-11  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-05  John David Anglin  <danglin@gcc.gnu.org>
 
        * config/pa/predicates.md (integer_store_memory_operand): Accept
index 0825391a0d351acad410fa63ca4f5563b3983966..7d536398daa3976f149e498c4b1ef9e448f3d405 100644 (file)
@@ -9997,6 +9997,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))
     {
@@ -10006,10 +10008,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,
@@ -10022,10 +10032,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,
@@ -10045,21 +10063,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:
@@ -10154,6 +10223,15 @@ fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
          return real_isnan (&r) ? integer_one_node : integer_zero_node;
        }
 
+      {
+       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);
 
index 5207ec1fb0a7c1592029f83f19516c9fd71d3860..8676cd5d1185dced0d918cfd40d8341db3eb5128 100644 (file)
@@ -1,3 +1,7 @@
+2016-04-11  Alan Modra  <amodra@gmail.com>
+
+       * gcc.target/powerpc/pr70117.c: New.
+
 2016-04-05  Dominique d'Humieres  <dominiq@lps.ens.fr>
            Jerry DeLisle  <jvdelisle@gcc.gnu.org>
 
diff --git a/gcc/testsuite/gcc.target/powerpc/pr70117.c b/gcc/testsuite/gcc.target/powerpc/pr70117.c
new file mode 100644 (file)
index 0000000..f1fdedb
--- /dev/null
@@ -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;
+}