[PATCH] Constant folding pow(x,y) for constant y.

Roger Sayle roger@www.eyesopen.com
Mon Mar 31 01:40:00 GMT 2003


The following patch is another installment in my series of constant
folding optimizations for the pow(3) builtin-function.  This round
performs constant folding of pow(x,y) where y is a constant.

This patch also contains a additional call to "fold" when
building exp(x/2.0), and constant folding of sin(0.0) and
cos(0.0).  These hunks didn't seem significant enough to
post separately.

The following patch has been tested by a complete bootstrap on
i686-pc-linux-gnu, all languages except Ada and treelang, and
regression tested with a top-level "make -k check" (except for
libjava due to timeouts) with no new regressions.

Ok for mainline?


2002-03-30  Roger Sayle  <roger@eyesopen.com>

	* emit-rtl.c (dconstm2, dconsthalf): New real constants.
	(init_emit_once): Initialize dconstm2 and dconsthalf here.
	* real.h (dconstm2, dconsthalf): Add prototypes here.
	* real.c (real_sqrt): Use dconsthalf rather than local copy.
	* builtins.c (fold_builtin): When optimizing sqrt(exp(x)) as
	exp(x/2.0) remember to fold the division if possible.
	Fold sin(0.0) as 0.0, cos(0.0) as 1.0, pow(x,1.0) as x,
	pow(x,-1.0) as 1.0/x, pow(x,2.0) as x*x, pow(x,-2.0) as
	1.0/(x*x) and pow(x,0.5) as sqrt(x).

	* gcc.dg/builtins-3.c: Add new tests for sin and cos.
	* gcc.dg/builtins-7.c: New test case.
	* gcc.dg/builtins-8.c: New test case.


Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.316
diff -c -3 -p -r1.316 emit-rtl.c
*** emit-rtl.c	13 Mar 2003 09:02:50 -0000	1.316
--- emit-rtl.c	30 Mar 2003 23:13:10 -0000
*************** REAL_VALUE_TYPE dconst0;
*** 111,116 ****
--- 111,118 ----
  REAL_VALUE_TYPE dconst1;
  REAL_VALUE_TYPE dconst2;
  REAL_VALUE_TYPE dconstm1;
+ REAL_VALUE_TYPE dconstm2;
+ REAL_VALUE_TYPE dconsthalf;

  /* All references to the following fixed hard registers go through
     these unique rtl objects.  On machines where the frame-pointer and
*************** init_emit_once (line_numbers)
*** 5552,5557 ****
--- 5554,5563 ----
    REAL_VALUE_FROM_INT (dconst1,   1,  0, double_mode);
    REAL_VALUE_FROM_INT (dconst2,   2,  0, double_mode);
    REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode);
+   REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode);
+
+   dconsthalf = dconst1;
+   dconsthalf.exp--;

    for (i = 0; i <= 2; i++)
      {
Index: real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.62
diff -c -3 -p -r1.62 real.h
*** real.h	27 Mar 2003 22:42:02 -0000	1.62
--- real.h	30 Mar 2003 23:13:10 -0000
*************** extern void real_ldexp		PARAMS ((REAL_VA
*** 322,333 ****

  /* **** End of software floating point emulator interface macros **** */

! /* Constant real values 0, 1, 2, and -1.  */

  extern REAL_VALUE_TYPE dconst0;
  extern REAL_VALUE_TYPE dconst1;
  extern REAL_VALUE_TYPE dconst2;
  extern REAL_VALUE_TYPE dconstm1;

  /* Function to return a real value (not a tree node)
     from a given integer constant.  */
--- 322,335 ----

  /* **** End of software floating point emulator interface macros **** */

! /* Constant real values 0, 1, 2, -1, -2 and 0.5.  */

  extern REAL_VALUE_TYPE dconst0;
  extern REAL_VALUE_TYPE dconst1;
  extern REAL_VALUE_TYPE dconst2;
  extern REAL_VALUE_TYPE dconstm1;
