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]

[RFC PATCH] Convert pow(10.0,x) -> exp10(x), etc...


Roger Sayle wrote:

One thought that you might consider, but that doesn't have to be part
of this change, would be to reorganize where this transformation is
performed...

I'm thinking of something like, when -ffast-math is specified, converting
exp10, exp2, etc... into the equivalent pow(10.0,x) and pow(2.0,x) in
fold_builtin_exponent, so that pow is the canonical form in the tree-ssa
optimizers, but then in expand_builtin_pow, we convert pow(10.0,x)
and pow(2.0,x) back to optabs/calls for exp10 and exp2.

This would simplify fold_builtin_exponent as all of the optimizations
would be performed in fold_builtin_pow. It would also simplify the
code in fold-const.c that catches "exp2(x)*exp2(y) -> exp2(x+y)",
which would be subsumed by the "pow(z,x)*pow(z,y) -> pow(z,x+y)".


Until we had code to convert pow(2.0,x) into exp2, it'd be impossible to require the above canonicalization. Interestingly, one of the optimizations that both your patch and canonicalization allow but that we don't currently get is "exp2(x) * pow(2.0,y)".


In short, I think your patch is a good idea. Even without optab support calling exp2 and exp10 results in shorter code (fewer arguments), and their libm functions are often more efficient than the generic pow. And it opens up some interesting possibilities for follow-up patches.



I hope that Roger doesn't mind that a part of our private communication is forwarded to the gcc-patches list, but following patch is based on his suggestions. This [RFC!] patch implements expansion of pow(10.0, x) as exp10(x) and similar for pow(2.0, x) and pow(e, x).

However, I encoutered a couple of problems:

1.) The definition of BUILT_IN_EXP10 is defined as DEF_EXT_LIB_BUILTIN, and because of this, mathfn_built_in() always returns a NULL_TREE that triggers gcc_assert:

+      fn = mathfn_built_in (TREE_TYPE (arg1), expcode);
+      gcc_assert (fn != NULL_TREE);

If BUILT_IN_EXP10 is defined as DEF_C99_BUILTIN, everything works OK.

2.) I dont't know how to declare an 'e' constant in test file that would satisfy ' if (REAL_VALUES_EQUAL (c, dconste))'. M_E from libm is not good.

Other that that, patch works OK and was succesfully bootstrapped on i686-pc-linux gnu. It introduces no regressions for c and c++. Also attached is an (incomplete) testcase that checks for pow->exp transformations.

2005-04-15 Uros Bizjak <uros@kss-loka.si>

   * builtins.c (expand_builtin_pow): Expand pow(e, x) as exp(x),
   expand pow(10.0, x) as exp10(x) and pow(2.0, x) as exp2(x)
   in c99 mode only.

testsuite:

* gcc.dg/builtins-54.c: New file.

