builtins.c (fold_builtin): Constant fold expressions as x*0.5 instead of x/2.0.

* builtins.c (fold_builtin):  Constant fold expressions as x*0.5
	instead of x/2.0.  Optimize sqrt(pow(x,y)) as pow(x,y*0.5),
	log(pow(x,y)) as y*log(x), pow(exp(x),y) as exp(x*y),
	pow(sqrt(x),y) as pow(x,y*0.5) and pow(pow(x,y),z) as pow(x,y*z).
	Delete function scope "fcode" variable to avoid shadowing.

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

From-SVN: r65386
This commit is contained in:
Roger Sayle 2003-04-08 23:24:38 +00:00 committed by Roger Sayle
parent c583e7c354
commit 531878a68e
5 changed files with 253 additions and 8 deletions

View file

@ -1,3 +1,11 @@
2003-04-08 Roger Sayle <roger@eyesopen.com>
* builtins.c (fold_builtin): Constant fold expressions as x*0.5
instead of x/2.0. Optimize sqrt(pow(x,y)) as pow(x,y*0.5),
log(pow(x,y)) as y*log(x), pow(exp(x),y) as exp(x*y),
pow(sqrt(x),y) as pow(x,y*0.5) and pow(pow(x,y),z) as pow(x,y*z).
Delete function scope "fcode" variable to avoid shadowing.
2003-04-08 Kevin Buettner <kevinb@redhat.com>
* dwarf2out.c (DWARF_ARANGES_HEADER_SIZE, DWARF_ARANGES_PAD_SIZE):

View file

