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 add code for exp, exp2, exp10/pow10


This patch builds on the one to evaluate sin/cos/tan at compile-time
posted here:
http://gcc.gnu.org/ml/gcc-patches/2006-10/msg01053.html

Below I've written a patch to add code for exp/exp2/exp10/pow10.

Two changes I made were to do_mpfr_arg1().  First, the logical boolean
sense of the variable `exact' was reversed.  I renamed it to `inexact'.

Second, I added code to that function to detect overflow/underflow.
I added a testcase to check that GCC avoids folding in those cases so libc
can set errors or exceptions as necessary.

Tested in combination with the previous patch on sparc-sun-solaris2.10,
including the new testcase, no regressions.  I also ran the `exp' test in
the transcendental accuracy suite and got perfect results.  (There is no
exp2 or exp10/pow10 in the suite.)  The previous sin/cos/tan still pass
with perfect scores as well.

The existing test gcc.dg/torture/builtin-explog-1.c still passes.  This
testcase does check exp2 and exp10/pow10, albeit superficially with only a
few cases.  But at least it shows I've hooked mpfr up correctly for these
functions and not made a silly typo or something like reversing two of
them.

Okay for mainline?

		Thanks,
		--Kaveh


2006-10-22  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* builtins.c (fold_builtin_exponent): Evaluate constant arguments
	at compile-time using MPFR.  Change parameter VALUE to FUNC,
	update all callers.
	(do_mpfr_arg1): Rename `exact' to `inexact'.  Carefully check
	for overflow and underflow at all times and avoid folding in
	those cases.

testsuite:
	* gcc.dg/builtin-notdone-1.c: New test.


