re PR middle-end/35509 (builtin isinf() mismatch to compile-time substitution)
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>
Sun, 18 May 2008 23:19:38 +0000 (23:19 +0000)
committerKaveh Ghazi <ghazi@gcc.gnu.org>
Sun, 18 May 2008 23:19:38 +0000 (23:19 +0000)
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

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/c-common.c
gcc/doc/extend.texi
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-error.c
gcc/testsuite/gcc.dg/tg-tests.h

index 5cf0155c5e7924525d2270722353368f863e8e05..74b7b35d46ed70c80e341a3a28769e43d3b8a906 100644 (file)
@@ -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
index 4211e6247a1abfb229a9d9d9b70a93ef08db2d49..3060f80ae00e981829caeadf92efc0cb4ce6dd91 100644 (file)
@@ -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:
index 722f81c7e3eac72047d6e7ac607182aa2f7af2a5..8bae2bd467ca05a976fc5da80de18ff1e0e57f5c 100644 (file)
@@ -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)
index 415807f1c5b750601b6e21a02d78e6c08e8526df..67c9c0b538febcbc68bbe72cc68c3a42ede8c5dd 100644 (file)
@@ -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))
index f3c6c574a42a3e8b6fdb5177f3b2472592c97dbd..36e81ffe55c182ddf1f05f4f5af8c524fece62b5 100644 (file)
@@ -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}.
 
index dc1e182c16ff6e5038e952d13ca231abf1246fc7..4113dc45b21beadbcabdf6752c45a3e42a2ac4fb 100644 (file)
@@ -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;
        }
index 77c5dab835a9e95995e2843edf0d9c719e35118b..c2dc86a21dd5b80553c499678b30060e46eea799 100644 (file)
@@ -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.
index 9f401bba1a02ca377083157a3eb58de950226028..2c0ece1934b40a59d593415835a2ab148676bd4c 100644 (file)
@@ -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" } */
+}
index 9d31e4b7bfa0df750b64396a0eb41321493dfd68..c34e8888cfa394b6dfdcf07533cac9a954637398 100644 (file)
@@ -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("");