Uros.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.454
diff -u -p -r1.454 builtins.c
--- builtins.c	15 Apr 2005 05:43:46 -0000	1.454
+++ builtins.c	15 Apr 2005 08:28:22 -0000
@@ -2487,6 +2487,96 @@ expand_builtin_pow (tree exp, rtx target
 
   if (! flag_unsafe_math_optimizations)
     return NULL_RTX;
+
+  if (TREE_CODE (arg0) == REAL_CST
+     && ! TREE_CONSTANT_OVERFLOW (arg0))
+    {
+      REAL_VALUE_TYPE c = TREE_REAL_CST (arg0);
+ 
+      /* Optimize pow(e,y) = exp(y).  */
+      if (REAL_VALUES_EQUAL (c, dconste))
+	{
+	  tree fndecl = get_callee_fndecl (exp);
+	  enum built_in_function fcode, expcode;
+	  tree fn;
+
+	  fcode = DECL_FUNCTION_CODE (fndecl);
+
+	  if (fcode == BUILT_IN_POW
+	      || fcode == BUILT_IN_POWF
+	      || fcode == BUILT_IN_POWL)
+	    expcode = BUILT_IN_EXP;
+	  else
+	    gcc_unreachable();
+
+	  fn = mathfn_built_in (TREE_TYPE (arg1), expcode);
+	  gcc_assert (fn != NULL_TREE);
+
+	  arglist = build_tree_list (NULL_TREE, arg1);
+	  exp = build_function_call_expr (fn, arglist);
+
+	  return expand_builtin_mathfn (exp, target, subtarget);
+	}
+
+      /* Optimize pow(10.0,y) = exp10(y).  */
+      else if (REAL_VALUES_EQUAL (c, dconst10))
+	{
+	  tree fndecl = get_callee_fndecl (exp);
+	  enum built_in_function fcode, expcode;
+	  tree fn;
+
+	  /* Only convert in ISO C99 mode.  */
+	  if (!TARGET_C99_FUNCTIONS)
+	    return NULL_RTX;
+
+	  fcode = DECL_FUNCTION_CODE (fndecl);
+
+	  if (fcode == BUILT_IN_POW
+	      || fcode == BUILT_IN_POWF
+	      || fcode == BUILT_IN_POWL)
+	    expcode = BUILT_IN_EXP10;
+	  else
+	    gcc_unreachable();
+
+	  fn = mathfn_built_in (TREE_TYPE (arg1), expcode);
+	  gcc_assert (fn != NULL_TREE);
+
+	  arglist = build_tree_list (NULL_TREE, arg1);
+	  exp = build_function_call_expr (fn, arglist);
+
+	  return expand_builtin_mathfn (exp, target, subtarget);
+	}
+
+      /* Optimize pow(2.0,y) = exp2(y).  */
+      else if (REAL_VALUES_EQUAL (c, dconst2))
+	{
+	  tree fndecl = get_callee_fndecl (exp);
+	  enum built_in_function fcode, expcode;
+	  tree fn;
+
+	  /* Only convert in ISO C99 mode.  */
+	  if (!TARGET_C99_FUNCTIONS)
+	    return NULL_RTX;
+
+	  fcode = DECL_FUNCTION_CODE (fndecl);
+
+	  if (fcode == BUILT_IN_POW
+	      || fcode == BUILT_IN_POWF
+	      || fcode == BUILT_IN_POWL)
+	    expcode = BUILT_IN_EXP2;
+	  else
+	    gcc_unreachable();
+
+	  fn = mathfn_built_in (TREE_TYPE (arg1), expcode);
+	  gcc_assert (fn != NULL_TREE);
+
+	  arglist = build_tree_list (NULL_TREE, arg1);
+	  exp = build_function_call_expr (fn, arglist);
+
+	  return expand_builtin_mathfn (exp, target, subtarget);
+	}
+    }
+
   return expand_builtin_mathfn_2 (exp, target, subtarget);
 }
 
/* Copyright (C) 2005 Free Software Foundation.

   Check that pow(2.0, x), powf(2.0, x), powl(2.0, x) and
   pow(10.0, x), powf(10.0, x), powl(10.0, x) functions compile.

   Written by Uros Bizjak, 15th April 2005.  */

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

#include "builtins-config.h"

extern double pow(double, double);

extern float powf(float, float);

extern long double powl(long double, long double);

#if 0
double test1(double x)
{
  return pow(10.0, x);
}
#endif

#ifdef HAVE_C99_RUNTIME
double test2(double x)
{
  return pow(2.0, x);
}
#endif

#if 0
double test1f(float x)
{
  return powf(10.0, x);
}
#endif

#ifdef HAVE_C99_RUNTIME
double test2f(float x)
{
  return powf(2.0, x);
}
#endif

#if 0
long double test1l(long double x)
{
  return powl(10.0, x);
}
#endif

#ifdef HAVE_C99_RUNTIME
long double test2l(long double x)
{
  return powl(2.0, x);
}
#endif

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