diff -rup orig/egcc-SVN20061021/gcc/builtins.c egcc-SVN20061021/gcc/builtins.c
--- orig/egcc-SVN20061021/gcc/builtins.c	2006-10-22 12:45:48.422136516 -0400
+++ egcc-SVN20061021/gcc/builtins.c	2006-10-22 17:57:18.145562518 -0400
@@ -7827,67 +7827,36 @@ fold_builtin_powi (tree fndecl ATTRIBUTE
 }

 /* A subroutine of fold_builtin to fold the various exponent
-   functions.  EXP is the CALL_EXPR of a call to a builtin function.
-   VALUE is the value which will be raised to a power.  */
+   functions.  Return NULL_TREE if no simplification can me made.
+   FUNC is the corresponding MPFR exponent function.  */

 static tree
 fold_builtin_exponent (tree fndecl, tree arglist,
-		       const REAL_VALUE_TYPE *value)
+		       int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
 {
   if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     {
       tree type = TREE_TYPE (TREE_TYPE (fndecl));
-      tree arg = TREE_VALUE (arglist);
-
-      /* Optimize exp*(0.0) = 1.0.  */
-      if (real_zerop (arg))
-	return build_real (type, dconst1);
-
-      /* Optimize expN(1.0) = N.  */
-      if (real_onep (arg))
-	{
-	  REAL_VALUE_TYPE cst;
-
-	  real_convert (&cst, TYPE_MODE (type), value);
-	  return build_real (type, cst);
-	}
-
-      /* Attempt to evaluate expN(integer) at compile-time.  */
-      if (flag_unsafe_math_optimizations
-	  && TREE_CODE (arg) == REAL_CST
-	  && ! TREE_CONSTANT_OVERFLOW (arg))
-	{
-	  REAL_VALUE_TYPE cint;
-	  REAL_VALUE_TYPE c;
-	  HOST_WIDE_INT n;
-
-	  c = TREE_REAL_CST (arg);
-	  n = real_to_integer (&c);
-	  real_from_integer (&cint, VOIDmode, n,
-			     n < 0 ? -1 : 0, 0);
-	  if (real_identical (&c, &cint))
-	    {
-	      REAL_VALUE_TYPE x;
-
-	      real_powi (&x, TYPE_MODE (type), value, n);
-	      return build_real (type, x);
-	    }
-	}
+      tree arg = TREE_VALUE (arglist), res;
+
+      /* Calculate the result when the argument is a constant.  */
+      if ((res = do_mpfr_arg1 (arg, type, func)))
+	return res;

       /* Optimize expN(logN(x)) = x.  */
       if (flag_unsafe_math_optimizations)
 	{
 	  const enum built_in_function fcode = builtin_mathfn_code (arg);

-	  if ((value == &dconste
+	  if ((func == mpfr_exp
 	       && (fcode == BUILT_IN_LOG
 		   || fcode == BUILT_IN_LOGF
 		   || fcode == BUILT_IN_LOGL))
-	      || (value == &dconst2
+	      || (func == mpfr_exp2
 		  && (fcode == BUILT_IN_LOG2
 		      || fcode == BUILT_IN_LOG2F
 		      || fcode == BUILT_IN_LOG2L))
-	      || (value == &dconst10
+	      || (func == mpfr_exp10
 		  && (fcode == BUILT_IN_LOG10
 		      || fcode == BUILT_IN_LOG10F
 		      || fcode == BUILT_IN_LOG10L)))
@@ -8959,14 +8928,14 @@ fold_builtin_1 (tree fndecl, tree arglis
       return fold_builtin_cos (arglist, type, fndecl);

     CASE_FLT_FN (BUILT_IN_EXP):
-      return fold_builtin_exponent (fndecl, arglist, &dconste);
+      return fold_builtin_exponent (fndecl, arglist, mpfr_exp);

     CASE_FLT_FN (BUILT_IN_EXP2):
-      return fold_builtin_exponent (fndecl, arglist, &dconst2);
+      return fold_builtin_exponent (fndecl, arglist, mpfr_exp2);

     CASE_FLT_FN (BUILT_IN_EXP10):
     CASE_FLT_FN (BUILT_IN_POW10):
-      return fold_builtin_exponent (fndecl, arglist, &dconst10);
+      return fold_builtin_exponent (fndecl, arglist, mpfr_exp10);

     CASE_FLT_FN (BUILT_IN_LOG):
       return fold_builtin_logarithm (fndecl, arglist, &dconste);
@@ -11193,22 +11162,34 @@ do_mpfr_arg1 (tree arg, tree type, int (
         {
 	  const enum machine_mode mode = TYPE_MODE (type);
 	  const int prec = REAL_MODE_FORMAT (mode)->p;
-	  int exact;
+	  int inexact;
 	  mpfr_t m;

 	  mpfr_init2 (m, prec);
 	  mpfr_from_real (m, &r);
-	  exact = func (m, m, GMP_RNDN);
+	  mpfr_clear_flags();
+	  inexact = func (m, m, GMP_RNDN);

-	  /* Proceed iff we get a normal number, i.e. not NaN or Inf.
-	     If -frounding-math is set, proceed iff the result of
-	     calling FUNC was exact, i.e. FUNC returned zero.  */
-	  if (mpfr_number_p (m)
-	      && (! flag_rounding_math || exact == 0))
+	  /* Proceed iff we get a normal number, i.e. not NaN or Inf
+	     and no overflow/underflow occurred.  If -frounding-math,
+	     proceed iff the result of calling FUNC was exact.  */
+	  if (mpfr_number_p (m) && !mpfr_overflow_p() && !mpfr_underflow_p()
+	      && (!flag_rounding_math || !inexact))
 	    {
 	      real_from_mpfr (&r, m);
-	      real_convert (&r, mode, &r);
-	      result = build_real (type, r);
+	      /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR
+		 value, check for overflow/underflow.  If the
+		 REAL_VALUE_TYPE is zero but the mpft_t is not, then
+		 we underflowed in the conversion.  */
+	      if (!real_isnan (&r) && !real_isinf (&r)
+		  && (r.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
+	        {
+		  REAL_VALUE_TYPE rmode;
+		  real_convert (&rmode, mode, &r);
+		  /* Proceed iff the specified mode can hold the value.  */
+		  if (real_identical (&rmode, &r))
+		    result = build_real (type, rmode);
+		}
 	    }
 	  mpfr_clear (m);
 	}



/* Test things that should block GCC from optimizing compile-time
   constants passed to a builtin transcendental function.

   Origin: Kaveh R. Ghazi 10/22/2006.  */

/* { dg-do compile } */
/* { dg-options "-fdump-tree-original" } */

extern void foof (float);
extern void foo (double);
extern void fool (long double);

void bar()
{
  /* An argument of NaN is not evaluated at compile-time.  */
  foof (__builtin_exp2f (__builtin_nanf("")));
  foo (__builtin_exp2 (__builtin_nan("")));
  fool (__builtin_exp2l (__builtin_nanl("")));

  /* An argument of Inf/-Inf is not evaluated at compile-time.  */
  foof (__builtin_exp2f (__builtin_inff()));
  foo (__builtin_exp2 (__builtin_inf()));
  fool (__builtin_exp2l (__builtin_infl()));
  foof (__builtin_exp2f (-__builtin_inff()));
  foo (__builtin_exp2 (-__builtin_inf()));
  fool (__builtin_exp2l (-__builtin_infl()));

  /* Result overflows MPFR, which in version 2.2.x has 30 exponent bits.  */
  foof (__builtin_exp2f (0x1p50F));
  foo (__builtin_exp2 (0x1p50));
  fool (__builtin_exp2l (0x1p50L));
  /* Result underflows MPFR, which in version 2.2.x has 30 exponent bits.  */
  foof (__builtin_exp2f (-0x1p50F));
  foo (__builtin_exp2 (-0x1p50));
  fool (__builtin_exp2l (-0x1p50L));

  /* Result overflows GCC's REAL_VALUE_TYPE, which has 26 exponent bits.  */
  foof (__builtin_exp2f (0x1p28F));
  foo (__builtin_exp2 (0x1p28));
  fool (__builtin_exp2l (0x1p28L));
  /* Result underflows GCC's REAL_VALUE_TYPE, which has 26 exponent bits.  */
  foof (__builtin_exp2f (-0x1p28F));
  foo (__builtin_exp2 (-0x1p28));
  fool (__builtin_exp2l (-0x1p28L));

  /* Result overflows (even an extended) C double's mode.  */
  foof (__builtin_exp2f (0x1p24F));
  foo (__builtin_exp2 (0x1p24));
  fool (__builtin_exp2l (0x1p24L));
  /* Result underflows (even an extended) C double's mode.  */
  foof (__builtin_exp2f (-0x1p24F));
  foo (__builtin_exp2 (-0x1p24));
  fool (__builtin_exp2l (-0x1p24L));

  /* Ensure that normal arguments/results are folded.  */
  foof (__builtin_exp2f (1.5F));
  foo (__builtin_exp2 (1.5));
  fool (__builtin_exp2l (1.5L));
  foof (__builtin_exp2f (-1.5F));
  foo (__builtin_exp2 (-1.5));
  fool (__builtin_exp2l (-1.5L));
}

/* { dg-final { scan-tree-dump-times "exp2 " 9 "original" } } */
/* { dg-final { scan-tree-dump-times "exp2f" 9 "original" } } */
/* { dg-final { scan-tree-dump-times "exp2l" 9 "original" } } */
/* { dg-final { cleanup-tree-dump "original" } } */


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