@ -4686,12 +4686,11 @@ fold_builtin (exp)
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)
return 0;
switch (fcode)
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_CONSTANT_P:
return fold_builtin_constant_p (arglist);
@ -4735,7 +4734,7 @@ fold_builtin (exp)
return build_real (type, r);
}
/* Optimize sqrt(exp(x)) = exp(x/2.0). */
/* Optimize sqrt(exp(x)) = exp(x*0.5). */
fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_EXP
@ -4743,12 +4742,28 @@ fold_builtin (exp)
|| fcode == BUILT_IN_EXPL))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
arg = fold (build (RDIV_EXPR, type,
arg = fold (build (MULT_EXPR, type,
TREE_VALUE (TREE_OPERAND (arg, 1)),
build_real (type, dconst2)));
build_real (type, dconsthalf)));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize sqrt(pow(x,y)) = pow(x,y*0.5). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL))
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
tree narg1 = fold (build (MULT_EXPR, type, arg1,
build_real (type, dconsthalf)));
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (powfn, arglist);
}
}
break;
@ -4820,7 +4835,7 @@ fold_builtin (exp)
|| fcode == BUILT_IN_EXPL))
return TREE_VALUE (TREE_OPERAND (arg, 1));
/* Optimize log(sqrt(x)) = log(x)/2.0. */
/* Optimize log(sqrt(x)) = log(x)*0.5. */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_SQRT
|| fcode == BUILT_IN_SQRTF
@ -4828,8 +4843,23 @@ fold_builtin (exp)
{
tree logfn = build_function_call_expr (fndecl,
TREE_OPERAND (arg, 1));
return fold (build (RDIV_EXPR, type, logfn,
build_real (type, dconst2)));
return fold (build (MULT_EXPR, type, logfn,
build_real (type, dconsthalf)));
}
/* Optimize log(pow(x,y)) = y*log(x). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL))
{
tree arg0, arg1, logfn;
arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
arglist = build_tree_list (NULL_TREE, arg0);
logfn = build_function_call_expr (fndecl, arglist);
return fold (build (MULT_EXPR, type, arg1, logfn));
}
}
break;
@ -4839,6 +4869,7 @@ fold_builtin (exp)
case BUILT_IN_POWL:
if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
{
enum built_in_function fcode;
tree arg0 = TREE_VALUE (arglist);
tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
@ -4895,6 +4926,7 @@ fold_builtin (exp)
{
tree sqrtfn;
fcode = DECL_FUNCTION_CODE (fndecl);
if (fcode == BUILT_IN_POW)
sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT];
else if (fcode == BUILT_IN_POWF)
@ -4911,6 +4943,49 @@ fold_builtin (exp)
}
}
}
/* Optimize pow(exp(x),y) = exp(x*y). */
fcode = builtin_mathfn_code (arg0);
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_EXP
|| fcode == BUILT_IN_EXPF
|| fcode == BUILT_IN_EXPL))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
arg = fold (build (MULT_EXPR, type, arg, arg1));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_SQRT
|| fcode == BUILT_IN_SQRTF
|| fcode == BUILT_IN_SQRTL))
{
tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree narg1 = fold (build (MULT_EXPR, type, arg1,
build_real (type, dconsthalf)));
arglist = tree_cons (NULL_TREE, narg0,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (fndecl, arglist);
}
/* Optimize pow(pow(x,y),z) = pow(x,y*z). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL))
{
tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
tree narg1 = fold (build (MULT_EXPR, type, arg01, arg1));
arglist = tree_cons (NULL_TREE, arg00,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (fndecl, arglist);
}
}
break;

View file

@ -1,3 +1,8 @@
2003-04-08 Roger Sayle <roger@eyesopen.com>
* gcc.dg/builtins-9.c: New test case.
* gcc.dg/builtins-10.c: New test case.
2003-04-07 J"orn Rennecke <joern.rennecke@superh.com>
* gcc.dg/noncompile/init-4.c.c: New test.

View file

@ -0,0 +1,54 @@
/* 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, 2nd April 2003. */
/* { dg-do link } */
/* { dg-options "-O2 -ffast-math" } */
extern void link_error(void);
extern double exp(double);
extern double log(double);
extern double sqrt(double);
extern double pow(double,double);
void test(double x)
{
if (sqrt(pow(x,4.0)) != x*x)
link_error ();
if (pow(sqrt(x),4.0) != x*x)
link_error ();
if (pow(pow(x,4.0),0.25) != x)
link_error ();
}
void test2(double x, double y, double z)
{
if (sqrt(pow(x,y)) != pow(x,y*0.5))
link_error ();
if (log(pow(x,y)) != y*log(x))
link_error ();
if (pow(exp(x),y) != exp(x*y))
link_error ();
if (pow(sqrt(x),y) != pow(x,y*0.5))
link_error ();
if (pow(pow(x,y),z) != pow(x,y*z))
link_error ();
}
int main()
{
test (2.0);
test2 (2.0, 3.0, 4.0);
return 0;
}

View file

@ -0,0 +1,103 @@
/* Copyright (C) 2003 Free Software Foundation.
Check that constant folding of built-in math functions doesn't
break anything.
Written by Roger Sayle, 2nd April 2003. */
/* { dg-do compile } */
/* { dg-options "-O2 -ffast-math" } */
extern double log(double);
extern double exp(double);
extern double sqrt(double);
extern double pow(double,double);
extern float logf(float);
extern float expf(float);
extern float sqrtf(float);
extern float powf(float,float);
extern long double logl(long double);
extern long double expl(long double);
extern long double sqrtl(long double);
extern long double powl(long double,long double);
double test1(double x, double y)
{
return log(pow(x,y));
}
double test2(double x, double y)
{
return sqrt(pow(x,y));
}
double test3(double x, double y)
{
return pow(exp(x),y);
}
double test4(double x, double y)
{
return pow(sqrt(x),y);
}
double test5(double x, double y, double z)
{
return pow(pow(x,y),z);
}
float test1f(float x, float y)
{
return logf(powf(x,y));
}
float test2f(float x, float y)
{
return sqrtf(powf(x,y));
}
float test3f(float x, float y)
{
return powf(expf(x),y);
}
float test4f(float x, float y)
{
return powf(sqrtf(x),y);
}
float test5f(float x, float y, float z)
{
return powf(powf(x,y),z);
}
long double test1l(long double x, long double y)
{
return logl(powl(x,y));
}
long double test2l(long double x, long double y)
{
return sqrtl(powl(x,y));
}
long double test3l(long double x, long double y)
{
return powl(expl(x),y);
}
long double test4l(long double x, long double y)
{
return powl(sqrtl(x),y);
}
long double test5l(long double x, long double y, long double z)
{
return powl(powl(x,y),z);
}