On Tue, Jul 26, 2016 at 06:26:19PM -0500, Segher Boessenkool wrote: > On Tue, Jul 26, 2016 at 04:09:01PM -0400, Michael Meissner wrote: > > > Could you test all five functions please? Use multiple testcases, maybe. > > > > I decided to write an executable test rather than do more assembly tests. > > The > > patch to rs6000.c is unchanged, and the test now tests all of the comparison > > operators and functions with various values including quiet NaNs and > > signalling > > NaNs. It passes on power7 big endian 64-bit, power7 big endian 32-bit, > > power8 > > little endian 64-bit, and I ran it on the power9 simulator with hardware > > float128 support. > > > --- gcc/testsuite/gcc.target/powerpc/float128-cmp.c (revision 0) > > +++ gcc/testsuite/gcc.target/powerpc/float128-cmp.c (revision 0) > > @@ -0,0 +1,106 @@ > > +/* { dg-do compile { target { powerpc*-*-linux* } } } */ > > +/* { dg-require-effective-target ppc_float128_sw } */ > > +/* { dg-options "-mvsx -O2 -mfloat128" } */ > > dg-do compile? That's not testing much then, as an executable test!
Good catch. Hopefully, third time is a charm. I verified that changing the dg-do compile to dg-do run did run properly on a big endian power7 (both 32-bit and 64-bit) and a little endian power8. [gcc] 2016-07-26 Michael Meissner <meiss...@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 <meiss...@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. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 238730) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -21755,8 +21755,8 @@ rs6000_generate_compare (rtx cmp, machin 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) { @@ -21783,21 +21783,23 @@ rs6000_generate_compare (rtx cmp, machin 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: @@ -21805,21 +21807,56 @@ rs6000_generate_compare (rtx cmp, machin } 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: gcc/testsuite/gcc.target/powerpc/float128-cmp.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/float128-cmp.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/float128-cmp.c (revision 0) @@ -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; +}