+ extern REAL_VALUE_TYPE dconstm2;
+ extern REAL_VALUE_TYPE dconsthalf;

  /* Function to return a real value (not a tree node)
     from a given integer constant.  */
Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.112
diff -c -3 -p -r1.112 real.c
*** real.c	27 Mar 2003 22:41:58 -0000	1.112
--- real.c	30 Mar 2003 23:13:11 -0000
*************** real_sqrt (r, mode, x)
*** 4423,4429 ****
       const REAL_VALUE_TYPE *x;
  {
    static REAL_VALUE_TYPE halfthree;
-   static REAL_VALUE_TYPE half;
    static bool init = false;
    REAL_VALUE_TYPE h, t, i;
    int iter, exp;
--- 4423,4428 ----
*************** real_sqrt (r, mode, x)
*** 4452,4459 ****

    if (!init)
      {
!       real_arithmetic (&half, RDIV_EXPR, &dconst1, &dconst2);
!       real_arithmetic (&halfthree, PLUS_EXPR, &dconst1, &half);
        init = true;
      }

--- 4451,4457 ----

    if (!init)
      {
!       real_arithmetic (&halfthree, PLUS_EXPR, &dconst1, &dconsthalf);
        init = true;
      }

*************** real_sqrt (r, mode, x)
*** 4467,4473 ****
        /* i(n+1) = i(n) * (1.5 - 0.5*i(n)*i(n)*x).  */
        real_arithmetic (&t, MULT_EXPR, x, &i);
        real_arithmetic (&h, MULT_EXPR, &t, &i);
!       real_arithmetic (&t, MULT_EXPR, &h, &half);
        real_arithmetic (&h, MINUS_EXPR, &halfthree, &t);
        real_arithmetic (&t, MULT_EXPR, &i, &h);

--- 4465,4471 ----
        /* i(n+1) = i(n) * (1.5 - 0.5*i(n)*i(n)*x).  */
        real_arithmetic (&t, MULT_EXPR, x, &i);
        real_arithmetic (&h, MULT_EXPR, &t, &i);
!       real_arithmetic (&t, MULT_EXPR, &h, &dconsthalf);
        real_arithmetic (&h, MINUS_EXPR, &halfthree, &t);
        real_arithmetic (&t, MULT_EXPR, &i, &h);

*************** real_sqrt (r, mode, x)
*** 4484,4490 ****
    real_arithmetic (&h, MULT_EXPR, &t, &i);
    real_arithmetic (&i, MINUS_EXPR, &dconst1, &h);
    real_arithmetic (&h, MULT_EXPR, &t, &i);
!   real_arithmetic (&i, MULT_EXPR, &half, &h);
    real_arithmetic (&h, PLUS_EXPR, &t, &i);

    /* ??? We need a Tuckerman test to get the last bit.  */
--- 4482,4488 ----
    real_arithmetic (&h, MULT_EXPR, &t, &i);
    real_arithmetic (&i, MINUS_EXPR, &dconst1, &h);
    real_arithmetic (&h, MULT_EXPR, &t, &i);
!   real_arithmetic (&i, MULT_EXPR, &dconsthalf, &h);
    real_arithmetic (&h, PLUS_EXPR, &t, &i);

    /* ??? We need a Tuckerman test to get the last bit.  */
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.183
diff -c -3 -p -r1.183 builtins.c
*** builtins.c	24 Mar 2003 01:24:37 -0000	1.183
--- builtins.c	30 Mar 2003 23:13:12 -0000
*************** fold_builtin (exp)
*** 4743,4757 ****
  		  || fcode == BUILT_IN_EXPL))
  	    {
  	      tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
! 	      arg = build (RDIV_EXPR, type,
! 			   TREE_VALUE (TREE_OPERAND (arg, 1)),
! 			   build_real (type, dconst2));
  	      arglist = build_tree_list (NULL_TREE, arg);
  	      return build_function_call_expr (expfn, arglist);
  	    }
  	}
        break;

      case BUILT_IN_EXP:
      case BUILT_IN_EXPF:
      case BUILT_IN_EXPL:
