diff --git a/gcc/builtins.cc b/gcc/builtins.cc index 6dff5214ff8..e2e99d6a995 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -171,6 +171,7 @@ static tree fold_builtin_fabs (location_t, tree, tree); static tree fold_builtin_abs (location_t, tree, tree); static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum tree_code, enum tree_code); +static tree fold_builtin_iseqsig (location_t, tree, tree); static tree fold_builtin_varargs (location_t, tree, tree*, int); static tree fold_builtin_strpbrk (location_t, tree, tree, tree, tree); @@ -9445,6 +9446,42 @@ fold_builtin_unordered_cmp (location_t loc, tree fndecl, tree arg0, tree arg1, fold_build2_loc (loc, code, type, arg0, arg1)); } +/* Fold a call to __builtin_iseqsig(). ARG0 and ARG1 are the arguments. + After choosing the wider floating-point type for the comparison, + the code is folded to: + SAVE_EXPR >= SAVE_EXPR && SAVE_EXPR <= SAVE_EXPR */ + +static tree +fold_builtin_iseqsig (location_t loc, tree arg0, tree arg1) +{ + tree type0, type1; + enum tree_code code0, code1; + tree cmp1, cmp2, cmp_type = NULL_TREE; + + type0 = TREE_TYPE (arg0); + type1 = TREE_TYPE (arg1); + + code0 = TREE_CODE (type0); + code1 = TREE_CODE (type1); + + if (code0 == REAL_TYPE && code1 == REAL_TYPE) + /* Choose the wider of two real types. */ + cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1) + ? type0 : type1; + else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE) + cmp_type = type0; + else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE) + cmp_type = type1; + + arg0 = builtin_save_expr (fold_convert_loc (loc, cmp_type, arg0)); + arg1 = builtin_save_expr (fold_convert_loc (loc, cmp_type, arg1)); + + cmp1 = fold_build2_loc (loc, GE_EXPR, integer_type_node, arg0, arg1); + cmp2 = fold_build2_loc (loc, LE_EXPR, integer_type_node, arg0, arg1); + + return fold_build2_loc (loc, TRUTH_AND_EXPR, integer_type_node, cmp1, cmp2); +} + /* Fold __builtin_{,s,u}{add,sub,mul}{,l,ll}_overflow, either into normal arithmetics if it can never overflow, or into internal functions that return both result of arithmetics and overflowed boolean flag in @@ -9878,6 +9915,9 @@ fold_builtin_2 (location_t loc, tree expr, tree fndecl, tree arg0, tree arg1) arg0, arg1, UNORDERED_EXPR, NOP_EXPR); + case BUILT_IN_ISEQSIG: + return fold_builtin_iseqsig (loc, arg0, arg1); + /* We do the folding for va_start in the expander. */ case BUILT_IN_VA_START: break; @@ -11396,6 +11436,7 @@ is_inexpensive_builtin (tree decl) case BUILT_IN_ISLESSEQUAL: case BUILT_IN_ISLESSGREATER: case BUILT_IN_ISUNORDERED: + case BUILT_IN_ISEQSIG: case BUILT_IN_VA_ARG_PACK: case BUILT_IN_VA_ARG_PACK_LEN: case BUILT_IN_VA_COPY: diff --git a/gcc/builtins.def b/gcc/builtins.def index 76e7200e772..5953266acba 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -1029,6 +1029,7 @@ DEF_GCC_BUILTIN (BUILT_IN_ISLESS, "isless", BT_FN_INT_VAR, ATTR_CONST_NOT DEF_GCC_BUILTIN (BUILT_IN_ISLESSEQUAL, "islessequal", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF) DEF_GCC_BUILTIN (BUILT_IN_ISLESSGREATER, "islessgreater", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF) DEF_GCC_BUILTIN (BUILT_IN_ISUNORDERED, "isunordered", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF) +DEF_GCC_BUILTIN (BUILT_IN_ISEQSIG, "iseqsig", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF) DEF_GCC_BUILTIN (BUILT_IN_ISSIGNALING, "issignaling", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF) DEF_LIB_BUILTIN (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST) diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 6ab63dae997..9fbaeb437a1 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -6334,6 +6334,7 @@ check_builtin_function_arguments (location_t loc, vec arg_loc, case BUILT_IN_ISLESSEQUAL: case BUILT_IN_ISLESSGREATER: case BUILT_IN_ISUNORDERED: + case BUILT_IN_ISEQSIG: if (builtin_function_validate_nargs (loc, fndecl, nargs, 2)) { enum tree_code code0, code1; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index ec9ffa3c86e..97eaacf8a7e 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -13187,6 +13187,7 @@ is called and the @var{flag} argument passed to it. @node Other Builtins @section Other Built-in Functions Provided by GCC @cindex built-in functions +@findex __builtin_iseqsig @findex __builtin_isfinite @findex __builtin_isnormal @findex __builtin_isgreater @@ -13738,9 +13739,9 @@ the same names as the standard macros ( @code{isgreater}, @code{islessgreater}, and @code{isunordered}) , with @code{__builtin_} prefixed. We intend for a library implementor to be able to simply @code{#define} each standard macro to its built-in equivalent. -In the same fashion, GCC provides @code{fpclassify}, @code{isfinite}, -@code{isinf_sign}, @code{isnormal} and @code{signbit} built-ins used with -@code{__builtin_} prefixed. The @code{isinf} and @code{isnan} +In the same fashion, GCC provides @code{fpclassify}, @code{iseqsig}, +@code{isfinite}, @code{isinf_sign}, @code{isnormal} and @code{signbit} built-ins +used with @code{__builtin_} prefixed. The @code{isinf} and @code{isnan} built-in functions appear both with and without the @code{__builtin_} prefix. With @code{-ffinite-math-only} option the @code{isinf} and @code{isnan} built-in functions will always return 0. diff --git a/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-1.c b/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-1.c new file mode 100644 index 00000000000..c66431fff1c --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-1.c @@ -0,0 +1,113 @@ +/* { dg-do run { xfail powerpc*-*-* } } */ +/* remove the xfail for powerpc when pr58684 is fixed */ +/* { dg-add-options ieee } */ +/* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include + +void +ftrue (float x, float y) +{ + if (!__builtin_iseqsig (x, y)) + __builtin_abort (); +} + +void +ffalse (float x, float y) +{ + if (__builtin_iseqsig (x, y)) + __builtin_abort (); +} + +int +main () +{ + volatile float f1, f2; + + f1 = 0.f; f2 = 0.f; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.f; f2 = -0.f; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.f; f2 = 1.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = -0.f; f2 = 1.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.f; f2 = __builtin_inff(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = -0.f; f2 = __builtin_inff(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.f; f2 = __builtin_nanf(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = -0.f; f2 = __builtin_nanf(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = 1.f; f2 = 1.f; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.f; f2 = 0.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.f; f2 = -0.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.f; f2 = __builtin_inff(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.f; f2 = __builtin_nanf(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_inff(); f2 = __builtin_inff(); + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = __builtin_inff(); f2 = __builtin_nanf(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nanf(""); f2 = __builtin_nanf(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nansf(""); f2 = 1.f; + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = 1.f; f2 = __builtin_nansf(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nansf(""); f2 = __builtin_nansf(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-2.c b/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-2.c new file mode 100644 index 00000000000..03625b07e6f --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-2.c @@ -0,0 +1,113 @@ +/* { dg-do run { xfail powerpc*-*-* } } */ +/* remove the xfail for powerpc when pr58684 is fixed */ +/* { dg-add-options ieee } */ +/* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-require-effective-target fenv_exceptions_double } */ + +#include + +void +ftrue (double x, double y) +{ + if (!__builtin_iseqsig (x, y)) + __builtin_abort (); +} + +void +ffalse (double x, double y) +{ + if (__builtin_iseqsig (x, y)) + __builtin_abort (); +} + +int +main () +{ + volatile double f1, f2; + + f1 = 0.; f2 = 0.; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.; f2 = -0.; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.; f2 = 1.; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = -0.; f2 = 1.; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.; f2 = __builtin_inf(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = -0.; f2 = __builtin_inf(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.; f2 = __builtin_nan(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = -0.; f2 = __builtin_nan(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = 1.; f2 = 1.; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.; f2 = 0.; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.; f2 = -0.; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.; f2 = __builtin_inf(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.; f2 = __builtin_nan(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_inf(); f2 = __builtin_inf(); + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = __builtin_inf(); f2 = __builtin_nan(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nan(""); f2 = __builtin_nan(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nans(""); f2 = 1.; + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = 1.; f2 = __builtin_nans(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nans(""); f2 = __builtin_nans(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-3.c b/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-3.c new file mode 100644 index 00000000000..ed24035264a --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-iseqsig-3.c @@ -0,0 +1,113 @@ +/* { dg-do run { xfail powerpc*-*-* } } */ +/* remove the xfail for powerpc when pr58684 is fixed */ +/* { dg-add-options ieee } */ +/* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-require-effective-target fenv_exceptions_long_double } */ + +#include + +void +ftrue (long double x, long double y) +{ + if (!__builtin_iseqsig (x, y)) + __builtin_abort (); +} + +void +ffalse (long double x, long double y) +{ + if (__builtin_iseqsig (x, y)) + __builtin_abort (); +} + +int +main () +{ + volatile long double f1, f2; + + f1 = 0.L; f2 = 0.f; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.L; f2 = -0.f; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.L; f2 = 1.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = -0.L; f2 = 1.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.L; f2 = __builtin_infl(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = -0.L; f2 = __builtin_infl(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 0.L; f2 = __builtin_nanl(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = -0.L; f2 = __builtin_nanl(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = 1.L; f2 = 1.f; + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.L; f2 = 0.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.L; f2 = -0.f; + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.L; f2 = __builtin_infl(); + ffalse (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = 1.L; f2 = __builtin_nanl(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_infl(); f2 = __builtin_infl(); + ftrue (f1, f2); + if (fetestexcept (FE_INVALID)) __builtin_abort (); + + f1 = __builtin_infl(); f2 = __builtin_nanl(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nanl(""); f2 = __builtin_nanl(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nansl(""); f2 = 1.L; + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = 1.L; f2 = __builtin_nansl(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + f1 = __builtin_nansl(""); f2 = __builtin_nansl(""); + ffalse (f1, f2); + if (!fetestexcept (FE_INVALID)) __builtin_abort (); + feclearexcept (FE_INVALID); + + return 0; +}