re PR target/71869 (__builtin_isgreater raises an invalid exception on PPC64 using...
authorMichael Meissner <meissner@linux.vnet.ibm.com>
Wed, 27 Jul 2016 04:45:59 +0000 (04:45 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Wed, 27 Jul 2016 04:45:59 +0000 (04:45 +0000)
[gcc]
2016-07-26  Michael Meissner  <meissner@linux.vnet.ibm.com>

PR target/71869
* config/rs6000/rs6000.c (rs6000_generate_compare): Rework
__float128 support when we don't have hardware support, so that
the IEEE built-in functions like isgreater, first call __unordkf3
to make sure neither operand is a NaN, and if both operands are
ordered, do the normal comparison.

[gcc/testsuite]
2016-07-26  Michael Meissner  <meissner@linux.vnet.ibm.com>

PR target/71869
* gcc.target/powerpc/float128-cmp.c: New test to make sure that
IEEE built-in functions handle quiet and signalling NaNs
correctly.

From-SVN: r238779

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/float128-cmp.c [new file with mode: 0644]

index 53cfe65987c5ddfa7ea5fe099105401b9c4b3eb5..acab50dbceecd472799849aa1c1011b59be58a3d 100644 (file)
@@ -1,3 +1,12 @@
+2016-07-26  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       PR target/71869
+       * config/rs6000/rs6000.c (rs6000_generate_compare): Rework
+       __float128 support when we don't have hardware support, so that
+       the IEEE built-in functions like isgreater, first call __unordkf3
+       to make sure neither operand is a NaN, and if both operands are
+       ordered, do the normal comparison.
+
 2016-07-26  Patrick Palka  <ppalka@gcc.gnu.org>
 
        * tree-vrp.c (dump_asserts_for): Print loc->expr instead of
index cea764b5a7103b5b13925d600ae3d1b5908801be..8a3e7994c9596e5fd79eba276105ab7479f05926 100644 (file)
@@ -21756,8 +21756,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
   else if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode))
     {
       rtx libfunc = NULL_RTX;
-      bool uneq_or_ltgt = false;
-      rtx dest = gen_reg_rtx (SImode);
+      bool check_nan = false;
+      rtx dest;
 
       switch (code)
        {
@@ -21784,21 +21784,23 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
 
        case UNGE:
        case UNGT:
-         libfunc = optab_libfunc (le_optab, mode);
+         check_nan = true;
+         libfunc = optab_libfunc (ge_optab, mode);
          code = (code == UNGE) ? GE : GT;
          break;
 
        case UNLE:
        case UNLT:
-         libfunc = optab_libfunc (ge_optab, mode);
+         check_nan = true;
+         libfunc = optab_libfunc (le_optab, mode);
          code = (code == UNLE) ? LE : LT;
          break;
 
        case UNEQ:
        case LTGT:
-         libfunc = optab_libfunc (le_optab, mode);
-         uneq_or_ltgt = true;
-         code = (code = UNEQ) ? NE : EQ;
+         check_nan = true;
+         libfunc = optab_libfunc (eq_optab, mode);
+         code = (code = UNEQ) ? EQ : NE;
          break;
 
        default:
@@ -21806,21 +21808,56 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
        }
 
       gcc_assert (libfunc);
-      dest = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
-                                     SImode, 2, op0, mode, op1, mode);
-
-      /* If this is UNEQ or LTGT, we call __lekf2, which returns -1 for less
-        than, 0 for equal, +1 for greater, and +2 for nan.  We add 1, to give
-        a value of 0..3, and then do and AND immediate of 1 to isolate whether
-        it is 0/Nan (i.e. bottom bit is 0), or less than/greater than
-        (i.e. bottom bit is 1).  */
-      if (uneq_or_ltgt)
-       {
-         rtx add_result = gen_reg_rtx (SImode);
-         rtx and_result = gen_reg_rtx (SImode);
-         emit_insn (gen_addsi3 (add_result, dest, GEN_INT (1)));
-         emit_insn (gen_andsi3 (and_result, add_result, GEN_INT (1)));
-         dest = and_result;
+
+      if (!check_nan)
+       dest = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+                                       SImode, 2, op0, mode, op1, mode);
+
+      /* The library signals an exception for signalling NaNs, so we need to
+        handle isgreater, etc. by first checking isordered.  */
+      else
+       {
+         rtx ne_rtx, normal_dest, unord_dest;
+         rtx unord_func = optab_libfunc (unord_optab, mode);
+         rtx join_label = gen_label_rtx ();
+         rtx join_ref = gen_rtx_LABEL_REF (VOIDmode, join_label);
+         rtx unord_cmp = gen_reg_rtx (comp_mode);
+
+
+         /* Test for either value being a NaN.  */
+         gcc_assert (unord_func);
+         unord_dest = emit_library_call_value (unord_func, NULL_RTX, LCT_CONST,
+                                               SImode, 2, op0, mode, op1,
+                                               mode);
+
+         /* Set value (0) if either value is a NaN, and jump to the join
+            label.  */
+         dest = gen_reg_rtx (SImode);
+         emit_move_insn (dest, const1_rtx);
+         emit_insn (gen_rtx_SET (unord_cmp,
+                                 gen_rtx_COMPARE (comp_mode, unord_dest,
+                                                  const0_rtx)));
+
+         ne_rtx = gen_rtx_NE (comp_mode, unord_cmp, const0_rtx);
+         emit_jump_insn (gen_rtx_SET (pc_rtx,
+                                      gen_rtx_IF_THEN_ELSE (VOIDmode, ne_rtx,
+                                                            join_ref,
+                                                            pc_rtx)));
+
+         /* Do the normal comparison, knowing that the values are not
+            NaNs.  */
+         normal_dest = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+                                                SImode, 2, op0, mode, op1,
+                                                mode);
+
+         emit_insn (gen_cstoresi4 (dest,
+                                   gen_rtx_fmt_ee (code, SImode, normal_dest,
+                                                   const0_rtx),
+                                   normal_dest, const0_rtx));
+
+         /* Join NaN and non-Nan paths.  Compare dest against 0.  */
+         emit_label (join_label);
+         code = NE;
        }
 
       emit_insn (gen_rtx_SET (compare_result,
index 3c335c6eb424f41a85a3e7a1af524349a586a9e8..0b8b40572b027c8835538dcb5ff85e430193073c 100644 (file)
@@ -1,3 +1,10 @@
+2016-07-26  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       PR target/71869
+       * gcc.target/powerpc/float128-cmp.c: New test to make sure that
+       IEEE built-in functions handle quiet and signalling NaNs
+       correctly.
+
 2016-07-26  Steven G. Kargl  <kargl@gcc.gnu.org>
 
        PR fortran/71862
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-cmp.c b/gcc/testsuite/gcc.target/powerpc/float128-cmp.c
new file mode 100644 (file)
index 0000000..247abc0
--- /dev/null
@@ -0,0 +1,106 @@
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -O2 -mfloat128" } */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifndef TYPE
+#define TYPE __float128
+#define NAN __builtin_nanq ("")
+#define SNAN __builtin_nansq ("")
+#else
+#define NAN __builtin_nan ("")
+#define SNAN __builtin_nans ("")
+#endif
+
+extern void check (TYPE a,
+                  TYPE b,
+                  int eq,
+                  int ne,
+                  int lt,
+                  int le,
+                  int gt,
+                  int ge,
+                  int i_lt,
+                  int i_le,
+                  int i_gt,
+                  int i_ge,
+                  int i_lg,
+                  int i_un) __attribute__((__noinline__));
+
+void
+check (TYPE a,
+       TYPE b,
+       int eq,
+       int ne,
+       int lt,
+       int le,
+       int gt,
+       int ge,
+       int i_lt,
+       int i_le,
+       int i_gt,
+       int i_ge,
+       int i_lg,
+       int i_un)
+{
+  if (eq != (a == b))
+    abort ();
+
+  if (ne != (a != b))
+    abort ();
+
+  if (lt != (a < b))
+    abort ();
+
+  if (le != (a <= b))
+    abort ();
+
+  if (gt != (a > b))
+    abort ();
+
+  if (ge != (a >= b))
+    abort ();
+
+  if (i_lt != __builtin_isless (a, b))
+    abort ();
+
+  if (i_le != __builtin_islessequal (a, b))
+    abort ();
+
+  if (i_gt != __builtin_isgreater (a, b))
+    abort ();
+
+  if (i_ge != __builtin_isgreaterequal (a, b))
+    abort ();
+
+  if (i_lg != __builtin_islessgreater (a, b))
+    abort ();
+
+  if (i_un != __builtin_isunordered (a, b))
+    abort ();
+}
+
+int main (void)
+{
+  TYPE one   = (TYPE) +1.0;
+  TYPE two   = (TYPE) +2.0;
+  TYPE pzero = (TYPE) +0.0;
+  TYPE mzero = (TYPE) -0.0;
+  TYPE nan   = (TYPE) NAN;
+  TYPE snan  = (TYPE) SNAN;
+
+  check (one,   two,   0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0);
+  check (one,   one,   1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0);
+  check (one,   pzero, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0);
+  check (mzero, pzero, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0);
+  check (nan,   one,   0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+  check (one,   nan,   0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+  check (nan,   nan,   0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+  check (snan,  one,   0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+  check (one,   snan,  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+  check (snan,  nan,   0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+  check (nan,   snan,  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+  return 0;
+}