aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMichael Meissner <meissner@linux.vnet.ibm.com>2016-07-27 04:45:59 +0000
committerMichael Meissner <meissner@gcc.gnu.org>2016-07-27 04:45:59 +0000
commit71abba1e35b19466c722cc987c115a1f6546a1a6 (patch)
tree76123d85bedded1b1d2c3de87dfbed9c00881dce /gcc
parent2f65c3b3377fc645b071f826f8f02776fb11cae8 (diff)
downloadgcc-71abba1e35b19466c722cc987c115a1f6546a1a6.zip
gcc-71abba1e35b19466c722cc987c115a1f6546a1a6.tar.gz
gcc-71abba1e35b19466c722cc987c115a1f6546a1a6.tar.bz2
re PR target/71869 (__builtin_isgreater raises an invalid exception on PPC64 using __float128 inputs.)
[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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/config/rs6000/rs6000.c81
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.target/powerpc/float128-cmp.c106
4 files changed, 181 insertions, 22 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 53cfe65..acab50d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index cea764b..8a3e799 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3c335c6..0b8b405 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..247abc0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-cmp.c
@@ -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;
+}