aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2008-05-18 23:19:38 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2008-05-18 23:19:38 +0000
commit05f41289d88658c05f34f713aed66054e12ff316 (patch)
tree90c75e8f2433a04ac95315cbba4166b8f7f7b3d2 /gcc
parentd393bbd73754dfe54fac24d350c789316f17428f (diff)
downloadgcc-05f41289d88658c05f34f713aed66054e12ff316.zip
gcc-05f41289d88658c05f34f713aed66054e12ff316.tar.gz
gcc-05f41289d88658c05f34f713aed66054e12ff316.tar.bz2
re PR middle-end/35509 (builtin isinf() mismatch to compile-time substitution)
PR middle-end/35509 * builtins.c (mathfn_built_in_1): Renamed from mathfn_built_in. Add `implicit' parameter. Handle BUILT_IN_SIGNBIT. (mathfn_built_in): Rewrite in terms of mathfn_built_in_1. (fold_builtin_classify): Handle BUILT_IN_ISINF_SIGN. (fold_builtin_1): Likewise. * builtins.def (BUILT_IN_ISINF_SIGN): New. c-common.c (check_builtin_function_arguments): Handle BUILT_IN_ISINF_SIGN. * doc/extend.texi: Document __builtin_isinf_sign. * fold-const.c (operand_equal_p): Handle COND_EXPR. testsuite: * gcc.dg/builtins-error.c: Test __builtin_isinf_sign. * gcc.dg/tg-tests.h: Likewise. Mark variables volatile. * gcc.dg/torture/builtin-isinf_sign-1.c: New test. From-SVN: r135517
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/builtins.c60
-rw-r--r--gcc/builtins.def1
-rw-r--r--gcc/c-common.c1
-rw-r--r--gcc/doc/extend.texi15
-rw-r--r--gcc/fold-const.c3
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/builtins-error.c5
-rw-r--r--gcc/testsuite/gcc.dg/tg-tests.h19
9 files changed, 112 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5cf0155..74b7b35 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2008-05-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ PR middle-end/35509
+
+ * builtins.c (mathfn_built_in_1): Renamed from mathfn_built_in.
+ Add `implicit' parameter. Handle BUILT_IN_SIGNBIT.
+ (mathfn_built_in): Rewrite in terms of mathfn_built_in_1.
+ (fold_builtin_classify): Handle BUILT_IN_ISINF_SIGN.
+ (fold_builtin_1): Likewise.
+ * builtins.def (BUILT_IN_ISINF_SIGN): New.
+ c-common.c (check_builtin_function_arguments): Handle
+ BUILT_IN_ISINF_SIGN.
+ * doc/extend.texi: Document __builtin_isinf_sign.
+ * fold-const.c (operand_equal_p): Handle COND_EXPR.
+
+
2008-05-18 Eric Botcazou <ebotcazou@adacore.com>
* tree-ssa-dom.c (tree_ssa_dominator_optimize): If some blocks need
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 4211e62..3060f80 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1669,10 +1669,15 @@ expand_builtin_classify_type (tree exp)
fcodel = BUILT_IN_MATHFN##L_R ; break;
/* Return mathematic function equivalent to FN but operating directly
- on TYPE, if available. If we can't do the conversion, return zero. */
-tree
-mathfn_built_in (tree type, enum built_in_function fn)
+ on TYPE, if available. If IMPLICIT is true find the function in
+ implicit_built_in_decls[], otherwise use built_in_decls[]. If we
+ can't do the conversion, return zero. */
+
+static tree
+mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit)
{
+ tree const *const fn_arr
+ = implicit ? implicit_built_in_decls : built_in_decls;
enum built_in_function fcode, fcodef, fcodel;
switch (fn)
@@ -1747,6 +1752,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
CASE_MATHFN (BUILT_IN_SCALB)
CASE_MATHFN (BUILT_IN_SCALBLN)
CASE_MATHFN (BUILT_IN_SCALBN)
+ CASE_MATHFN (BUILT_IN_SIGNBIT)
CASE_MATHFN (BUILT_IN_SIGNIFICAND)
CASE_MATHFN (BUILT_IN_SIN)
CASE_MATHFN (BUILT_IN_SINCOS)
@@ -1765,15 +1771,23 @@ mathfn_built_in (tree type, enum built_in_function fn)
}
if (TYPE_MAIN_VARIANT (type) == double_type_node)
- return implicit_built_in_decls[fcode];
+ return fn_arr[fcode];
else if (TYPE_MAIN_VARIANT (type) == float_type_node)
- return implicit_built_in_decls[fcodef];
+ return fn_arr[fcodef];
else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
- return implicit_built_in_decls[fcodel];
+ return fn_arr[fcodel];
else
return NULL_TREE;
}
+/* Like mathfn_built_in_1(), but always use the implicit array. */
+
+tree
+mathfn_built_in (tree type, enum built_in_function fn)
+{
+ return mathfn_built_in_1 (type, fn, /*implicit=*/ 1);
+}
+
/* If errno must be maintained, expand the RTL to check if the result,
TARGET, of a built-in function call, EXP, is NaN, and if so set
errno to EDOM. */
@@ -9668,6 +9682,37 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
return NULL_TREE;
+ case BUILT_IN_ISINF_SIGN:
+ {
+ /* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */
+ /* In a boolean context, GCC will fold the inner COND_EXPR to
+ 1. So e.g. "if (isinf_sign(x))" would be folded to just
+ "if (isinf(x) ? 1 : 0)" which becomes "if (isinf(x))". */
+ tree signbit_fn = mathfn_built_in_1 (TREE_TYPE (arg), BUILT_IN_SIGNBIT, 0);
+ tree isinf_fn = built_in_decls[BUILT_IN_ISINF];
+ tree tmp = NULL_TREE;
+
+ arg = builtin_save_expr (arg);
+
+ if (signbit_fn && isinf_fn)
+ {
+ tree signbit_call = build_call_expr (signbit_fn, 1, arg);
+ tree isinf_call = build_call_expr (isinf_fn, 1, arg);
+
+ signbit_call = fold_build2 (NE_EXPR, integer_type_node,
+ signbit_call, integer_zero_node);
+ isinf_call = fold_build2 (NE_EXPR, integer_type_node,
+ isinf_call, integer_zero_node);
+
+ tmp = fold_build3 (COND_EXPR, integer_type_node, signbit_call,
+ integer_minus_one_node, integer_one_node);
+ tmp = fold_build3 (COND_EXPR, integer_type_node, isinf_call, tmp,
+ integer_zero_node);
+ }
+
+ return tmp;
+ }
+
case BUILT_IN_ISFINITE:
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg)))
&& !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
@@ -10074,6 +10119,9 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
case BUILT_IN_ISINFD128:
return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF);
+ case BUILT_IN_ISINF_SIGN:
+ return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF_SIGN);
+
CASE_FLT_FN (BUILT_IN_ISNAN):
case BUILT_IN_ISNAND32:
case BUILT_IN_ISNAND64:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 722f81c..8bae2bd 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -655,6 +655,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FINITED32, "finited32", BT_FN_INT_DFLOAT32, ATT
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_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)
DEF_EXT_LIB_BUILTIN (BUILT_IN_ISINFF, "isinff", BT_FN_INT_FLOAT, ATTR_CONST_NOTHROW_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_ISINFL, "isinfl", BT_FN_INT_LONGDOUBLE, ATTR_CONST_NOTHROW_LIST)
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 415807f..67c9c0b 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -6674,6 +6674,7 @@ check_builtin_function_arguments (tree fndecl, int nargs, tree *args)
case BUILT_IN_ISFINITE:
case BUILT_IN_ISINF:
+ case BUILT_IN_ISINF_SIGN:
case BUILT_IN_ISNAN:
case BUILT_IN_ISNORMAL:
if (validate_nargs (fndecl, nargs, 1))
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f3c6c57..36e81ff 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5768,6 +5768,7 @@ should be called and the @var{flag} argument passed to it.
@findex __builtin_isnormal
@findex __builtin_isgreater
@findex __builtin_isgreaterequal
+@findex __builtin_isinf_sign
@findex __builtin_isless
@findex __builtin_islessequal
@findex __builtin_islessgreater
@@ -6294,8 +6295,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} and @code{isnormal}
-built-ins used with @code{__builtin_} prefixed.
+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.
@deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2})
@@ -6579,6 +6582,14 @@ Similar to @code{__builtin_inf}, except the return
type is @code{long double}.
@end deftypefn
+@deftypefn {Built-in Function} int __builtin_isinf_sign (...)
+Similar to @code{isinf}, except the return value will be negative for
+an argument of @code{-Inf}. Note while the parameter list is an
+ellipsis, this function only accepts exactly one floating point
+argument. GCC treats this parameter as type-generic, which means it
+does not do default promotion from float to double.
+@end deftypefn
+
@deftypefn {Built-in Function} double __builtin_nan (const char *str)
This is an implementation of the ISO C99 function @code{nan}.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index dc1e182..4113dc4 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -3258,6 +3258,9 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
&& operand_equal_p (TREE_OPERAND (arg0, 1),
TREE_OPERAND (arg1, 0), flags));
+ case COND_EXPR:
+ return OP_SAME (0) && OP_SAME (1) && OP_SAME (2);
+
default:
return 0;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 77c5dab..c2dc86a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2008-05-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gcc.dg/builtins-error.c: Test __builtin_isinf_sign.
+ * gcc.dg/tg-tests.h: Likewise. Mark variables volatile.
+ * gcc.dg/torture/builtin-isinf_sign-1.c: New test.
+
2008-05-18 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
* gfortran.dg/achar_3.f90: Adjust error messages.
diff --git a/gcc/testsuite/gcc.dg/builtins-error.c b/gcc/testsuite/gcc.dg/builtins-error.c
index 9f401bb..2c0ece1 100644
--- a/gcc/testsuite/gcc.dg/builtins-error.c
+++ b/gcc/testsuite/gcc.dg/builtins-error.c
@@ -16,3 +16,8 @@ int test3(double x)
{
return __builtin_isinf(x, x); /* { dg-error "too many arguments" } */
}
+
+int test4(double x)
+{
+ return __builtin_isinf_sign(x, x); /* { dg-error "too many arguments" } */
+}
diff --git a/gcc/testsuite/gcc.dg/tg-tests.h b/gcc/testsuite/gcc.dg/tg-tests.h
index 9d31e4b..c34e888 100644
--- a/gcc/testsuite/gcc.dg/tg-tests.h
+++ b/gcc/testsuite/gcc.dg/tg-tests.h
@@ -3,7 +3,7 @@
void __attribute__ ((__noinline__))
foo_1 (float f, double d, long double ld,
int res_unord, int res_isnan, int res_isinf,
- int res_isfin, int res_isnorm)
+ int res_isinf_sign, int res_isfin, int res_isnorm)
{
if (__builtin_isunordered (f, 0) != res_unord)
__builtin_abort ();
@@ -40,6 +40,13 @@ foo_1 (float f, double d, long double ld,
if (__builtin_isinfl (ld) != res_isinf)
__builtin_abort ();
+ if (__builtin_isinf_sign (f) != res_isinf_sign)
+ __builtin_abort ();
+ if (__builtin_isinf_sign (d) != res_isinf_sign)
+ __builtin_abort ();
+ if (__builtin_isinf_sign (ld) != res_isinf_sign)
+ __builtin_abort ();
+
if (__builtin_isnormal (f) != res_isnorm)
__builtin_abort ();
if (__builtin_isnormal (d) != res_isnorm)
@@ -71,17 +78,17 @@ foo (float f, double d, long double ld,
int res_unord, int res_isnan, int res_isinf,
int res_isfin, int res_isnorm)
{
- foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isfin, res_isnorm);
+ foo_1 (f, d, ld, res_unord, res_isnan, res_isinf, res_isinf, res_isfin, res_isnorm);
/* Try all the values negated as well. */
- foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, res_isfin, res_isnorm);
+ foo_1 (-f, -d, -ld, res_unord, res_isnan, res_isinf, -res_isinf, res_isfin, res_isnorm);
}
int __attribute__ ((__noinline__))
main_tests (void)
{
- float f;
- double d;
- long double ld;
+ volatile float f;
+ volatile double d;
+ volatile long double ld;
/* Test NaN. */
f = __builtin_nanf(""); d = __builtin_nan(""); ld = __builtin_nanl("");