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] More constant folding of math built-ins.


The following patch implements some more constant folding optimizations
of GCC's mathematical builtins.  We now optimize tan(0.0) = 0.0,
atan(0.0) = 0.0, exp(1.0) = e, atan(1) = pi/4, atan(tan(x)) = x
(with -funsafe-math-optimizations) and evaluate exp(x) when x is
an integer constant (also with -funsafe-math-optimizations).

This patch also includes a bug fix.  The IEEE standard requires that
sin(-0.0) = -0.0, and similarly for tan and atan.  This is corrected
with this patch, which also contains a new test case to catch this.

I'm particularly happy with the atan(1.0) = pi/4.  It is a common
idiom, to write code such as double "pi = 4*atan(1);", indeed it
occurs several times in the SPEC benchmark suite, and can now be
evaluated at compile-time.  Indeed, on x86, "4*atanl(1)" will now
generate the x87's "fldpi" instruction!

The following patch has been tested on i686-pc-linux-gnu with a
complete bootstrap, all languages except treelang (including Ada),
and regression tested with a top-level "make -k check" with no new
failures.

Ok for mainline?


2003-05-28  Roger Sayle  <roger@eyesopen.com>

	* builtins.c (dconstpi, dconste): New mathematical constants.
	(init_builtin_dconsts): New function to initialize dconstpi
	and dconste.
	(fold_builtin): Optimize exp(1.0) = e.  Evaluate exp(x) at
	compile time with -ffast-math when x is an integer constant.
	Optimize tan(0.0) = 0.0.  Optimize atan(0.0) = 0.0,
	atan(1.0) = pi/4 and atan(tan(x)) = x with -ffast-math.

	* gcc.dg/builtins-2.c: Add tests for atan(tan(x)).
	* gcc.dg/builtins-3.c: Add tests for tan(0.0) and atan(0.0).
	* gcc.dg/builtins-7.c: Add tests for atan(tan(x)) == x.
	* gcc.dg/builtins-17.c: New test case.
	* gcc.dg/i386-387-4.c: New test case.
	* gcc.c-torture/execute/ieee/mzero4.c: New test case.


Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.203
diff -c -3 -p -r1.203 builtins.c
*** builtins.c	23 May 2003 20:45:38 -0000	1.203
--- builtins.c	27 May 2003 13:06:22 -0000
*************** tree built_in_decls[(int) END_BUILTINS];
*** 79,84 ****
--- 79,89 ----
     required to implement the function call in all cases.  */
  tree implicit_built_in_decls[(int) END_BUILTINS];

+ /* Trigonometric and mathematical constants used in builtin folding.  */
+ static bool builtin_dconsts_init = 0;
+ static REAL_VALUE_TYPE dconstpi;
+ static REAL_VALUE_TYPE dconste;
+
  static int get_pointer_alignment	PARAMS ((tree, unsigned int));
  static tree c_strlen			PARAMS ((tree));
  static const char *c_getstr		PARAMS ((tree));
*************** static tree fold_builtin_nan		PARAMS ((t
*** 169,174 ****
--- 174,194 ----
  static int validate_arglist		PARAMS ((tree, ...));
  static tree fold_trunc_transparent_mathfn PARAMS ((tree));
  static bool readonly_data_expr		PARAMS ((tree));
+ static void init_builtin_dconsts	PARAMS ((void));
+
+ /* Initialize mathematical constants for constant folding builtins.
+    These constants need to be given to atleast 160 bits precision.  */
+
+ static void
+ init_builtin_dconsts ()
+ {
+   real_from_string (&dconstpi,
+     "3.1415926535897932384626433832795028841971693993751058209749445923078");
+   real_from_string (&dconste,
+     "2.7182818284590452353602874713526624977572470936999595749669676277241");
+
+   builtin_dconsts_init = true;
+ }

  /* Return the alignment in bits of EXP, a pointer valued expression.
     But don't return more than MAX_ALIGN no matter what.
*************** fold_builtin (exp)
*** 5117,5123 ****

  	  /* Optimize sin(0.0) = 0.0.  */
  	  if (real_zerop (arg))
! 	    return build_real (type, dconst0);
  	}
        break;

--- 5137,5143 ----

  	  /* Optimize sin(0.0) = 0.0.  */
  	  if (real_zerop (arg))
! 	    return arg;
  	}
        break;

*************** fold_builtin (exp)
*** 5146,5151 ****
--- 5166,5206 ----
  	  if (real_zerop (arg))
  	    return build_real (type, dconst1);