--- 4743,4783 ----
  		  || fcode == BUILT_IN_EXPL))
  	    {
  	      tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
! 	      arg = fold (build (RDIV_EXPR, type,
! 				 TREE_VALUE (TREE_OPERAND (arg, 1)),
! 				 build_real (type, dconst2)));
  	      arglist = build_tree_list (NULL_TREE, arg);
  	      return build_function_call_expr (expfn, arglist);
  	    }
  	}
        break;

+     case BUILT_IN_SIN:
+     case BUILT_IN_SINF:
+     case BUILT_IN_SINL:
+       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ 	{
+ 	  tree arg = TREE_VALUE (arglist);
+
+ 	  /* Optimize sin(0.0) = 0.0.  */
+ 	  if (real_zerop (arg))
+ 	    return build_real (type, dconst0);
+ 	}
+       break;
+
+     case BUILT_IN_COS:
+     case BUILT_IN_COSF:
+     case BUILT_IN_COSL:
+       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ 	{
+ 	  tree arg = TREE_VALUE (arglist);
+
+ 	  /* Optimize cos(0.0) = 1.0.  */
+ 	  if (real_zerop (arg))
+ 	    return build_real (type, dconst1);
+ 	}
+       break;
+
      case BUILT_IN_EXP:
      case BUILT_IN_EXPF:
      case BUILT_IN_EXPL:
*************** fold_builtin (exp)
*** 4816,4828 ****
  	  tree arg0 = TREE_VALUE (arglist);
  	  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));

- 	  /* Optimize pow(x,0.0) = 1.0.  */
- 	  if (real_zerop (arg1))
- 	    return omit_one_operand (type, build_real (type, dconst1), arg0);
-
  	  /* Optimize pow(1.0,y) = 1.0.  */
  	  if (real_onep (arg0))
  	    return omit_one_operand (type, build_real (type, dconst1), arg1);
  	}
        break;

--- 4842,4916 ----
  	  tree arg0 = TREE_VALUE (arglist);
  	  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));

  	  /* Optimize pow(1.0,y) = 1.0.  */
  	  if (real_onep (arg0))
  	    return omit_one_operand (type, build_real (type, dconst1), arg1);
+
+ 	  if (TREE_CODE (arg1) == REAL_CST
+ 	      && ! TREE_CONSTANT_OVERFLOW (arg1))
+ 	    {
+ 	      REAL_VALUE_TYPE c;
+ 	      c = TREE_REAL_CST (arg1);
+
+ 	      /* Optimize pow(x,0.0) = 1.0.  */
+ 	      if (REAL_VALUES_EQUAL (c, dconst0))
+ 		return omit_one_operand (type, build_real (type, dconst1),
+ 					 arg0);
+
+ 	      /* Optimize pow(x,1.0) = x.  */
+ 	      if (REAL_VALUES_EQUAL (c, dconst1))
+ 		return arg0;
+
+ 	      /* Optimize pow(x,-1.0) = 1.0/x.  */
+ 	      if (REAL_VALUES_EQUAL (c, dconstm1))
+ 		return fold (build (RDIV_EXPR, type,
+ 				    build_real (type, dconst1),
+ 				    arg0));
+
+ 	      /* Optimize pow(x,2.0) = x*x.  */
+ 	      if (REAL_VALUES_EQUAL (c, dconst2)
+ 		  && (*lang_hooks.decls.global_bindings_p) () == 0
+ 		  && ! contains_placeholder_p (arg0))
+ 		{
+ 		  arg0 = save_expr (arg0);
+ 		  return fold (build (MULT_EXPR, type, arg0, arg0));
+ 		}
+
+ 	      /* Optimize pow(x,-2.0) = 1.0/(x*x).  */
+ 	      if (flag_unsafe_math_optimizations
+ 		  && REAL_VALUES_EQUAL (c, dconstm2)
+ 		  && (*lang_hooks.decls.global_bindings_p) () == 0
+ 		  && ! contains_placeholder_p (arg0))
+ 		{
+ 		  arg0 = save_expr (arg0);
+ 		  return fold (build (RDIV_EXPR, type,
+ 				      build_real (type, dconst1),
+ 				      fold (build (MULT_EXPR, type,
+ 						   arg0, arg0))));
+ 		}
+
+ 	      /* Optimize pow(x,0.5) = sqrt(x).  */
+ 	      if (flag_unsafe_math_optimizations
+ 		  && REAL_VALUES_EQUAL (c, dconsthalf))
+ 		{
+ 		  tree sqrtfn;
+
+ 		  if (fcode == BUILT_IN_POW)
+ 		    sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT];
+ 		  else if (fcode == BUILT_IN_POWF)
+ 		    sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTF];
+ 		  else if (fcode == BUILT_IN_POWL)
+ 		    sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTL];
+ 		  else
+ 		    sqrtfn = NULL_TREE;
+
+ 		  if (sqrtfn != NULL_TREE)
+ 		    {
+ 		      tree arglist = build_tree_list (NULL_TREE, arg0);
+ 		      return build_function_call_expr (sqrtfn, arglist);
+ 		    }
+ 		}
+ 	    }
  	}
        break;

