aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-reassoc.c
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2015-10-14 12:54:03 +0000
committerMarek Polacek <mpolacek@gcc.gnu.org>2015-10-14 12:54:03 +0000
commit0155ad4011c58e3608d88e76d1fa0f628ccedcdb (patch)
tree5a52a546f2b43eb3303cdf7667c6a5678747951b /gcc/tree-ssa-reassoc.c
parentd5efd4498ae04ae9e6cfc193e430febd29773d39 (diff)
downloadgcc-0155ad4011c58e3608d88e76d1fa0f628ccedcdb.zip
gcc-0155ad4011c58e3608d88e76d1fa0f628ccedcdb.tar.gz
gcc-0155ad4011c58e3608d88e76d1fa0f628ccedcdb.tar.bz2
re PR tree-optimization/67815 (Optimize const1 * copysign (const2, y) into copysign (const1 * const2, y) if const1 > 0 or -copysign (const1 * const2, y) if const1 < 0)
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
Diffstat (limited to 'gcc/tree-ssa-reassoc.c')
-rw-r--r--gcc/tree-ssa-reassoc.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 879722e..62438dd 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -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)