This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: PR29335 use MPFR for more trigonometric transcendentals


This patch uses MPFR for the remaining trigonometric transcendentals,
namely asin, acos, atan, asinh, acosh, atanh, sinh, cosh and tanh.

In the process, I added one more bit to do_mpfr_arg1() to add min and max
bounds on the compile-time constant, plus an `inclusive' bool for whether
the bounds themselves are acceptable values.  This allowed me to verify
whether the supplied argument was in the range accepted by the
transcendental function in the generic code before trying to fold it.

The existing sin and atan builtins didn't need their own functions since
they only calculated compile-time constants.  I moved the two lines of
code into the main switch and deleted the functions.

Tested on sparc-sun-solaris2.10, no regressions, the new test
builtin-math-3.c also passes.  I also had another "notdone" test, but
since we've agreed not to use that name, I'll update that as a separate
patch, testing should be done later today.  It did pass in its "notdone"
form so I don't expect any problems...

Finally, all nine functions I've added pass the transcendetal testsuite
with "perfect" results and no regressions in the prior builtins already
converted to MPFR.  Weee! :-)

Okay for mainline?

		Thanks,
		--Kaveh



2006-10-23  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.

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


diff -rup orig/egcc-SVN20061021/gcc/builtins.c egcc-SVN20061021/gcc/builtins.c
--- orig/egcc-SVN20061021/gcc/builtins.c	2006-10-23 20:21:35.101850292 -0400
+++ egcc-SVN20061021/gcc/builtins.c	2006-10-23 21:04:46.261999310 -0400
@@ -149,10 +149,8 @@ static tree fold_builtin_sqrt (tree, tre
 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);
@@ -204,7 +202,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
@@ -7155,23 +7154,6 @@ fold_builtin_cbrt (tree arglist, tree ty
   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
@@ -7183,7 +7165,7 @@ fold_builtin_cos (tree arglist, tree typ
     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).  */
@@ -7209,7 +7191,7 @@ fold_builtin_tan (tree arglist, tree typ
     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.  */
@@ -7223,35 +7205,6 @@ fold_builtin_tan (tree arglist, tree typ
   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.  */

@@ -7840,7 +7793,7 @@ fold_builtin_exponent (tree fndecl, tree
       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.  */
@@ -8921,12 +8874,72 @@ fold_builtin_1 (tree fndecl, tree arglis
     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);

@@ -8946,12 +8959,6 @@ fold_builtin_1 (tree fndecl, tree arglis
     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);

@@ -11143,12 +11150,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;

@@ -11158,7 +11170,9 @@ do_mpfr_arg1 (tree arg, tree type, int (
     {
       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;


/* 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;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]