Index: testsuite/gcc.dg/builtins-3.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/builtins-3.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 builtins-3.c
*** testsuite/gcc.dg/builtins-3.c	16 Dec 2002 18:22:43 -0000	1.2
--- testsuite/gcc.dg/builtins-3.c	30 Mar 2003 23:13:12 -0000
***************
*** 1,7 ****
! /* Copyright (C) 2002  Free Software Foundation.

     Verify that built-in math function constant folding of constant
!    arguments is correctly performed by the by the compiler.

     Written by Roger Sayle, 16th August 2002.  */

--- 1,7 ----
! /* Copyright (C) 2002, 2003  Free Software Foundation.

     Verify that built-in math function constant folding of constant
!    arguments is correctly performed by the compiler.

     Written by Roger Sayle, 16th August 2002.  */

*************** int main()
*** 24,29 ****
--- 24,35 ----
    if (log (1.0) != 0.0)
      link_error ();

+   if (sin (0.0) != 0.0)
+     link_error ();
+
+   if (cos (0.0) != 1.0)
+     link_error ();
+

    if (sqrtf (0.0f) != 0.0f)
      link_error ();
*************** int main()
*** 37,42 ****
--- 43,54 ----
    if (logf (1.0f) != 0.0f)
      link_error ();

+   if (sinf (0.0f) != 0.0f)
+     link_error ();
+
+   if (cosf (0.0f) != 1.0f)
+     link_error ();
+

    if (sqrtl (0.0l) != 0.0l)
      link_error ();
*************** int main()
*** 48,53 ****
--- 60,71 ----
      link_error ();

    if (logl (1.0l) != 0.0l)
+     link_error ();
+
+   if (sinl (0.0l) != 0.0l)
+     link_error ();
+
+   if (cosl (0.0l) != 1.0l)
      link_error ();

    return 0;


/* Copyright (C) 2003  Free Software Foundation.

   Verify that built-in math function constant folding of constant
   arguments is correctly performed by the compiler.

   Written by Roger Sayle, 30th March 2003.  */

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

extern void link_error(void);

void test(double x)
{
  if (pow (x, 1.0) != x)
    link_error ();
}

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

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

int main()
{
  test (2.0);
  testf (2.0f);
  testl (2.0l);

  return 0;
}



/* Copyright (C) 2003  Free Software Foundation.

   Verify that built-in math function constant folding of functions
   with one constant argument is correctly performed by the compiler.

   Written by Roger Sayle, 30th March 2003.  */

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

extern void abort(void);

void test(double x)
{
  if (pow(x,-1.0) != 1.0/x)
    abort ();

  if (pow(x,2.0) != x*x)
    abort ();

  if (pow(x,-2.0) != 1.0/(x*x))
    abort ();

  if (pow(x,0.5) != sqrt(x))
    abort ();
}

int main()
{
  test (1.0);
  test (2.0);
  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



More information about the Gcc-patches mailing list