]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
builtins.c (fold_builtin): Optimize cos(-x) as cos(x).
authorRoger Sayle <roger@eyesopen.com>
Tue, 10 Jun 2003 13:05:54 +0000 (13:05 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Tue, 10 Jun 2003 13:05:54 +0000 (13:05 +0000)
* 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

gcc/ChangeLog
gcc/builtins.c
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-20.c [new file with mode: 0644]

index 6ef9b93146028be549c6b88462ffa63ef012e20a..1565c4871c2d97a0e04b1bdb42e4cae04ae31899 100644 (file)
@@ -1,3 +1,13 @@
+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
index 79d46bce2a0e9fc3d6e72fb6c7d0c101710fe64b..9c5a18b50a52bd0732d9a99ca91e93f03e870db5 100644 (file)
@@ -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;
 
index 7b0f2cc533e633eedf30a7e8a8db8af40a896ed7..927b4d7410c5ddf0e3b33caa80f0152d838e60e8 100644 (file)
@@ -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:
index 88381678bf14f447d8321527bf4453e6928acd50..01cf4e7438ba2e0a4cbe8813e88017cf35069ea7 100644 (file)
@@ -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 (file)
index 0000000..a4e24a8
--- /dev/null
@@ -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;
+}
+