re PR tree-optimization/67815 (Optimize const1 * copysign (const2, y) into copysign...
authorMarek Polacek <polacek@redhat.com>
Wed, 14 Oct 2015 12:54:03 +0000 (12:54 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Wed, 14 Oct 2015 12:54:03 +0000 (12:54 +0000)
PR tree-optimization/67815
* tree-ssa-reassoc.c (attempt_builtin_copysign): New function.
(reassociate_bb): Call it.

* gcc.dg/tree-ssa/reassoc-39.c: New test.
* gcc.dg/tree-ssa/reassoc-40.c: New test.
* gcc.dg/tree-ssa/reassoc-41.c: New test.

From-SVN: r228809

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/reassoc-39.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/reassoc-40.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/reassoc-41.c [new file with mode: 0644]
gcc/tree-ssa-reassoc.c

index 2dcb640a11fd82bb2129587dc23acab25a9d36ba..d85a2704aadd28e8327f5266ece76bfcc07bd1c3 100644 (file)
@@ -1,3 +1,9 @@
+2015-10-14  Marek Polacek  <polacek@redhat.com>
+
+       PR tree-optimization/67815
+       * tree-ssa-reassoc.c (attempt_builtin_copysign): New function.
+       (reassociate_bb): Call it.
+
 2015-10-14  Richard Biener  <rguenther@suse.de>
 
        * tree-vect-data-refs.c (vect_enhance_data_refs_alignment):
index da0015284be2b64e86c2de9fe8c5a92bbca46ea8..670b9e43ce5fb2a47c429ea47b9236ded5a6958c 100644 (file)
@@ -1,3 +1,10 @@
+2015-10-14  Marek Polacek  <polacek@redhat.com>
+
+       PR tree-optimization/67815
+       * gcc.dg/tree-ssa/reassoc-39.c: New test.
+       * gcc.dg/tree-ssa/reassoc-40.c: New test.
+       * gcc.dg/tree-ssa/reassoc-41.c: New test.
+
 2015-10-14  Dominik Vogt  <vogt@linux.vnet.ibm.com>
 
        * gcc.dg/pragma-pop_options-1.c: New test.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-39.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-39.c
new file mode 100644 (file)
index 0000000..589d06b
--- /dev/null
@@ -0,0 +1,41 @@
+/* PR tree-optimization/67815 */
+/* { dg-do compile } */
+/* { dg-options "-Ofast -fdump-tree-reassoc1-details" } */
+
+float
+f0 (float x)
+{
+  return 7.5 * __builtin_copysignf (2.0, x);
+}
+
+float
+f1 (float x)
+{
+  return -7.5 * __builtin_copysignf (2.0, x);
+}
+
+double
+f2 (double x, double y)
+{
+  return x * ((1.0/12) * __builtin_copysign (1.0, y));
+}
+
+double
+f3 (double x, double y)
+{
+  return (x * (-1.0/12)) * __builtin_copysign (1.0, y);
+}
+
+double
+f4 (double x, double y, double z)
+{
+  return (x * z) * ((1.0/12) * __builtin_copysign (4.0, y));
+}
+
+double
+f5 (double x, double y, double z)
+{
+  return (x * (-1.0/12)) * z * __builtin_copysign (2.0, y);
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing copysign" 6 "reassoc1"} }*/
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-40.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-40.c
new file mode 100644 (file)
index 0000000..d65bcc1
--- /dev/null
@@ -0,0 +1,21 @@
+/* PR tree-optimization/67815 */
+/* { dg-do compile } */
+/* { dg-options "-Ofast -frounding-math -fdump-tree-reassoc1-details" } */
+
+/* Test that the copysign reassoc optimization doesn't fire for
+   -frounding-math (i.e. HONOR_SIGN_DEPENDENT_ROUNDING) if the multiplication
+   is inexact.  */
+
+double
+f1 (double y)
+{
+  return (1.2 * __builtin_copysign (1.1, y));
+}
+
+double
+f2 (double y)
+{
+  return (-1.2 * __builtin_copysign (1.1, y));
+}
+
+/* { dg-final { scan-tree-dump-not "Optimizing copysign" "reassoc1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-41.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-41.c
new file mode 100644 (file)
index 0000000..8a18b88
--- /dev/null
@@ -0,0 +1,21 @@
+/* PR tree-optimization/67815 */
+/* { dg-do compile } */
+/* { dg-options "-Ofast -fno-rounding-math -fdump-tree-reassoc1-details" } */
+
+/* Test that the copysign reassoc optimization does fire for
+   -fno-rounding-math (i.e. HONOR_SIGN_DEPENDENT_ROUNDING) if the multiplication
+   is inexact.  */
+
+double
+f1 (double y)
+{
+  return (1.2 * __builtin_copysign (1.1, y));
+}
+
+double
+f2 (double y)
+{
+  return (-1.2 * __builtin_copysign (1.1, y));
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing copysign" 2 "reassoc1"} }*/
index 879722e1c611b3b51a90df99e18255d2a97376c3..62438dd702786aaf8d197dd4ea1e27897c13f22e 100644 (file)
@@ -4622,6 +4622,102 @@ attempt_builtin_powi (gimple *stmt, vec<operand_entry *> *ops)
   return result;
 }
 
+/* Attempt to optimize
+   CST1 * copysign (CST2, y) -> copysign (CST1 * CST2, y) if CST1 > 0, or
+   CST1 * copysign (CST2, y) -> -copysign (CST1 * CST2, y) if CST1 < 0.  */
+
+static void
+attempt_builtin_copysign (vec<operand_entry *> *ops)
+{
+  operand_entry *oe;
+  unsigned int i;
+  unsigned int length = ops->length ();
+  tree cst = ops->last ()->op;
+
+  if (length == 1 || TREE_CODE (cst) != REAL_CST)
+    return;
+
+  FOR_EACH_VEC_ELT (*ops, i, oe)
+    {
+      if (TREE_CODE (oe->op) == SSA_NAME
+         && has_single_use (oe->op))
+       {
+         gimple *def_stmt = SSA_NAME_DEF_STMT (oe->op);
+         if (is_gimple_call (def_stmt))
+           {
+             tree fndecl = gimple_call_fndecl (def_stmt);
+             tree arg0, arg1;
+             switch (DECL_FUNCTION_CODE (fndecl))
+               {
+               CASE_FLT_FN (BUILT_IN_COPYSIGN):
+                 arg0 = gimple_call_arg (def_stmt, 0);
+                 arg1 = gimple_call_arg (def_stmt, 1);
+                 /* The first argument of copysign must be a constant,
+                    otherwise there's nothing to do.  */
+                 if (TREE_CODE (arg0) == REAL_CST)
+                   {
+                     tree mul = const_binop (MULT_EXPR, TREE_TYPE (cst),
+                                             cst, arg0);
+                     /* If we couldn't fold to a single constant, skip it.
+                        That happens e.g. for inexact multiplication when
+                        -frounding-math.  */
+                     if (mul == NULL_TREE)
+                       break;
+                     /* Instead of adjusting the old DEF_STMT, let's build
+                        a new call to not leak the LHS and prevent keeping
+                        bogus debug statements.  DCE will clean up the old
+                        call.  */
+                     gcall *call = gimple_build_call (fndecl, 2, mul, arg1);
+                     tree lhs = make_ssa_name (TREE_TYPE (arg0));
+                     gimple_call_set_lhs (call, lhs);
+                     gimple_set_location (call, gimple_location (def_stmt));
+                     insert_stmt_after (call, def_stmt);
+                     /* We've used the constant, get rid of it.  */
+                     ops->pop ();
+                     bool cst1_neg = real_isneg (TREE_REAL_CST_PTR (cst));
+                     /* Handle the CST1 < 0 case by negating the result.  */
+                     if (cst1_neg)
+                       {
+                         tree negrhs = make_ssa_name (TREE_TYPE (lhs));
+                         gimple *negate_stmt
+                           = gimple_build_assign (negrhs, NEGATE_EXPR, lhs);
+                         insert_stmt_after (negate_stmt, call);
+                         oe->op = negrhs;
+                       }
+                     else
+                       oe->op = lhs;
+                     if (dump_file && (dump_flags & TDF_DETAILS))
+                       {
+                         fprintf (dump_file, "Optimizing copysign: ");
+                         print_generic_expr (dump_file, cst, 0);
+                         fprintf (dump_file, " * ");
+                         print_generic_expr (dump_file,
+                                             gimple_call_fn (def_stmt), 0);
+                         fprintf (dump_file, " (");
+                         print_generic_expr (dump_file, arg0, 0);
+                         fprintf (dump_file, ", ");
+                         print_generic_expr (dump_file, arg1, 0);
+                         fprintf (dump_file, ") into %s",
+                                  cst1_neg ? "-" : "");
+                         print_generic_expr (dump_file,
+                                             gimple_call_fn (def_stmt), 0);
+                         fprintf (dump_file, " (");
+                         print_generic_expr (dump_file, mul, 0);
+                         fprintf (dump_file, ", ");
+                         print_generic_expr (dump_file, arg1, 0);
+                         fprintf (dump_file, "\n");
+                       }
+                     return;
+                   }
+                 break;
+               default:
+                 break;
+               }
+           }
+       }
+    }
+}
+
 /* Transform STMT at *GSI into a copy by replacing its rhs with NEW_RHS.  */
 
 static void
@@ -4764,6 +4860,9 @@ reassociate_bb (basic_block bb)
              if (rhs_code == BIT_IOR_EXPR || rhs_code == BIT_AND_EXPR)
                optimize_range_tests (rhs_code, &ops);
 
+             if (rhs_code == MULT_EXPR)
+               attempt_builtin_copysign (&ops);
+
              if (first_pass_instance
                  && rhs_code == MULT_EXPR
                  && flag_unsafe_math_optimizations)