fold-const.c (fold <MULT_EXPR>): Optimize both x*pow(x,c) and pow(x,c)*x as pow(x,c+1) for constant values c.

* fold-const.c (fold <MULT_EXPR>): Optimize both x*pow(x,c) and
	pow(x,c)*x as pow(x,c+1) for constant values c.  Optimize x*x
	as pow(x,2.0) when the latter will be expanded back into x*x.
	(fold <RDIV_EXPR>): Optimize pow(x,c)/x as pow(x,c-1).
	* builtins.c (expand_builtin_pow): Ignore flag_errno_math as
	pow can never set errno when used with an integer exponent.
	Always use expand_powi when exponent is -1, 0, 1 or 2.
	(fold_builtin): Don't rewrite pow(x,2.0) as x*x nor pow(x,-2.0)
	as 1.0/(x*x).  This avoids unbounded recursion as we now prefer
	the pow forms of these expressions.

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

From-SVN: r70030
This commit is contained in:
Roger Sayle 2003-08-01 00:36:53 +00:00 committed by Roger Sayle
parent e3da5a9a50
commit 2598550fa6
5 changed files with 177 additions and 32 deletions

View File

@ -1,3 +1,16 @@
2003-07-31 Roger Sayle <roger@eyesopen.com>
* fold-const.c (fold <MULT_EXPR>): Optimize both x*pow(x,c) and
pow(x,c)*x as pow(x,c+1) for constant values c. Optimize x*x
as pow(x,2.0) when the latter will be expanded back into x*x.
(fold <RDIV_EXPR>): Optimize pow(x,c)/x as pow(x,c-1).
* builtins.c (expand_builtin_pow): Ignore flag_errno_math as
pow can never set errno when used with an integer exponent.
Always use expand_powi when exponent is -1, 0, 1 or 2.
(fold_builtin): Don't rewrite pow(x,2.0) as x*x nor pow(x,-2.0)
as 1.0/(x*x). This avoids unbounded recursion as we now prefer
the pow forms of these expressions.
2003-07-31 Geoffrey Keating <geoffk@apple.com>
* Makefile.in (libexecdir): New.

View File

@ -2170,10 +2170,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
if (flag_unsafe_math_optimizations
&& ! flag_errno_math
&& ! optimize_size
&& TREE_CODE (arg1) == REAL_CST
if (TREE_CODE (arg1) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg1))
{
REAL_VALUE_TYPE cint;
@ -2183,13 +2180,21 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
c = TREE_REAL_CST (arg1);
n = real_to_integer (&c);
real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
if (real_identical (&c, &cint)
&& powi_cost (n) <= POWI_MAX_MULTS)
if (real_identical (&c, &cint))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
op = force_reg (mode, op);
return expand_powi (op, mode, n);
/* If the exponent is -1, 0, 1 or 2, then expand_powi is exact.
Otherwise, check the number of multiplications required.
Note that pow never sets errno for an integer exponent. */
if ((n >= -1 && n <= 2)
|| (flag_unsafe_math_optimizations
&& ! optimize_size
&& powi_cost (n) <= POWI_MAX_MULTS))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
op = force_reg (mode, op);
return expand_powi (op, mode, n);
}
}
}
return expand_builtin_mathfn_2 (exp, target, NULL_RTX);
@ -6245,28 +6250,6 @@ fold_builtin (tree exp)
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))

View File

@ -6071,6 +6071,80 @@ fold (tree expr)
return build_function_call_expr (sinfn,
TREE_OPERAND (arg0, 1));
}
/* Optimize x*pow(x,c) as pow(x,c+1). */
if (fcode1 == BUILT_IN_POW
|| fcode1 == BUILT_IN_POWF
|| fcode1 == BUILT_IN_POWL)
{
tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
1)));
if (TREE_CODE (arg11) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg11)
&& operand_equal_p (arg0, arg10, 0))
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
REAL_VALUE_TYPE c;
tree arg, arglist;
c = TREE_REAL_CST (arg11);
real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
arg = build_real (type, c);
arglist = build_tree_list (NULL_TREE, arg);
arglist = tree_cons (NULL_TREE, arg0, arglist);
return build_function_call_expr (powfn, arglist);
}
}
/* Optimize pow(x,c)*x as pow(x,c+1). */
if (fcode0 == BUILT_IN_POW
|| fcode0 == BUILT_IN_POWF
|| fcode0 == BUILT_IN_POWL)
{
tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
1)));
if (TREE_CODE (arg01) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg01)
&& operand_equal_p (arg1, arg00, 0))
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
REAL_VALUE_TYPE c;
tree arg, arglist;
c = TREE_REAL_CST (arg01);
real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
arg = build_real (type, c);
arglist = build_tree_list (NULL_TREE, arg);
arglist = tree_cons (NULL_TREE, arg1, arglist);
return build_function_call_expr (powfn, arglist);
}
}
/* Optimize x*x as pow(x,2.0), which is expanded as x*x. */
if (! optimize_size
&& operand_equal_p (arg0, arg1, 0))
{
tree powfn;
if (type == double_type_node)
powfn = implicit_built_in_decls[BUILT_IN_POW];
else if (type == float_type_node)
powfn = implicit_built_in_decls[BUILT_IN_POWF];
else if (type == long_double_type_node)
powfn = implicit_built_in_decls[BUILT_IN_POWL];
else
powfn = NULL_TREE;
if (powfn)
{
tree arg = build_real (type, dconst2);
tree arglist = build_tree_list (NULL_TREE, arg);
arglist = tree_cons (NULL_TREE, arg0, arglist);
return build_function_call_expr (powfn, arglist);
}
}
}
}
goto associate;
@ -6328,6 +6402,30 @@ fold (tree expr)
tmp));
}
}
/* Optimize pow(x,c)/x as pow(x,c-1). */
if (fcode0 == BUILT_IN_POW
|| fcode0 == BUILT_IN_POWF
|| fcode0 == BUILT_IN_POWL)
{
tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
if (TREE_CODE (arg01) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg01)
&& operand_equal_p (arg1, arg00, 0))
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
REAL_VALUE_TYPE c;
tree arg, arglist;
c = TREE_REAL_CST (arg01);
real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
arg = build_real (type, c);
arglist = build_tree_list (NULL_TREE, arg);
arglist = tree_cons (NULL_TREE, arg1, arglist);
return build_function_call_expr (powfn, arglist);
}
}
}
goto binary;

View File

@ -1,3 +1,7 @@
2003-07-31 Roger Sayle <roger@eyesopen.com>
* gcc.dg/builtins-27.c: New test case.
2003-07-31 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/tls/opt-7.c: New test.

View File

@ -0,0 +1,47 @@
/* 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, 29th July 2003. */
/* { dg-do link } */
/* { dg-options "-O2 -ffast-math" } */
extern void link_error(void);
extern double pow(double,double);
void test(double x)
{
if (pow(x,2.0) != x*x)
link_error ();
if (x*pow(x,2.0) != pow(x,3.0))
link_error ();
if (pow(x,2.0)*x != pow(x,3.0))
link_error ();
if (pow(x,3.0) != x*x*x)
link_error ();
if (pow(x,2.0)*x != x*x*x)
link_error ();
if (x*pow(x,2.0) != x*x*x)
link_error ();
if (pow(x,3.0)/x != pow(x,2.0))
link_error ();
if (pow(x,3.0)/x != x*x)
link_error ();
}
int main()
{
test (2.0);
return 0;
}