* builtin-types.def (BT_FN_INT_INT_INT_INT_INT_INT_VAR): New.
* builtins.c (fold_builtin_fpclassify): New.
(fold_builtin_varargs): Handle BUILT_IN_FPCLASSIFY.
* builtins.def (BUILT_IN_FPCLASSIFY): New.
* c-common.c (handle_type_generic_attribute): Adjust to accept
fixed arguments before an elipsis.
(check_builtin_function_arguments): Handle BUILT_IN_FPCLASSIFY.
* doc/extend.texi: Document __builtin_fpclassify.
testsuite:
* gcc.dg/builtins-error.c: Test __builtin_fpclassify. Also
add tests for all previous type-generic builtins.
* gcc.dg/pr28796-2.c: Add -DUNSAFE flag.
* gcc.dg/tg-tests.h: Test __builtin_fpclassify.
From-SVN: r135789
+2008-05-23 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * builtin-types.def (BT_FN_INT_INT_INT_INT_INT_INT_VAR): New.
+ * builtins.c (fold_builtin_fpclassify): New.
+ (fold_builtin_varargs): Handle BUILT_IN_FPCLASSIFY.
+ * builtins.def (BUILT_IN_FPCLASSIFY): New.
+ * c-common.c (handle_type_generic_attribute): Adjust to accept
+ fixed arguments before an elipsis.
+ (check_builtin_function_arguments): Handle BUILT_IN_FPCLASSIFY.
+ * doc/extend.texi: Document __builtin_fpclassify.
+
2008-05-22 Aldy Hernandez <aldyh@redhat.com>
* omp-low.c (gate_expand_omp_ssa): Remove.
BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE,
BT_CONST_STRING)
+DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_INT_INT_INT_INT_VAR,
+ BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
+
DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR)
DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE,
BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE)
}
}
+/* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
+ This builtin will generate code to return the appropriate floating
+ point classification depending on the value of the floating point
+ number passed in. The possible return values must be supplied as
+ int arguments to the call in the following order: FP_NAN, FP_INF,
+ FP_NORMAL, FP_SUBNORMAL and FP_ZERO. The ellipses is for exactly
+ one floating point argument which is "type generic". */
+
+static tree
+fold_builtin_fpclassify (tree exp)
+{
+ tree fp_nan, fp_inf, fp_normal, fp_subnormal, fp_zero, arg, type, res, tmp;
+ enum machine_mode mode;
+ REAL_VALUE_TYPE r;
+ char buf[128];
+
+ /* Verify the required arguments in the original call. */
+ if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE,
+ INTEGER_TYPE, INTEGER_TYPE,
+ INTEGER_TYPE, REAL_TYPE, VOID_TYPE))
+ return NULL_TREE;
+
+ fp_nan = CALL_EXPR_ARG (exp, 0);
+ fp_inf = CALL_EXPR_ARG (exp, 1);
+ fp_normal = CALL_EXPR_ARG (exp, 2);
+ fp_subnormal = CALL_EXPR_ARG (exp, 3);
+ fp_zero = CALL_EXPR_ARG (exp, 4);
+ arg = CALL_EXPR_ARG (exp, 5);
+ type = TREE_TYPE (arg);
+ mode = TYPE_MODE (type);
+ arg = builtin_save_expr (fold_build1 (ABS_EXPR, type, arg));
+
+ /* fpclassify(x) ->
+ isnan(x) ? FP_NAN :
+ (fabs(x) == Inf ? FP_INF :
+ (fabs(x) >= DBL_MIN ? FP_NORMAL :
+ (x == 0 ? FP_ZERO : FP_SUBNORMAL))). */
+
+ tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+ build_real (type, dconst0));
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_zero, fp_subnormal);
+
+ sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+ real_from_string (&r, buf);
+ tmp = fold_build2 (GE_EXPR, integer_type_node, arg, build_real (type, r));
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_normal, res);
+
+ if (HONOR_INFINITIES (mode))
+ {
+ real_inf (&r);
+ tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+ build_real (type, r));
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_inf, res);
+ }
+
+ if (HONOR_NANS (mode))
+ {
+ tmp = fold_build2 (ORDERED_EXPR, integer_type_node, arg, arg);
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, res, fp_nan);
+ }
+
+ return res;
+}
+
/* Fold a call to an unordered comparison function such as
__builtin_isgreater(). FNDECL is the FUNCTION_DECL for the function
being called and ARG0 and ARG1 are the arguments for the call.
case BUILT_IN_SNPRINTF_CHK:
case BUILT_IN_VSNPRINTF_CHK:
ret = fold_builtin_snprintf_chk (exp, NULL_TREE, fcode);
+ break;
+
+ case BUILT_IN_FPCLASSIFY:
+ ret = fold_builtin_fpclassify (exp);
+ break;
default:
break;
DEF_EXT_LIB_BUILTIN (BUILT_IN_FINITED32, "finited32", BT_FN_INT_DFLOAT32, ATTR_CONST_NOTHROW_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FINITED64, "finited64", BT_FN_INT_DFLOAT64, ATTR_CONST_NOTHROW_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FINITED128, "finited128", BT_FN_INT_DFLOAT128, ATTR_CONST_NOTHROW_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_FPCLASSIFY, "fpclassify", BT_FN_INT_INT_INT_INT_INT_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
DEF_GCC_BUILTIN (BUILT_IN_ISFINITE, "isfinite", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
DEF_GCC_BUILTIN (BUILT_IN_ISINF_SIGN, "isinf_sign", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
DEF_C99_C90RES_BUILTIN (BUILT_IN_ISINF, "isinf", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC)
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
bool * ARG_UNUSED (no_add_attrs))
{
- /* Ensure we have a function type, with no arguments. */
- gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE && ! TYPE_ARG_TYPES (*node));
+ tree params;
+
+ /* Ensure we have a function type. */
+ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+ params = TYPE_ARG_TYPES (*node);
+ while (params && ! VOID_TYPE_P (TREE_VALUE (params)))
+ params = TREE_CHAIN (params);
+
+ /* Ensure we have a variadic function. */
+ gcc_assert (!params);
return NULL_TREE;
}
}
return false;
+ case BUILT_IN_FPCLASSIFY:
+ if (validate_nargs (fndecl, nargs, 6))
+ {
+ unsigned i;
+
+ for (i=0; i<5; i++)
+ if (TREE_CODE (args[i]) != INTEGER_CST)
+ {
+ error ("non-const integer argument %u in call to function %qE",
+ i+1, fndecl);
+ return false;
+ }
+
+ if (TREE_CODE (TREE_TYPE (args[5])) != REAL_TYPE)
+ {
+ error ("non-floating-point argument in call to function %qE",
+ fndecl);
+ return false;
+ }
+ return true;
+ }
+ return false;
+
default:
return true;
}
@node Other Builtins
@section Other built-in functions provided by GCC
@cindex built-in functions
+@findex __builtin_fpclassify
@findex __builtin_isfinite
@findex __builtin_isnormal
@findex __builtin_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{isfinite}, @code{isinf_sign}
-and @code{isnormal} built-ins used with @code{__builtin_} prefixed.
-The @code{isinf} and @code{isnan} builtins appear both with and
-without the @code{__builtin_} prefix.
+In the same fashion, GCC provides @code{fpclassify}, @code{isfinite},
+@code{isinf_sign} and @code{isnormal} built-ins used with
+@code{__builtin_} prefixed. The @code{isinf} and @code{isnan}
+builtins appear both with and without the @code{__builtin_} prefix.
@deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2})
type is @code{long double}.
@end deftypefn
+@deftypefn {Built-in Function} int __builtin_fpclassify (int, int, int, int, int, ...)
+This built-in implements the C99 fpclassify functionality. The first
+five int arguments should be the target library's notion of the
+possible FP classes and are used for return values. They must be
+constant values and they must appear in this order: @code{FP_NAN},
+@code{FP_INF}, @code{FP_NORMAL}, @code{FP_SUBNORMAL} and
+@code{FP_ZERO}. The ellipsis is for exactly one floating point value
+to classify. GCC treats the last argument as type-generic, which
+means it does not do default promotion from float to double.
+@end deftypefn
+
@deftypefn {Built-in Function} double __builtin_inf (void)
Similar to @code{__builtin_huge_val}, except a warning is generated
if the target floating-point format does not support infinities.
+2008-05-23 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gcc.dg/builtins-error.c: Test __builtin_fpclassify. Also
+ add tests for all previous type-generic builtins.
+ * gcc.dg/pr28796-2.c: Add -DUNSAFE flag.
+ * gcc.dg/tg-tests.h: Test __builtin_fpclassify.
+
2008-05-22 Thomas Koenig <tkoenig@gcc.gnu.org>
PR libgfortran/36302
int test1(struct X x)
{
- return __builtin_isnormal(x); /* { dg-error "non-floating-point argument" } */
+ if (x.x == 1) return __builtin_fpclassify(1,2,3,4,5,x); /* { dg-error "non-floating-point argument" } */
+ if (x.x == 2) return __builtin_isfinite(x); /* { dg-error "non-floating-point argument" } */
+ if (x.x == 3) return __builtin_isinf_sign(x); /* { dg-error "non-floating-point argument" } */
+ if (x.x == 4) return __builtin_isinf(x); /* { dg-error "non-floating-point argument" } */
+ if (x.x == 5) return __builtin_isnan(x); /* { dg-error "non-floating-point argument" } */
+ if (x.x == 6) return __builtin_isnormal(x); /* { dg-error "non-floating-point argument" } */
+ if (x.x == 7) return __builtin_isgreater(x, x); /* { dg-error "non-floating-point arguments" } */
+ if (x.x == 8) return __builtin_isgreaterequal(x, x); /* { dg-error "non-floating-point arguments" } */
+ if (x.x == 9) return __builtin_isless(x, x); /* { dg-error "non-floating-point arguments" } */
+ if (x.x == 10) return __builtin_islessequal(x, x); /* { dg-error "non-floating-point arguments" } */
+ if (x.x == 11) return __builtin_islessgreater(x, x); /* { dg-error "non-floating-point arguments" } */
+ if (x.x == 12) return __builtin_isunordered(x, x); /* { dg-error "non-floating-point arguments" } */
+
+ return 0;
}
int test2(double x)
{
- return __builtin_isgreater(x); /* { dg-error "not enough arguments" } */
+ if (x == 1) return __builtin_fpclassify(1,2,3,4,5); /* { dg-error "not enough arguments" } */
+ if (x == 2) return __builtin_isfinite(); /* { dg-error "not enough arguments" } */
+ if (x == 3) return __builtin_isinf_sign(); /* { dg-error "not enough arguments" } */
+ if (x == 4) return __builtin_isinf(); /* { dg-error "not enough arguments" } */
+ if (x == 5) return __builtin_isnan(); /* { dg-error "not enough arguments" } */
+ if (x == 6) return __builtin_isnormal(); /* { dg-error "not enough arguments" } */
+ if (x == 7) return __builtin_isgreater(x); /* { dg-error "not enough arguments" } */
+ if (x == 8) return __builtin_isgreaterequal(x); /* { dg-error "not enough arguments" } */
+ if (x == 9) return __builtin_isless(x); /* { dg-error "not enough arguments" } */
+ if (x == 10) return __builtin_islessequal(x); /* { dg-error "not enough arguments" } */
+ if (x == 11) return __builtin_islessgreater(x); /* { dg-error "not enough arguments" } */
+ if (x == 12) return __builtin_isunordered(x); /* { dg-error "not enough arguments" } */
+ return 0;
}
int test3(double x)
{
- return __builtin_isinf(x, x); /* { dg-error "too many arguments" } */
+ if (x == 1) return __builtin_fpclassify(1,2,3,4,5,x,x); /* { dg-error "too many arguments" } */
+ if (x == 2) return __builtin_isfinite(x, x); /* { dg-error "too many arguments" } */
+ if (x == 3) return __builtin_isinf_sign(x, x); /* { dg-error "too many arguments" } */
+ if (x == 4) return __builtin_isinf(x, x); /* { dg-error "too many arguments" } */
+ if (x == 5) return __builtin_isnan(x, x); /* { dg-error "too many arguments" } */
+ if (x == 6) return __builtin_isnormal(x, x); /* { dg-error "too many arguments" } */
+ if (x == 7) return __builtin_isgreater(x, x, x); /* { dg-error "too many arguments" } */
+ if (x == 8) return __builtin_isgreaterequal(x, x, x); /* { dg-error "too many arguments" } */
+ if (x == 9) return __builtin_isless(x, x, x); /* { dg-error "too many arguments" } */
+ if (x == 10) return __builtin_islessequal(x, x, x); /* { dg-error "too many arguments" } */
+ if (x == 11) return __builtin_islessgreater(x, x, x); /* { dg-error "too many arguments" } */
+ if (x == 12) return __builtin_isunordered(x, x, x); /* { dg-error "too many arguments" } */
+ return 0;
}
-int test4(double x)
+int test4(int i, double x)
{
- return __builtin_isinf_sign(x, x); /* { dg-error "too many arguments" } */
+ if (x == 1) return __builtin_fpclassify(i,2,3,4,5,x); /* { dg-error "non-const integer argument" } */
+ if (x == 2) return __builtin_fpclassify(1,i,3,4,5,x); /* { dg-error "non-const integer argument" } */
+ if (x == 3) return __builtin_fpclassify(1,2,i,4,5,x); /* { dg-error "non-const integer argument" } */
+ if (x == 4) return __builtin_fpclassify(1,2,3,i,5,x); /* { dg-error "non-const integer argument" } */
+ if (x == 5) return __builtin_fpclassify(1,2,3,4,i,x); /* { dg-error "non-const integer argument" } */
+ return 0;
}
/* { dg-do run } */
-/* { dg-options "-O2 -funsafe-math-optimizations -fno-finite-math-only" } */
-/* { dg-options "-mieee -O2 -funsafe-math-optimizations -fno-finite-math-only" { target alpha*-*-* } } */
+/* { dg-options "-O2 -funsafe-math-optimizations -fno-finite-math-only -DUNSAFE" } */
+/* { dg-options "-mieee -O2 -funsafe-math-optimizations -fno-finite-math-only -DUNSAFE" { target alpha*-*-* } } */
#include "tg-tests.h"
/* Test various type-generic builtins by calling "main_tests()". */
+#define FP_NAN 1
+#define FP_INF 2
+#define FP_NORMAL 3
+#define FP_SUBNORMAL 4
+#define FP_ZERO 5
+#define fpclassify(X) __builtin_fpclassify(FP_NAN, FP_INF, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, (X))
+
void __attribute__ ((__noinline__))
foo_1 (float f, double d, long double ld,
int res_unord, int res_isnan, int res_isinf,
- int res_isinf_sign, int res_isfin, int res_isnorm)
+ int res_isinf_sign, int res_isfin, int res_isnorm,
+ int classification)
{
if (__builtin_isunordered (f, 0) != res_unord)
__builtin_abort ();
__builtin_abort ();
if (__builtin_finitel (ld) != res_isfin)
__builtin_abort ();
+
+ /* Subnormals can abruptly underflow to zero in unsafe math
+ mode, so bypass testing these numbers if necessary. */
+#ifdef UNSAFE
+ if (classification != FP_SUBNORMAL)
+#endif
+ {
+ if (fpclassify(f) != classification)
+ __builtin_abort ();
+ if (fpclassify(d) != classification)
+ __builtin_abort ();
+ if (fpclassify(ld) != classification)
+ __builtin_abort ();
+ }
}
void __attribute__ ((__noinline__))
foo (float f, double d, long double ld,
int res_unord, int res_isnan, int res_isinf,
- int res_isfin, int res_isnorm)
+ int res_isfin, int res_isnorm, int classification)
{
- foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isinf, res_isfin, res_isnorm);
+ foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isinf, res_isfin, res_isnorm, classification);
/* Try all the values negated as well. */
- foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, -res_isinf, res_isfin, res_isnorm);
+ foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, -res_isinf, res_isfin, res_isnorm, classification);
}
int __attribute__ ((__noinline__))
/* Test NaN. */
f = __builtin_nanf(""); d = __builtin_nan(""); ld = __builtin_nanl("");
- foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isinf=*/ 0, /*isfin=*/ 0, /*isnorm=*/ 0);
+ foo(f, d, ld, /*unord=*/ 1, /*isnan=*/ 1, /*isinf=*/ 0, /*isfin=*/ 0, /*isnorm=*/ 0, FP_NAN);
/* Test infinity. */
f = __builtin_inff(); d = __builtin_inf(); ld = __builtin_infl();
- foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0);
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, FP_INF);
/* Test zero. */
f = 0; d = 0; ld = 0;
- foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0);
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, FP_ZERO);
/* Test one. */
f = 1; d = 1; ld = 1;
- foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1);
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
/* Test minimum values. */
f = __FLT_MIN__; d = __DBL_MIN__; ld = __LDBL_MIN__;
- foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1);
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
/* Test subnormal values. */
f = __FLT_MIN__/2; d = __DBL_MIN__/2; ld = __LDBL_MIN__/2;
- foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0);
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 0, FP_SUBNORMAL);
/* Test maximum values. */
f = __FLT_MAX__; d = __DBL_MAX__; ld = __LDBL_MAX__;
- foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1);
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 0, /*isfin=*/ 1, /*isnorm=*/ 1, FP_NORMAL);
/* Test overflow values. */
f = __FLT_MAX__*2; d = __DBL_MAX__*2; ld = __LDBL_MAX__*2;
- foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0);
+ foo(f, d, ld, /*unord=*/ 0, /*isnan=*/ 0, /*isinf=*/ 1, /*isfin=*/ 0, /*isnorm=*/ 0, FP_INF);
return 0;
}