Commit 2598550f by Roger Sayle Committed by Roger Sayle

fold-const.c (fold <MULT_EXPR>): Optimize both x*pow(x,c) and pow(x,c)*x as…

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
parent e3da5a9a
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> 2003-07-31 Geoffrey Keating <geoffk@apple.com>
* Makefile.in (libexecdir): New. * Makefile.in (libexecdir): New.
......
...@@ -2170,10 +2170,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget) ...@@ -2170,10 +2170,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
arg0 = TREE_VALUE (arglist); arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist)); arg1 = TREE_VALUE (TREE_CHAIN (arglist));
if (flag_unsafe_math_optimizations if (TREE_CODE (arg1) == REAL_CST
&& ! flag_errno_math
&& ! optimize_size
&& TREE_CODE (arg1) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg1)) && ! TREE_CONSTANT_OVERFLOW (arg1))
{ {
REAL_VALUE_TYPE cint; REAL_VALUE_TYPE cint;
...@@ -2183,13 +2180,21 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget) ...@@ -2183,13 +2180,21 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
c = TREE_REAL_CST (arg1); c = TREE_REAL_CST (arg1);
n = real_to_integer (&c); n = real_to_integer (&c);
real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0); real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
if (real_identical (&c, &cint) if (real_identical (&c, &cint))
&& powi_cost (n) <= POWI_MAX_MULTS)
{ {
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); /* If the exponent is -1, 0, 1 or 2, then expand_powi is exact.
rtx op = expand_expr (arg0, subtarget, VOIDmode, 0); Otherwise, check the number of multiplications required.
op = force_reg (mode, op); Note that pow never sets errno for an integer exponent. */
return expand_powi (op, mode, n); 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); return expand_builtin_mathfn_2 (exp, target, NULL_RTX);
...@@ -6245,28 +6250,6 @@ fold_builtin (tree exp) ...@@ -6245,28 +6250,6 @@ fold_builtin (tree exp)
build_real (type, dconst1), build_real (type, dconst1),
arg0)); 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). */ /* Optimize pow(x,0.5) = sqrt(x). */
if (flag_unsafe_math_optimizations if (flag_unsafe_math_optimizations
&& REAL_VALUES_EQUAL (c, dconsthalf)) && REAL_VALUES_EQUAL (c, dconsthalf))
......
...@@ -6071,6 +6071,80 @@ fold (tree expr) ...@@ -6071,6 +6071,80 @@ fold (tree expr)
return build_function_call_expr (sinfn, return build_function_call_expr (sinfn,
TREE_OPERAND (arg0, 1)); 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; goto associate;
...@@ -6328,6 +6402,30 @@ fold (tree expr) ...@@ -6328,6 +6402,30 @@ fold (tree expr)
tmp)); 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; goto binary;
......
2003-07-31 Roger Sayle <roger@eyesopen.com>
* gcc.dg/builtins-27.c: New test case.
2003-07-31 Jakub Jelinek <jakub@redhat.com> 2003-07-31 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/tls/opt-7.c: New test. * gcc.dg/tls/opt-7.c: New test.
......
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment