re PR middle-end/20219 (Missed optimisation sin / tan --> cos)

PR middle-end/20219
	* fold-const.c (fold binary) <RDIV_EXPR>: Optimize 
	sin(x)/tan(x) as cos(x) and tan(x)/sin(x) as 1.0/cos(x)
	when flag_unsafe_math_optimizations is set and
	we don't care about NaNs or Infinities.

	Move x/expN(y) and x/pow(y,z) transformation into common
	flag_unsafe_math_optimizations section.

testsuite/

	* gcc.dg/builtins-20.c: Add checks for sin(x)/tan(x) and
	tan(x)/sin(x) transformations.


Co-Authored-By: Uros Bizjak <uros@kss-loka.si>

From-SVN: r107597
This commit is contained in:
Roger Sayle 2005-11-28 07:29:43 +00:00 committed by Uros Bizjak
parent 401cd90a90
commit d531830f5d
4 changed files with 110 additions and 30 deletions

View File

@ -1,3 +1,15 @@
2005-11-28 Roger Sayle <roger@eyesopen.com>
Uros Bizjak <uros@kss-loka.si>
PR middle-end/20219
* fold-const.c (fold binary) <RDIV_EXPR>: Optimize
sin(x)/tan(x) as cos(x) and tan(x)/sin(x) as 1.0/cos(x)
when flag_unsafe_math_optimizations is set and
we don't care about NaNs or Infinities.
Move x/expN(y) and x/pow(y,z) transformation into common
flag_unsafe_math_optimizations section.
2005-11-27 Mark Mitchell <mark@codesourcery.com>
* gcc.c (main): Change type of argv to "char **".

View File

@ -8363,36 +8363,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
TREE_OPERAND (arg1, 0));
}
if (flag_unsafe_math_optimizations)
{
enum built_in_function fcode = builtin_mathfn_code (arg1);
/* Optimize x/expN(y) into x*expN(-y). */
if (BUILTIN_EXPONENT_P (fcode))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1)));
tree arglist = build_tree_list (NULL_TREE,
fold_convert (type, arg));
arg1 = build_function_call_expr (expfn, arglist);
return fold_build2 (MULT_EXPR, type, arg0, arg1);
}
/* Optimize x/pow(y,z) into x*pow(y,-z). */
if (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL)
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
tree neg11 = fold_convert (type, negate_expr (arg11));
tree arglist = tree_cons(NULL_TREE, arg10,
build_tree_list (NULL_TREE, neg11));
arg1 = build_function_call_expr (powfn, arglist);
return fold_build2 (MULT_EXPR, type, arg0, arg1);
}
}
if (flag_unsafe_math_optimizations)
{
enum built_in_function fcode0 = builtin_mathfn_code (arg0);
@ -8430,6 +8400,53 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
}
}
/* Optimize sin(x)/tan(x) as cos(x) if we don't care about
NaNs or Infinities. */
if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_TAN)
|| (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_TANF)
|| (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_TANL)))
{
tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1));
if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00)))
&& ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00)))
&& operand_equal_p (arg00, arg01, 0))
{
tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
if (cosfn != NULL_TREE)
return build_function_call_expr (cosfn,
TREE_OPERAND (arg0, 1));
}
}
/* Optimize tan(x)/sin(x) as 1.0/cos(x) if we don't care about
NaNs or Infintes. */
if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_SIN)
|| (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_SINF)
|| (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_SINL)))
{
tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1));
if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00)))
&& ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00)))
&& operand_equal_p (arg00, arg01, 0))
{
tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
if (cosfn != NULL_TREE)
{
tree tmp = TREE_OPERAND (arg0, 1);
tmp = build_function_call_expr (cosfn, tmp);
return fold (build (RDIV_EXPR, type,
build_real (type, dconst1),
tmp));
}
}
}
/* Optimize pow(x,c)/x as pow(x,c-1). */
if (fcode0 == BUILT_IN_POW
|| fcode0 == BUILT_IN_POWF
@ -8453,6 +8470,32 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return build_function_call_expr (powfn, arglist);
}
}
/* Optimize x/expN(y) into x*expN(-y). */
if (BUILTIN_EXPONENT_P (fcode1))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1)));
tree arglist = build_tree_list (NULL_TREE,
fold_convert (type, arg));
arg1 = build_function_call_expr (expfn, arglist);
return fold_build2 (MULT_EXPR, type, arg0, arg1);
}
/* Optimize x/pow(y,z) into x*pow(y,-z). */
if (fcode1 == BUILT_IN_POW
|| fcode1 == BUILT_IN_POWF
|| fcode1 == BUILT_IN_POWL)
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
tree neg11 = fold_convert (type, negate_expr (arg11));
tree arglist = tree_cons(NULL_TREE, arg10,
build_tree_list (NULL_TREE, neg11));
arg1 = build_function_call_expr (powfn, arglist);
return fold_build2 (MULT_EXPR, type, arg0, arg1);
}
}
goto binary;

View File

@ -1,3 +1,10 @@
2005-11-28 Roger Sayle <roger@eyesopen.com>
Uros Bizjak <uros@kss-loka.si>
PR middle-end/20219
* gcc.dg/builtins-20.c: Add checks for sin(x)/tan(x) and
tan(x)/sin(x) transformations.
2005-11-27 Andrew Pinski <pinskia@physics.uc.edu>
PR middle-end/24575

View File

@ -39,6 +39,12 @@ void test1(double x)
if (cos(x)*tan(x) != sin(x))
link_error ();
if (sin(x)/tan(x) != cos(x))
link_error ();
if (tan(x)/sin(x) != 1.0/cos(x))
link_error ();
}
void test2(double x, double y)
@ -67,6 +73,12 @@ void test1f(float x)
if (cosf(x)*tanf(x) != sinf(x))
link_error ();
if (sinf(x)/tanf(x) != cosf(x))
link_error ();
if (tanf(x)/sinf(x) != 1.0f/cosf(x))
link_error ();
#endif
}
@ -97,6 +109,12 @@ void test1l(long double x)
if (cosl(x)*tanl(x) != sinl(x))
link_error ();
if (sinl(x)/tanl(x) != cosl(x))
link_error ();
if (tanl(x)/sinl(x) != 1.0l/cosl(x))
link_error ();
#endif
}