re PR middle-end/29335 (transcendental functions with constant arguments should be...
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>
Tue, 24 Oct 2006 17:44:36 +0000 (17:44 +0000)
committerKaveh Ghazi <ghazi@gcc.gnu.org>
Tue, 24 Oct 2006 17:44:36 +0000 (17:44 +0000)
PR middle-end/29335
* builtins.c (fold_builtin_sin, fold_builtin_atan): Remove.
(do_mpfr_arg1): Add `min', `max' and `inclusive' arguments.
Update all callers.
(BUILT_IN_SIN, BUILT_IN_ATAN): Handle in main switch.
(BUILT_IN_ASIN, BUILT_IN_ACOS, BUILT_IN_ATAN, BUILT_IN_ASINH,
BUILT_IN_ACOSH, BUILT_IN_ATANH, BUILT_IN_SINH, BUILT_IN_COSH,
BUILT_IN_TANH): Calculate compile-time arguments using MPFR.

testsuite:
* gcc.dg/torture/builtin-math-3.c: New test.

From-SVN: r118009

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/builtin-math-3.c [new file with mode: 0644]

index 811fd4c16bc03fe00e86baa6631cf2f7768dc5f1..d47b94b74cce3a99e499319545813c208948f379 100644 (file)
@@ -1,3 +1,14 @@
+2006-10-24  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       PR middle-end/29335
+       * builtins.c (fold_builtin_sin, fold_builtin_atan): Remove.
+       (do_mpfr_arg1): Add `min', `max' and `inclusive' arguments.
+       Update all callers.
+       (BUILT_IN_SIN, BUILT_IN_ATAN): Handle in main switch.
+       (BUILT_IN_ASIN, BUILT_IN_ACOS, BUILT_IN_ATAN, BUILT_IN_ASINH,
+       BUILT_IN_ACOSH, BUILT_IN_ATANH, BUILT_IN_SINH, BUILT_IN_COSH,
+       BUILT_IN_TANH): Calculate compile-time arguments using MPFR.
+
 2006-10-24  Richard Guenther  <rguenther@suse.de>
 
        PR middle-end/28796
@@ -21,6 +32,7 @@
 
 2006-10-24  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
+       PR middle-end/29335
        * builtins.c (fold_builtin_exponent): Evaluate constant arguments
        at compile-time using MPFR.  Change parameter VALUE to FUNC,
        update all callers.
index f77f8b24a1a0ce4b06549e4add8f7019095532dd..ebb9a857629279099316bdb3289b818baa8aee77 100644 (file)
@@ -150,10 +150,8 @@ static tree fold_builtin_sqrt (tree, tree);
 static tree fold_builtin_cbrt (tree, tree);
 static tree fold_builtin_pow (tree, tree, tree);
 static tree fold_builtin_powi (tree, tree, tree);
-static tree fold_builtin_sin (tree, tree);
 static tree fold_builtin_cos (tree, tree, tree);
 static tree fold_builtin_tan (tree, tree);
-static tree fold_builtin_atan (tree, tree);
 static tree fold_builtin_trunc (tree, tree);
 static tree fold_builtin_floor (tree, tree);
 static tree fold_builtin_ceil (tree, tree);
@@ -205,7 +203,8 @@ static unsigned HOST_WIDE_INT target_s;
 static char target_percent_c[3];
 static char target_percent_s[3];
 static char target_percent_s_newline[4];
-static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t));
+static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
+                         const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, bool);
 
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
@@ -7204,23 +7203,6 @@ fold_builtin_cbrt (tree arglist, tree type)
   return NULL_TREE;
 }
 
-/* Fold function call to builtin sin, sinf, or sinl.  Return
-   NULL_TREE if no simplification can be made.  */
-static tree
-fold_builtin_sin (tree arglist, tree type)
-{
-  tree arg = TREE_VALUE (arglist), res;
-
-  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
-    return NULL_TREE;
-
-  /* Calculate the result when the argument is a constant.  */
-  if ((res = do_mpfr_arg1 (arg, type, mpfr_sin)))
-    return res;
-  
-  return NULL_TREE;
-}
-
 /* Fold function call to builtin cos, cosf, or cosl.  Return
    NULL_TREE if no simplification can be made.  */
 static tree
@@ -7232,7 +7214,7 @@ fold_builtin_cos (tree arglist, tree type, tree fndecl)
     return NULL_TREE;
 
   /* Calculate the result when the argument is a constant.  */
-  if ((res = do_mpfr_arg1 (arg, type, mpfr_cos)))
+  if ((res = do_mpfr_arg1 (arg, type, mpfr_cos, NULL, NULL, 0)))
     return res;
   
   /* Optimize cos(-x) into cos (x).  */
@@ -7258,7 +7240,7 @@ fold_builtin_tan (tree arglist, tree type)
     return NULL_TREE;
 
   /* Calculate the result when the argument is a constant.  */
-  if ((res = do_mpfr_arg1 (arg, type, mpfr_tan)))
+  if ((res = do_mpfr_arg1 (arg, type, mpfr_tan, NULL, NULL, 0)))
     return res;
   
   /* Optimize tan(atan(x)) = x.  */
@@ -7272,35 +7254,6 @@ fold_builtin_tan (tree arglist, tree type)
   return NULL_TREE;
 }
 
-/* Fold function call to builtin atan, atanf, or atanl.  Return
-   NULL_TREE if no simplification can be made.  */
-
-static tree
-fold_builtin_atan (tree arglist, tree type)
-{
-
-  tree arg = TREE_VALUE (arglist);
-
-  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
-    return NULL_TREE;
-
-  /* Optimize atan(0.0) = 0.0.  */
-  if (real_zerop (arg))
-    return arg;
-
-  /* Optimize atan(1.0) = pi/4.  */
-  if (real_onep (arg))
-    {
-      REAL_VALUE_TYPE cst;
-
-      real_convert (&cst, TYPE_MODE (type), &dconstpi);
-      SET_REAL_EXP (&cst, REAL_EXP (&cst) - 2);
-      return build_real (type, cst);
-    }
-
-  return NULL_TREE;
-}
-
 /* Fold function call to builtin trunc, truncf or truncl.  Return
    NULL_TREE if no simplification can be made.  */
 
@@ -7924,7 +7877,7 @@ fold_builtin_exponent (tree fndecl, tree arglist,
       tree arg = TREE_VALUE (arglist), res;
       
       /* Calculate the result when the argument is a constant.  */
-      if ((res = do_mpfr_arg1 (arg, type, func)))
+      if ((res = do_mpfr_arg1 (arg, type, func, NULL, NULL, 0)))
        return res;
 
       /* Optimize expN(logN(x)) = x.  */
@@ -9026,12 +8979,72 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     CASE_FLT_FN (BUILT_IN_CBRT):
       return fold_builtin_cbrt (arglist, type);
 
+    CASE_FLT_FN (BUILT_IN_ASIN):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_asin,
+                            &dconstm1, &dconst1, true);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_ACOS):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_acos,
+                            &dconstm1, &dconst1, true);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_ATAN):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_atan,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_ASINH):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_asinh,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_ACOSH):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_acosh,
+                            &dconst1, NULL, true);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_ATANH):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_atanh,
+                            &dconstm1, &dconst1, false);
+    break;
+
     CASE_FLT_FN (BUILT_IN_SIN):
-      return fold_builtin_sin (arglist, type);
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_sin,
+                            NULL, NULL, 0);
+    break;
 
     CASE_FLT_FN (BUILT_IN_COS):
       return fold_builtin_cos (arglist, type, fndecl);
 
+    CASE_FLT_FN (BUILT_IN_TAN):
+      return fold_builtin_tan (arglist, type);
+
+    CASE_FLT_FN (BUILT_IN_SINH):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_sinh,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_COSH):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_cosh,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_TANH):
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_tanh,
+                            NULL, NULL, 0);
+    break;
+
     CASE_FLT_FN (BUILT_IN_EXP):
       return fold_builtin_exponent (fndecl, arglist, mpfr_exp);
 
@@ -9051,12 +9064,6 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     CASE_FLT_FN (BUILT_IN_LOG10):
       return fold_builtin_logarithm (fndecl, arglist, &dconst10);
 
-    CASE_FLT_FN (BUILT_IN_TAN):
-      return fold_builtin_tan (arglist, type);
-
-    CASE_FLT_FN (BUILT_IN_ATAN):
-      return fold_builtin_atan (arglist, type);
-
     CASE_FLT_FN (BUILT_IN_POW):
       return fold_builtin_pow (fndecl, arglist, type);
 
@@ -11269,12 +11276,17 @@ init_target_chars (void)
 
 /* If argument ARG is a REAL_CST, call the one-argument mpfr function
    FUNC on it and return the resulting value as a tree with type TYPE.
-   The mpfr precision is set to the precision of TYPE.  We assume that
-   function FUNC returns zero if the result could be calculated
-   exactly within the requested precision.  */
+   If MIN and/or MAX are not NULL, then the supplied ARG must be
+   within those bounds.  If INCLUSIVE is true, then MIN/MAX are
+   acceptable values, otherwise they are not.  The mpfr precision is
+   set to the precision of TYPE.  We assume that function FUNC returns
+   zero if the result could be calculated exactly within the requested
+   precision.  */
 
 static tree
