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] Optimize pow(x,0.0) = pow(1.0,y) = 1.0


The following patch implements the built-in constant folding optimizations
that "pow(x,0.0) = 1.0" and "pow(1.0,y) = 1.0", even when x and/or y are
NaN.  There are plenty more optimizations to come, but the patch below is
large enough as it is.

Firstly, this patch exports the function "omit_one_operand" from
fold-const.c (so that it can be used in builtins.c).  The prototype
is added to tree.h, and whilst I was there I moved the prototype for
div_and_round_double so that all the fold-const.c functions were in
a single place.

Next, I modified builtin_mathfn_code to also handle the binary math
built-ins, such as pow and atan2.  This extended functionality isn't
used yet but will be in follow-up patches.

The actual optimizations themselves are quite straight forward, but
by introducing the variable "type" to hold the function's return type,
it turned out that much of the code in fold_builtin could be simplified.


The following patch has been tested on i686-pc-linux-gnu, with a full
"make bootstrap", all languages except Ada and treelang, and a complete
"make -k check" with no new regressions in the testsuite.  I've also
added a new test to gcc.dg that confirms the optimization is performed.


Ok for mainline?


2003-02-20  Roger Sayle  <roger at eyesopen dot com>

	* fold-const.c (omit_one_operand): No longer static.
	* tree.h (omit_one_operand): Prototype here.
	(div_and_round_double): Keep fold-const.c prototypes together.
	* builtins.c (builtin_mathfn_code): Handle binary built-in
	funtions, such as "pow" and "atan2".
	(fold_builtin): Optimize both pow(x,0.0) and pow(1.0,y) to 1.0.
	Simplify optimizations using "type" the builtin's return type.

	* gcc.dg/builtins-5.c: New test case.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.237
