From: Michael Meissner Date: Wed, 27 Jul 2016 04:45:59 +0000 (+0000) Subject: re PR target/71869 (__builtin_isgreater raises an invalid exception on PPC64 using... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=71abba1e35b19466c722cc987c115a1f6546a1a6;p=gcc.git re PR target/71869 (__builtin_isgreater raises an invalid exception on PPC64 using __float128 inputs.) [gcc] 2016-07-26 Michael Meissner 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 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 53cfe65987c..acab50dbcee 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2016-07-26 Michael Meissner + + 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 * 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 cea764b5a71..8a3e7994c95 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 3c335c6eb42..0b8b40572b0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2016-07-26 Michael Meissner + + 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 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 00000000000..247abc0f7d9 --- /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 +#include + +#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; +}