-do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
+do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
+             const REAL_VALUE_TYPE *min, const REAL_VALUE_TYPE *max,
+             bool inclusive)
 {
   tree result = NULL_TREE;
   
@@ -11284,7 +11296,9 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
     {
       REAL_VALUE_TYPE r = TREE_REAL_CST (arg);
 
-      if (!real_isnan (&r) && !real_isinf (&r))
+      if (!real_isnan (&r) && !real_isinf (&r)
+         && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , &r, min))
+         && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , &r, max)))
         {
          const enum machine_mode mode = TYPE_MODE (type);
          const int prec = REAL_MODE_FORMAT (mode)->p;
index 87c2154f9e1b464b84dd564521814bb3ff43cdfd..97e3f75c6ac3234512f2a022330f412b715870b7 100644 (file)
@@ -1,3 +1,7 @@
+2006-10-24  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * gcc.dg/torture/builtin-math-3.c: New test.
+
 2006-10-24  Erik Edelmann  <eedelman@gcc.gnu.org>
 
        PR fortran/29393
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-math-3.c b/gcc/testsuite/gcc.dg/torture/builtin-math-3.c
new file mode 100644 (file)
index 0000000..60f030b
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2006  Free Software Foundation.
+
+   Verify that built-in math function constant folding of constant
+   arguments is correctly performed by the compiler.
+
+   Origin: Kaveh R. Ghazi, October 23, 2006.  */
+
+/* { dg-do link } */
+
+/* All references to link_error should go away at compile-time.  */
+extern void link_error(int);
+
+/* Test that FUNC(ARG) == (RES).  */
+#define TESTIT(FUNC,ARG,RES) do { \
+  if (__builtin_##FUNC##f(ARG) != RES) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC(ARG) != RES) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC##l(ARG) != RES) \
+    link_error(__LINE__); \
+  } while (0);
+
+/* Test that (LOW) < FUNC(ARG) < (HI).  */
+#define TESTIT2(FUNC,ARG,LOW,HI) do { \
+  if (__builtin_##FUNC##f(ARG) <= (LOW) || __builtin_##FUNC##f(ARG) >= (HI)) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC(ARG) <= (LOW) || __builtin_##FUNC(ARG) >= (HI)) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC##l(ARG) <= (LOW) || __builtin_##FUNC##l(ARG) >= (HI)) \
+    link_error(__LINE__); \
+  } while (0);
+
+int main (void)
+{
+  TESTIT2 (asin, -1, -3.15/2, -3.14/2); /* asin(-1) == -pi/2 */
+  TESTIT (asin, 0, 0); /* asin(0) == 0 */
+  TESTIT2 (asin, 1, 3.14/2, 3.15/2); /* asin(1) == pi/2 */
+
+  TESTIT2 (acos, -1, 3.14, 3.15); /* acos(-1) == pi */
+  TESTIT2 (acos, 0, 3.14/2, 3.15/2); /* acos(0) == pi/2 */
+  TESTIT (acos, 1, 0); /* acos(1) == 0 */
+
+  TESTIT2 (atan, -1, -3.15/4, -3.14/4); /* atan(-1) == -pi/4 */
+  TESTIT (atan, 0, 0); /* atan(0) == 0 */
+  TESTIT2 (atan, 1, 3.14/4, 3.15/4); /* atan(1) == pi/4 */
+
+  TESTIT2 (asinh, -1, -0.89, -0.88); /* asinh(-1) == -0.881... */
+  TESTIT (asinh, 0, 0); /* asinh(0) == 0 */
+  TESTIT2 (asinh, 1, 0.88, 0.89); /* asinh(1) == 0.881... */
+
+  TESTIT (acosh, 1, 0); /* acosh(1) == 0. */
+  TESTIT2 (acosh, 2, 1.31, 1.32); /* acosh(2) == 1.316... */
+
+  TESTIT2 (atanh, -0.5, -0.55, -0.54); /* atanh(-0.5) == -0.549... */
+  TESTIT (atanh, 0, 0); /* atanh(0) == 0 */
+  TESTIT2 (atanh, 0.5, 0.54, 0.55); /* atanh(0.5) == 0.549... */
+
+  TESTIT2 (sinh, -1, -1.18, -1.17); /* sinh(-1) == -1.175... */
+  TESTIT (sinh, 0, 0); /* sinh(0) == 0 */
+  TESTIT2 (sinh, 1, 1.17, 1.18); /* sinh(1) == 1.175... */
+
+  TESTIT2 (cosh, -1, 1.54, 1.55); /* cosh(-1) == 1.543... */
+  TESTIT (cosh, 0, 1); /* cosh(0) == 1 */
+  TESTIT2 (cosh, 1, 1.54, 1.55); /* cosh(1) == 1.543... */
+
+  TESTIT2 (tanh, -1, -0.77, -0.76); /* tanh(-1) == -0.761... */
+  TESTIT (tanh, 0, 0); /* tanh(0) == 0 */
+  TESTIT2 (tanh, 1, 0.76, 0.77); /* tanh(1) == 0.761... */
+
+  return 0;
+}