+ 	  /* Optimize exp(1.0) = e.  */
+ 	  if (real_onep (arg))
+ 	    {
+ 	      REAL_VALUE_TYPE cst;
+
+ 	      if (! builtin_dconsts_init)
+ 		init_builtin_dconsts ();
+ 	      real_convert (&cst, TYPE_MODE (type), &dconste);
+ 	      return build_real (type, cst);
+ 	    }
+
+ 	  /* Attempt to evaluate exp 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;
+
+ 		  if (! builtin_dconsts_init)
+ 		    init_builtin_dconsts ();
+ 		  real_powi (&x, TYPE_MODE (type), &dconste, n);
+ 		  return build_real (type, x);
+ 		}
+ 	    }
+
  	  /* Optimize exp(log(x)) = x.  */
  	  fcode = builtin_mathfn_code (arg);
  	  if (flag_unsafe_math_optimizations
*************** fold_builtin (exp)
*** 5205,5210 ****
--- 5260,5312 ----
  	}
        break;

+     case BUILT_IN_TAN:
+     case BUILT_IN_TANF:
+     case BUILT_IN_TANL:
+       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ 	{
+ 	  tree arg = TREE_VALUE (arglist);
+
+ 	  /* Optimize tan(0.0) = 0.0.  */
+ 	  if (real_zerop (arg))
+ 	    return arg;
+ 	}
+       break;
+
+     case BUILT_IN_ATAN:
+     case BUILT_IN_ATANF:
+     case BUILT_IN_ATANL:
+       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ 	{
+ 	  enum built_in_function fcode;
+ 	  tree arg = TREE_VALUE (arglist);
+
+ 	  /* 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;
+
+ 	      if (! builtin_dconsts_init)
+ 		init_builtin_dconsts ();
+ 	      real_convert (&cst, TYPE_MODE (type), &dconstpi);
+ 	      cst.exp -= 2;
+ 	      return build_real (type, cst);
+ 	    }
+
+ 	  /* Optimize atan(tan(x)) = x.  */
+ 	  fcode = builtin_mathfn_code (arg);
+ 	  if (flag_unsafe_math_optimizations
+ 	      && (fcode == BUILT_IN_TAN
+ 		  || fcode == BUILT_IN_TANF
+ 		  || fcode == BUILT_IN_TANL))
+ 	    return TREE_VALUE (TREE_OPERAND (arg, 1));
+ 	}
+       break;
+
      case BUILT_IN_POW:
      case BUILT_IN_POWF:
      case BUILT_IN_POWL:
*************** fold_builtin (exp)
*** 5291,5297 ****
  		  REAL_VALUE_TYPE cint;
  		  HOST_WIDE_INT n;

! 		  n = real_to_integer(&c);
  		  real_from_integer (&cint, VOIDmode, n,
  				     n < 0 ? -1 : 0, 0);
  		  if (real_identical (&c, &cint))
--- 5393,5399 ----
  		  REAL_VALUE_TYPE cint;
  		  HOST_WIDE_INT n;

! 		  n = real_to_integer (&c);
  		  real_from_integer (&cint, VOIDmode, n,
  				     n < 0 ? -1 : 0, 0);
  		  if (real_identical (&c, &cint))


Index: builtins-2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/builtins-2.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 builtins-2.c
*** builtins-2.c	16 Dec 2002 18:22:43 -0000	1.2
--- builtins-2.c	26 May 2003 17:40:17 -0000
*************** double test9(double x)
*** 53,58 ****
--- 53,63 ----
    return fabs(exp(x));
  }

+ double test10(double x)
+ {
+   return atan(tan(x));
+ }
+
  float test1f(float x)
  {
    return logf(expf(x));
*************** float test9f(float x)
*** 98,103 ****
--- 103,113 ----
    return fabsf(expf(x));
  }

+ float test10f(float x)
+ {
+   return atanf(tanf(x));
+ }
+
  long double test1l(long double x)
  {
    return logl(expl(x));
*************** long double test9l(long double x)
*** 143,146 ****
--- 153,160 ----
    return fabsl(expl(x));
  }

+ long double test10l(long double x)
+ {
+   return atanl(tanl(x));
+ }

Index: builtins-3.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/builtins-3.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 builtins-3.c
*** builtins-3.c	31 Mar 2003 14:30:29 -0000	1.3
--- builtins-3.c	26 May 2003 17:40:17 -0000
*************** int main()
*** 30,35 ****
--- 30,41 ----
    if (cos (0.0) != 1.0)
      link_error ();

