diff options
author | Roger Sayle <roger@eyesopen.com> | 2003-06-10 13:05:54 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2003-06-10 13:05:54 +0000 |
commit | 9f0a7f9dccbf2317fdb4f489b737f37ff30ba996 (patch) | |
tree | c3bfed8bf44d2e144c58458d3cfa991de969b782 | |
parent | 8936c82f1ea5c9146ca32ac5c75ab166d242cf0d (diff) | |
download | gcc-9f0a7f9dccbf2317fdb4f489b737f37ff30ba996.zip gcc-9f0a7f9dccbf2317fdb4f489b737f37ff30ba996.tar.gz gcc-9f0a7f9dccbf2317fdb4f489b737f37ff30ba996.tar.bz2 |
builtins.c (fold_builtin): Optimize cos(-x) as cos(x).
* builtins.c (fold_builtin): Optimize cos(-x) as cos(x).
* fold-const.c (fold <NEGATE_EXPR>): Convert -f(x) into f(-x)
when x is easily negated and f is sin, tan or atan.
(fold <MULT_EXPR>): Optimize tan(x)*cos(x) and cos(x)*tan(x) as
sin(x) with flag_unsafe_math_optimizations.
(fold <RDIV_EXPR>): With flag_unsafe_math_optimizations fold
sin(x)/cos(x) as tan(x) and cos(x)/sin(x) as 1.0/tan(x).
* gcc.dg/builtins-20.c: New test case.
From-SVN: r67701
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/builtins.c | 8 | ||||
-rw-r--r-- | gcc/fold-const.c | 119 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/builtins-20.c | 108 |
5 files changed, 249 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6ef9b93..1565c48 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,15 @@ 2003-06-10 Roger Sayle <roger@eyesopen.com> + * builtins.c (fold_builtin): Optimize cos(-x) as cos(x). + * fold-const.c (fold <NEGATE_EXPR>): Convert -f(x) into f(-x) + when x is easily negated and f is sin, tan or atan. + (fold <MULT_EXPR>): Optimize tan(x)*cos(x) and cos(x)*tan(x) as + sin(x) with flag_unsafe_math_optimizations. + (fold <RDIV_EXPR>): With flag_unsafe_math_optimizations fold + sin(x)/cos(x) as tan(x) and cos(x)/sin(x) as 1.0/tan(x). + +2003-06-10 Roger Sayle <roger@eyesopen.com> + * fold-const.c (fold <EQ_EXPR>): Don't fold x == x only if x is a floating point type *and* we currently honor NaNs. (fold <NE_EXPR>): Likewise. diff --git a/gcc/builtins.c b/gcc/builtins.c index 79d46bc..9c5a18b 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -5346,6 +5346,14 @@ fold_builtin (exp) /* Optimize cos(0.0) = 1.0. */ if (real_zerop (arg)) return build_real (type, dconst1); + + /* Optimize cos(-x) into cos(x). */ + if (TREE_CODE (arg) == NEGATE_EXPR) + { + tree arglist = build_tree_list (NULL_TREE, + TREE_OPERAND (arg, 0)); + return build_function_call_expr (fndecl, arglist); + } } break; diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7b0f2cc..927b4d7 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -5376,6 +5376,33 @@ fold (expr) return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1), TREE_OPERAND (arg0, 0)); + /* Convert -f(x) into f(-x) where f is sin, tan or atan. */ + switch (builtin_mathfn_code (arg0)) + { + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + case BUILT_IN_TAN: + case BUILT_IN_TANF: + case BUILT_IN_TANL: + case BUILT_IN_ATAN: + case BUILT_IN_ATANF: + case BUILT_IN_ATANL: + if (negate_expr_p (TREE_VALUE (TREE_OPERAND (arg0, 1)))) + { + tree fndecl, arg, arglist; + + fndecl = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); + arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); + arg = fold (build1 (NEGATE_EXPR, type, arg)); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (fndecl, arglist); + } + break; + + default: + break; + } return t; case ABS_EXPR: @@ -5965,6 +5992,41 @@ fold (expr) return build_function_call_expr (powfn, arglist); } } + + /* Optimize tan(x)*cos(x) as sin(x). */ + if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_COS) + || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_COSF) + || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_COSL) + || (fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_TAN) + || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_TANF) + || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_TANL)) + && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)), + TREE_VALUE (TREE_OPERAND (arg1, 1)), 0)) + { + tree sinfn; + + switch (fcode0) + { + case BUILT_IN_TAN: + case BUILT_IN_COS: + sinfn = implicit_built_in_decls[BUILT_IN_SIN]; + break; + case BUILT_IN_TANF: + case BUILT_IN_COSF: + sinfn = implicit_built_in_decls[BUILT_IN_SINF]; + break; + case BUILT_IN_TANL: + case BUILT_IN_COSL: + sinfn = implicit_built_in_decls[BUILT_IN_SINL]; + break; + default: + sinfn = NULL_TREE; + } + + if (sinfn != NULL_TREE) + return build_function_call_expr (sinfn, + TREE_OPERAND (arg0, 1)); + } } } goto associate; @@ -6166,6 +6228,63 @@ fold (expr) return fold (build (MULT_EXPR, type, arg0, arg1)); } } + + if (flag_unsafe_math_optimizations) + { + enum built_in_function fcode0 = builtin_mathfn_code (arg0); + enum built_in_function fcode1 = builtin_mathfn_code (arg1); + + /* Optimize sin(x)/cos(x) as tan(x). */ + if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS) + || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF) + || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL)) + && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)), + TREE_VALUE (TREE_OPERAND (arg1, 1)), 0)) + { + tree tanfn; + + if (fcode0 == BUILT_IN_SIN) + tanfn = implicit_built_in_decls[BUILT_IN_TAN]; + else if (fcode0 == BUILT_IN_SINF) + tanfn = implicit_built_in_decls[BUILT_IN_TANF]; + else if (fcode0 == BUILT_IN_SINL) + tanfn = implicit_built_in_decls[BUILT_IN_TANL]; + else + tanfn = NULL_TREE; + + if (tanfn != NULL_TREE) + return build_function_call_expr (tanfn, + TREE_OPERAND (arg0, 1)); + } + + /* Optimize cos(x)/sin(x) as 1.0/tan(x). */ + if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN) + || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF) + || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL)) + && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)), + TREE_VALUE (TREE_OPERAND (arg1, 1)), 0)) + { + tree tanfn; + + if (fcode0 == BUILT_IN_COS) + tanfn = implicit_built_in_decls[BUILT_IN_TAN]; + else if (fcode0 == BUILT_IN_COSF) + tanfn = implicit_built_in_decls[BUILT_IN_TANF]; + else if (fcode0 == BUILT_IN_COSL) + tanfn = implicit_built_in_decls[BUILT_IN_TANL]; + else + tanfn = NULL_TREE; + + if (tanfn != NULL_TREE) + { + tree tmp = TREE_OPERAND (arg0, 1); + tmp = build_function_call_expr (tanfn, tmp); + return fold (build (RDIV_EXPR, type, + build_real (type, dconst1), + tmp)); + } + } + } goto binary; case TRUNC_DIV_EXPR: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8838167..01cf4e7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-06-10 Roger Sayle <roger@eyesopen.com> + + * gcc.dg/builtins-20.c: New test case. + 2003-06-10 Mark Mitchell <mark@codesourcery.com> PR c++/11131 diff --git a/gcc/testsuite/gcc.dg/builtins-20.c b/gcc/testsuite/gcc.dg/builtins-20.c new file mode 100644 index 0000000..a4e24a8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-20.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Verify that built-in math function constant folding doesn't break + anything and produces the expected results. + + Written by Roger Sayle, 8th June 2003. */ + +/* { dg-do link } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern void link_error(void); + +void test1(double x) +{ + if (cos(x) != cos(-x)) + link_error (); + + if (sin(x)/cos(x) != tan(x)) + link_error (); + + if (cos(x)/sin(x) != 1.0/tan(x)) + link_error (); + + if (tan(x)*cos(x) != sin(x)) + link_error (); + + if (cos(x)*tan(x) != sin(x)) + link_error (); +} + +void test2(double x, double y) +{ + if (-tan(x-y) != tan(y-x)) + link_error (); + + if (-sin(x-y) != sin(y-x)) + link_error (); +} + +void test1f(float x) +{ + if (cosf(x) != cosf(-x)) + link_error (); + + if (sinf(x)/cosf(x) != tanf(x)) + link_error (); + + if (cosf(x)/sinf(x) != 1.0f/tanf(x)) + link_error (); + + if (tanf(x)*cosf(x) != sinf(x)) + link_error (); + + if (cosf(x)*tanf(x) != sinf(x)) + link_error (); +} + +void test2f(float x, float y) +{ + if (-tanf(x-y) != tanf(y-x)) + link_error (); + + if (-sinf(x-y) != sinf(y-x)) + link_error (); +} + + +void test1l(long double x) +{ + if (cosl(x) != cosl(-x)) + link_error (); + + if (sinl(x)/cosl(x) != tanl(x)) + link_error (); + + if (cosl(x)/sinl(x) != 1.0l/tanl(x)) + link_error (); + + if (tanl(x)*cosl(x) != sinl(x)) + link_error (); + + if (cosl(x)*tanl(x) != sinl(x)) + link_error (); +} + +void test2l(long double x, long double y) +{ + if (-tanl(x-y) != tanl(y-x)) + link_error (); + + if (-sinl(x-y) != sinl(y-x)) + link_error (); +} + +int main() +{ + test1 (1.0); + test2 (1.0, 2.0); + + test1f (1.0f); + test2f (1.0f, 2.0f); + + test1l (1.0l); + test2l (1.0l, 2.0l); + + return 0; +} + |