builtin-types.def (BT_FN_INT_INT_INT_INT_INT_INT_VAR): New.

* 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
This commit is contained in:
Kaveh R. Ghazi 2008-05-23 04:47:12 +00:00 committed by Kaveh Ghazi
parent 2aa5c17ce5
commit 3bf5906b31
10 changed files with 224 additions and 25 deletions

View file

@ -1,3 +1,14 @@
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.

View file

@ -449,6 +449,9 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR,
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)

View file

@ -9744,6 +9744,70 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
}
}
/* 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.
@ -10528,6 +10592,11 @@ fold_builtin_varargs (tree fndecl, tree exp, bool ignore ATTRIBUTE_UNUSED)
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;

View file

@ -654,6 +654,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FINITEL, "finitel", BT_FN_INT_LONGDOUBLE, ATTR_
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)

View file

@ -6528,8 +6528,17 @@ handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
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;
}
@ -6712,6 +6721,29 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
}
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;
}

View file

@ -5764,6 +5764,7 @@ should be 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_fpclassify
@findex __builtin_isfinite
@findex __builtin_isnormal
@findex __builtin_isgreater
@ -6295,10 +6296,10 @@ 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{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})
@ -6555,6 +6556,17 @@ Similar to @code{__builtin_huge_val}, except the return
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.

View file

@ -1,3 +1,10 @@
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

View file

@ -4,20 +4,62 @@ struct X { int x; };
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;
}

View file

@ -1,6 +1,6 @@
/* { 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"

View file

@ -1,9 +1,17 @@
/* 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 ();
@ -71,16 +79,30 @@ foo_1 (float f, double d, long double ld,
__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__))
@ -92,35 +114,35 @@ main_tests (void)
/* 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;
}