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 (take 2)


My sincere apologies.  As Brad Lucier has pointed out, my trigonometry
is not what it was twenty years ago, and the identity that I'd intended
to implement is tan(atan(x)) = x, not atan(tan(x)) = x [which is only
valid for -pi/2 < x < pi/2].

The following patch corrects my shame.  Just goes to show you can
list six separate test cases, for a total of 26 checks of a single
patch, and still get things wrong!  Many thanks again to Brad for
his excellent catch.

The following patch has been tested on i686-pc-linux-gnu, with a full
"make bootstrap", all languages except treelang (including Ada), and
regression tested with a top-level "make -k check" with no new failures.
The new test cases are unchanged, and as posted in my original patch.

Ok for mainline?


2003-05-29  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 tan(atan(x)) = x with -ffast-math.

	* gcc.dg/builtins-2.c: Add tests for tan(atan(x)).
	* gcc.dg/builtins-3.c: Add tests for tan(0.0) and atan(0.0).
	* gcc.dg/builtins-7.c: Add tests for tan(atan(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	29 May 2003 04:27:01 -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))
+ 	{
+ 	  enum built_in_function fcode;
+ 	  tree arg = TREE_VALUE (arglist);
+
+ 	  /* Optimize tan(0.0) = 0.0.  */
+ 	  if (real_zerop (arg))
+ 	    return arg;
+
+ 	  /* Optimize tan(atan(x)) = x.  */
+ 	  fcode = builtin_mathfn_code (arg);
+ 	  if (flag_unsafe_math_optimizations
+ 	      && (fcode == BUILT_IN_ATAN
+ 		  || fcode == BUILT_IN_ATANF
+ 		  || fcode == BUILT_IN_ATANL))
+ 	    return TREE_VALUE (TREE_OPERAND (arg, 1));
+ 	}
+       break;
+
+     case BUILT_IN_ATAN:
+     case BUILT_IN_ATANF:
+     case BUILT_IN_ATANL:
+       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ 	{
+ 	  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);
+ 	    }
+ 	}
+       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	29 May 2003 04:23:06 -0000
*************** double test9(double x)
*** 53,58 ****
--- 53,63 ----
    return fabs(exp(x));
  }

+ double test10(double x)
+ {
+   return tan(atan(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 tanf(atanf(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 tanl(atanl(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	29 May 2003 04:23:06 -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	29 May 2003 04:23:06 -0000
*************** void test(double x)
*** 14,30 ****
--- 14,36 ----
  {
    if (pow (x, 1.0) != x)
      link_error ();
+   if (tan (atan (x)) != x)
+     link_error ();
  }

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

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


Roger
--


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