diff -c -3 -p -r1.237 fold-const.c
*** fold-const.c	19 Feb 2003 22:59:33 -0000	1.237
--- fold-const.c	20 Feb 2003 15:19:13 -0000
*************** static int truth_value_p	PARAMS ((enum t
*** 81,87 ****
  static int operand_equal_for_comparison_p PARAMS ((tree, tree, tree));
  static int twoval_comparison_p	PARAMS ((tree, tree *, tree *, int *));
  static tree eval_subst		PARAMS ((tree, tree, tree, tree, tree));
- static tree omit_one_operand	PARAMS ((tree, tree, tree));
  static tree pedantic_omit_one_operand PARAMS ((tree, tree, tree));
  static tree distribute_bit_expr PARAMS ((enum tree_code, tree, tree, tree));
  static tree make_bit_field_ref	PARAMS ((tree, tree, int, int, int));
--- 81,86 ----
*************** eval_subst (arg, old0, new0, old1, new1)
*** 2256,2262 ****
     If OMITTED has side effects, we must evaluate it.  Otherwise, just do
     the conversion of RESULT to TYPE.  */

! static tree
  omit_one_operand (type, result, omitted)
       tree type, result, omitted;
  {
--- 2255,2261 ----
     If OMITTED has side effects, we must evaluate it.  Otherwise, just do
     the conversion of RESULT to TYPE.  */

! tree
  omit_one_operand (type, result, omitted)
       tree type, result, omitted;
  {
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.381
diff -c -3 -p -r1.381 tree.h
*** tree.h	12 Feb 2003 21:48:58 -0000	1.381
--- tree.h	20 Feb 2003 15:19:14 -0000
***************
*** 1,6 ****
  /* Front-end tree definitions for GNU compiler.
     Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
!    2001, 2002 Free Software Foundation, Inc.

  This file is part of GCC.

--- 1,6 ----
  /* Front-end tree definitions for GNU compiler.
     Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
!    2001, 2002, 2003 Free Software Foundation, Inc.

  This file is part of GCC.

*************** extern void rrotate_double	PARAMS ((unsi
*** 2909,2915 ****
--- 2909,2927 ----
  					 HOST_WIDE_INT, unsigned int,
  					 unsigned HOST_WIDE_INT *,
  					 HOST_WIDE_INT *));
+
+ extern int div_and_round_double		PARAMS ((enum tree_code, int,
+ 						 unsigned HOST_WIDE_INT,
+ 						 HOST_WIDE_INT,
+ 						 unsigned HOST_WIDE_INT,
+ 						 HOST_WIDE_INT,
+ 						 unsigned HOST_WIDE_INT *,
+ 						 HOST_WIDE_INT *,
+ 						 unsigned HOST_WIDE_INT *,
+ 						 HOST_WIDE_INT *));
+
  extern int operand_equal_p	PARAMS ((tree, tree, int));
+ extern tree omit_one_operand	PARAMS ((tree, tree, tree));
  extern tree invert_truthvalue	PARAMS ((tree));

  /* In builtins.c */
*************** extern int supports_one_only		PARAMS ((v
*** 3056,3072 ****
  extern void variable_section		PARAMS ((tree, int));
  enum tls_model decl_tls_model		PARAMS ((tree));
  enum symbol_visibility decl_visibility	PARAMS ((tree));
-
- /* In fold-const.c */
- extern int div_and_round_double		PARAMS ((enum tree_code, int,
- 						 unsigned HOST_WIDE_INT,
- 						 HOST_WIDE_INT,
- 						 unsigned HOST_WIDE_INT,
- 						 HOST_WIDE_INT,
- 						 unsigned HOST_WIDE_INT *,
- 						 HOST_WIDE_INT *,
- 						 unsigned HOST_WIDE_INT *,
- 						 HOST_WIDE_INT *));

  /* In stmt.c */
  extern void emit_nop			PARAMS ((void));
--- 3068,3073 ----
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.177
diff -c -3 -p -r1.177 builtins.c
*** builtins.c	11 Feb 2003 21:15:26 -0000	1.177
--- builtins.c	20 Feb 2003 15:19:16 -0000
*************** builtin_mathfn_code (t)
*** 4512,4521 ****

    arglist = TREE_OPERAND (t, 1);
    if (! arglist
!       || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE
!       || TREE_CHAIN (arglist))
      return END_BUILTINS;

    return DECL_FUNCTION_CODE (fndecl);
  }

--- 4512,4541 ----

    arglist = TREE_OPERAND (t, 1);
    if (! arglist
!       || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE)
      return END_BUILTINS;

+   arglist = TREE_CHAIN (arglist);
+   switch (DECL_FUNCTION_CODE (fndecl))
+     {
+     case BUILT_IN_POW:
+     case BUILT_IN_POWF:
+     case BUILT_IN_POWL:
+     case BUILT_IN_ATAN2:
+     case BUILT_IN_ATAN2F:
+     case BUILT_IN_ATAN2L:
+       if (! arglist
+ 	  || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE
+ 	  || TREE_CHAIN (arglist))
+ 	return END_BUILTINS;
+       break;
+
+     default:
+       if (arglist)
+ 	return END_BUILTINS;
+       break;
+     }
+
    return DECL_FUNCTION_CODE (fndecl);
  }

*************** fold_builtin (exp)
*** 4650,4655 ****
--- 4670,4676 ----
  {
    tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
    tree arglist = TREE_OPERAND (exp, 1);
+   tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);

    if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
*************** fold_builtin (exp)
*** 4693,4702 ****
  	      REAL_VALUE_TYPE r, x;

  	      x = TREE_REAL_CST (arg);
! 	      mode = TYPE_MODE (TREE_TYPE (arg));
  	      if (real_sqrt (&r, mode, &x)
  		  || (!flag_trapping_math && !flag_errno_math))
! 		return build_real (TREE_TYPE (arg), r);
  	    }

  	  /* Optimize sqrt(exp(x)) = exp(x/2.0).  */
--- 4714,4723 ----
  	      REAL_VALUE_TYPE r, x;

  	      x = TREE_REAL_CST (arg);
! 	      mode = TYPE_MODE (type);
  	      if (real_sqrt (&r, mode, &x)
  		  || (!flag_trapping_math && !flag_errno_math))
! 		return build_real (type, r);
  	    }

  	  /* Optimize sqrt(exp(x)) = exp(x/2.0).  */
*************** fold_builtin (exp)
*** 4707,4715 ****
  		  || fcode == BUILT_IN_EXPL))
  	    {
  	      tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
! 	      arg = build (RDIV_EXPR, TREE_TYPE (arg),
  			   TREE_VALUE (TREE_OPERAND (arg, 1)),
! 			   build_real (TREE_TYPE (arg), dconst2));
  	      arglist = build_tree_list (NULL_TREE, arg);
  	      return build_function_call_expr (expfn, arglist);
  	    }
--- 4728,4736 ----
  		  || 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);
  	    }
*************** fold_builtin (exp)
*** 4726,4732 ****

  	  /* Optimize exp(0.0) = 1.0.  */
  	  if (real_zerop (arg))
! 	    return build_real (TREE_TYPE (arg), dconst1);

  	  /* Optimize exp(log(x)) = x.  */
  	  fcode = builtin_mathfn_code (arg);