+   if (tan (0.0) != 0.0)
+     link_error ();
+
+   if (atan (0.0) != 0.0)
+     link_error ();
+

    if (sqrtf (0.0f) != 0.0f)
      link_error ();
*************** int main()
*** 49,54 ****
--- 55,65 ----
    if (cosf (0.0f) != 1.0f)
      link_error ();

+   if (tanf (0.0f) != 0.0f)
+     link_error ();
+
+   if (atanf (0.0f) != 0.0f)
+     link_error ();

    if (sqrtl (0.0l) != 0.0l)
      link_error ();
*************** int main()
*** 66,71 ****
--- 77,88 ----
      link_error ();

    if (cosl (0.0l) != 1.0l)
+     link_error ();
+
+   if (tanl (0.0l) != 0.0l)
+     link_error ();
+
+   if (atanl (0.0) != 0.0l)
      link_error ();

    return 0;
Index: builtins-7.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/builtins-7.c,v
retrieving revision 1.1
diff -c -3 -p -r1.1 builtins-7.c
*** builtins-7.c	31 Mar 2003 14:30:29 -0000	1.1
--- builtins-7.c	26 May 2003 17:40:17 -0000
*************** void test(double x)
*** 14,30 ****
--- 14,36 ----
  {
    if (pow (x, 1.0) != x)
      link_error ();
+   if (atan (tan (x)) != x)
+     link_error ();
  }

  void testf(float x)
  {
    if (powf (x, 1.0f) != x)
      link_error ();
+   if (atanf (tanf (x)) != x)
+     link_error ();
  }

  void testl(long double x)
  {
    if (powl (x, 1.0l) != x)
+     link_error ();
+   if (atanl (tanl (x)) != x)
      link_error ();
  }



/* Copyright (C) 2003 Free Software Foundation.

   Check that constant folding of built-in math functions doesn't
   break anything and produces the expected results.

   Written by Roger Sayle, 25th May 2003.  */

/* { dg-do link } */
/* { dg-options "-O2 -ffast-math" } */

extern void link_error(void);

extern double exp(double);


int main()
{
  if (exp (1.0) < 2.71 || exp (1.0) > 2.72)
    link_error ();
  if (exp (2.0) < 7.38 || exp (2.0) > 7.39)
    link_error ();
  if (exp (-2.0) < 0.13 || exp (-2.0) > 0.14)
    link_error ();
  if (atan (1.0) < 0.78 || atan (1.0) > 0.79)
    link_error ();

  return 0;
}



/* { dg-do compile { target "i?86-*-*" } } */
/* { dg-options "-O2 -march=i686" } */
/* { dg-final { scan-assembler "fldpi" } } */

long double atanl (long double);

long double pi()
{
  return 4.0 * atanl (1.0);
}


/* Copyright (C) 2003  Free Software Foundation.
   by Roger Sayle <roger@eyesopen.com>, derived from mzero3.c

   Constant folding of sin(-0.0), tan(-0.0) and atan(-0.0) should
   all return -0.0, for both double and float forms.  */

void abort (void);
typedef __SIZE_TYPE__ size_t;
extern int memcmp (const void *, const void *, size_t);

double sin (double);
double tan (double);
double atan (double);

float sinf (float);
float tanf (float);
float atanf (float);

void expectd (double, double);
void expectf (float, float);

void
expectd (double value, double expected)
{
  if (value != expected
      || memcmp ((void *)&value, (void *) &expected, sizeof (double)) != 0)
    abort ();
}

void
expectf (float value, float expected)
{
  if (value != expected
      || memcmp ((void *)&value, (void *) &expected, sizeof (float)) != 0)
    abort ();
}

int main ()
{
  expectd (sin (0.0), 0.0);
  expectd (tan (0.0), 0.0);
  expectd (atan (0.0), 0.0);

  expectd (sin (-0.0), -0.0);
  expectd (tan (-0.0), -0.0);
  expectd (atan (-0.0), -0.0);

  expectf (sinf (0.0f), 0.0f);
  expectf (tanf (0.0f), 0.0f);
  expectf (atanf (0.0f), 0.0f);

  expectf (sinf (-0.0f), -0.0f);
  expectf (tanf (-0.0f), -0.0f);
  expectf (atanf (-0.0f), -0.0f);

  return 0;
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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