aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2003-06-10 13:05:54 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2003-06-10 13:05:54 +0000
commit9f0a7f9dccbf2317fdb4f489b737f37ff30ba996 (patch)
treec3bfed8bf44d2e144c58458d3cfa991de969b782
parent8936c82f1ea5c9146ca32ac5c75ab166d242cf0d (diff)
downloadgcc-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/ChangeLog10
-rw-r--r--gcc/builtins.c8
-rw-r--r--gcc/fold-const.c119
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/builtins-20.c108
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;
+}
+