--- 4747,4753 ----

  	  /* Optimize exp(0.0) = 1.0.  */
  	  if (real_zerop (arg))
! 	    return build_real (type, dconst1);

  	  /* Optimize exp(log(x)) = x.  */
  	  fcode = builtin_mathfn_code (arg);
*************** fold_builtin (exp)
*** 4748,4754 ****

  	  /* Optimize log(1.0) = 0.0.  */
  	  if (real_onep (arg))
! 	    return build_real (TREE_TYPE (arg), dconst0);

  	  /* Optimize log(exp(x)) = x.  */
  	  fcode = builtin_mathfn_code (arg);
--- 4769,4775 ----

  	  /* Optimize log(1.0) = 0.0.  */
  	  if (real_onep (arg))
! 	    return build_real (type, dconst0);

  	  /* Optimize log(exp(x)) = x.  */
  	  fcode = builtin_mathfn_code (arg);
*************** fold_builtin (exp)
*** 4766,4796 ****
  	    {
  	      tree logfn = build_function_call_expr (fndecl,
  						     TREE_OPERAND (arg, 1));
! 	      return fold (build (RDIV_EXPR, TREE_TYPE (arg), logfn,
! 				  build_real (TREE_TYPE (arg), dconst2)));
  	    }
  	}
        break;

      case BUILT_IN_INF:
      case BUILT_IN_INFF:
      case BUILT_IN_INFL:
!       return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), true);

      case BUILT_IN_HUGE_VAL:
      case BUILT_IN_HUGE_VALF:
      case BUILT_IN_HUGE_VALL:
!       return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), false);

      case BUILT_IN_NAN:
      case BUILT_IN_NANF:
      case BUILT_IN_NANL:
!       return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), true);

      case BUILT_IN_NANS:
      case BUILT_IN_NANSF:
      case BUILT_IN_NANSL:
!       return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), false);

      case BUILT_IN_FLOOR:
      case BUILT_IN_FLOORF:
--- 4787,4835 ----
  	    {
  	      tree logfn = build_function_call_expr (fndecl,
  						     TREE_OPERAND (arg, 1));
! 	      return fold (build (RDIV_EXPR, type, logfn,
! 				  build_real (type, dconst2)));
  	    }
  	}
        break;

+     case BUILT_IN_POW:
+     case BUILT_IN_POWF:
+     case BUILT_IN_POWL:
+       if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+ 	{
+ 	  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;
+
      case BUILT_IN_INF:
      case BUILT_IN_INFF:
      case BUILT_IN_INFL:
!       return fold_builtin_inf (type, true);

      case BUILT_IN_HUGE_VAL:
      case BUILT_IN_HUGE_VALF:
      case BUILT_IN_HUGE_VALL:
!       return fold_builtin_inf (type, false);

      case BUILT_IN_NAN:
      case BUILT_IN_NANF:
      case BUILT_IN_NANL:
!       return fold_builtin_nan (arglist, type, true);

      case BUILT_IN_NANS:
      case BUILT_IN_NANSF:
      case BUILT_IN_NANSL:
!       return fold_builtin_nan (arglist, type, false);

      case BUILT_IN_FLOOR:
      case BUILT_IN_FLOORF:

*** /dev/null	Thu Aug 30 14:30:55 2001
--- gcc.dg/builtins-5.c	Thu Feb 20 20:09:45 2003
***************
*** 0 ****
--- 1,45 ----
+ /* Copyright (C) 2003  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, 20th February 2003.  */
+
+ /* { dg-do link } */
+ /* { dg-options "-O2 -ffast-math" } */
+
+ extern void link_error(void);
+
+ void test(double x)
+ {
+   if (pow (x, 0.0) != 1.0)
+     link_error ();
+   if (pow (1.0, x) != 1.0)
+     link_error ();
+ }
+
+ void testf(float x)
+ {
+   if (powf (x, 0.0f) != 1.0f)
+     link_error ();
+   if (powf (1.0f, x) != 1.0f)
+     link_error ();
+ }
+
+ void testl(long double x)
+ {
+   if (powl (x, 0.0l) != 1.0l)
+     link_error ();
+   if (powl (1.0l, x) != 1.0l)
+     link_error ();
+ }
+
+ int main()
+ {
+   test (0.0);
+   testf (0.0f);
+   testl (0.0l);
+
+   return 0;
+ }
+

Roger
--
Roger Sayle,                         E-mail: roger at eyesopen dot 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]