From: Robin Dapp <[email protected]>
This patch adds a wrapper for the multiplicative factors in plus/mult
tree rewriting. Wrapping plus/mult allows to easily add floating-point
handling to the rewriting functions and also permits extending to
vectors later. Apart from that, there's no structural change and the
wi::plus/mult operations are done with real_arithmetic instead.
As far as I know there is no further guard necessary as reassoc only
works on floating-point types when -fassociative-math is specified.
PR tree-optimization/113583
gcc/ChangeLog:
* tree-ssa-reassoc.cc (constant_maybe_expensive): Add
floating-point variant.
(struct mult_factor): Wrapper for multiplicative factor.
(struct plus_mult_tree_state): Use wrapper for hashmap and
constant.
(linearize_plus_mult_tree): Add float handling.
(expand_plus_mult_tree): Use wrapper.
(gather_plus_mult_tree_stats): Use wrapper.
(rewrite_plus_mult_tree): Use wrapper and allow float.
(reassociate_bb): Allow float for plus/mult.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/reassoc-54.c: New test.
* gcc.dg/tree-ssa/reassoc-55.c: New test.
---
gcc/testsuite/gcc.dg/tree-ssa/reassoc-54.c | 18 ++
gcc/testsuite/gcc.dg/tree-ssa/reassoc-55.c | 30 +++
gcc/tree-ssa-reassoc.cc | 244 +++++++++++++++++----
3 files changed, 248 insertions(+), 44 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-54.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-55.c
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-54.c
b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-54.c
new file mode 100644
index 00000000000..e95c677545d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-54.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2 -ffast-math -fdump-tree-reassoc-details" } */
+
+double
+foo (double fs)
+{
+ return 0.5 * (fs + 1.0) + 0.25 * (fs + 2.0);
+}
+
+double srcn, feqa, fs;
+
+double
+foo2 (void)
+{
+ return srcn - 0.5 * (4.0 - feqa) + 0.25 * (4.0 + fs);
+}
+
+/* { dg-final { scan-tree-dump-times "Rewriting plus/mult" 2 "reassoc1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-55.c
b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-55.c
new file mode 100644
index 00000000000..e101cbde5b3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-55.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2 -ffast-math -fno-tree-vectorize
-fdump-tree-reassoc-details" } */
+
+/* This is from PR tree-optimization/113583 */
+
+#define SX 100
+#define SY 100
+#define SZ 130
+#define NN 20
+#define OMEGA 0.123
+#define LAMBDA (1.0 / (0.5 + 3.0 / (16.0 * (1.0 / OMEGA - 0.5))))
+#define CST1 (1.0 / 3.0)
+#define FEQS (CST1 * (1.0 + 4.5 * 1.0 * 1.0))
+
+void
+foo (double *src, double *dst)
+{
+ double avg_diff;
+ unsigned i = 0;
+
+ for (i = 0; i < SX * SY * SZ * NN; i += NN)
+ {
+ avg_diff = 0.5 * (src[i + 1] + src[i + 2]) - FEQS;
+
+ dst[i] = src[i] - OMEGA * (src[i] - CST1 * 1.0);
+ dst[i + 1] = src[i + 1] - OMEGA * avg_diff - LAMBDA * (0.1 - 0.2);
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Rewriting plus/mult" 2 "reassoc1" } } */
diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc
index 211e8778d6c..440c6271e28 100644
--- a/gcc/tree-ssa-reassoc.cc
+++ b/gcc/tree-ssa-reassoc.cc
@@ -1871,6 +1871,148 @@ constant_maybe_expensive (REAL_VALUE_TYPE)
return false;
}
+static inline bool
+constant_maybe_expensive (tree t)
+{
+ tree type = TREE_TYPE (t);
+ gcc_checking_assert (INTEGRAL_TYPE_P (type)
+ || SCALAR_FLOAT_TYPE_P (type));
+ if (INTEGRAL_TYPE_P (type))
+ return constant_maybe_expensive (wi::to_wide (t));
+ else
+ return constant_maybe_expensive (TREE_REAL_CST (t));
+}
+
+/* Helper to wrap operations for the constant multiplicative factors in
+ plus/mult trees. */
+struct mult_factor
+{
+ wide_int cst;
+ REAL_VALUE_TYPE fcst;
+
+ HOST_WIDE_INT prec;
+ tree type;
+ bool is_float;
+
+ bool is_zero ()
+ {
+ if (!is_float)
+ return cst == wi::zero (prec);
+ else
+ return real_equal (&fcst, &dconst0);
+ }
+
+ void mul (tree other)
+ {
+ tree other_type = TREE_TYPE (other);
+ gcc_checking_assert ((!is_float && INTEGRAL_TYPE_P (other_type))
+ || (is_float && SCALAR_FLOAT_TYPE_P (other_type)));
+ if (!is_float)
+ cst = wi::mul (cst, wi::to_wide (other));
+ else
+ real_arithmetic (&fcst, MULT_EXPR, &fcst,
+ TREE_REAL_CST_PTR (other));
+ }
+
+ void mul (mult_factor &other)
+ {
+ gcc_checking_assert (is_float == other.is_float);
+ if (!is_float)
+ cst = wi::mul (cst, other.cst);
+ else
+ real_arithmetic (&fcst, MULT_EXPR, &fcst,
+ &other.fcst);
+ }
+
+ void plus (tree other)
+ {
+ tree other_type = TREE_TYPE (other);
+ gcc_checking_assert ((!is_float && INTEGRAL_TYPE_P (other_type))
+ || (is_float && SCALAR_FLOAT_TYPE_P (other_type)));
+ if (!is_float)
+ cst = wi::add (cst, wi::to_wide (other));
+ else
+ real_arithmetic (&fcst, PLUS_EXPR, &fcst,
+ TREE_REAL_CST_PTR (other));
+ }
+
+ void plus (mult_factor &other)
+ {
+ gcc_checking_assert (is_float == other.is_float);
+ if (!is_float)
+ cst = wi::add (cst, other.cst);
+ else
+ real_arithmetic (&fcst, PLUS_EXPR, &fcst,
+ &other.fcst);
+ }
+
+ void neg ()
+ {
+ if (!is_float)
+ cst = wi::neg (cst);
+ else
+ fcst = real_value_negate (&fcst);
+ }
+
+ bool is_one ()
+ {
+ if (!is_float)
+ return cst == wi::one (prec);
+ else
+ return real_equal (&fcst, &dconst1);
+ }
+
+ bool is_m1 ()
+ {
+ if (!is_float)
+ return cst == wi::minus_one (prec);
+ else
+ return real_equal (&fcst, &dconstm1);
+ }
+
+ bool maybe_expensive ()
+ {
+ if (!is_float)
+ return constant_maybe_expensive (cst);
+ else
+ return constant_maybe_expensive (fcst);
+ }
+
+ tree to_tree ()
+ {
+ if (!is_float)
+ return wide_int_to_tree (type, cst);
+ else
+ {
+ REAL_VALUE_TYPE r;
+ real_convert (&r, TYPE_MODE (type), &fcst);
+ return build_real (type, r);
+ }
+ }
+
+ mult_factor (tree t)
+ {
+ type = TREE_TYPE (t);
+ prec = TYPE_PRECISION (type);
+ if (INTEGRAL_TYPE_P (type))
+ {
+ is_float = false;
+ cst = wi::to_wide (t);
+ fcst = dconst0;
+ }
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ is_float = true;
+ fcst = TREE_REAL_CST (t);
+ }
+ else
+ gcc_unreachable ();
+ }
+
+ mult_factor ()
+ : fcst (dconst0), prec (0), type (NULL_TREE), is_float (false) {}
+};
+
struct plus_mult_tree_state
{
/* Stats for costing. */
@@ -1888,21 +2030,21 @@ struct plus_mult_tree_state
/* Operands of the cst/plus/mult sequence in program order. */
auto_vec<tree> ops;
/* Maps SSA names to their multiplicative factors. */
- hash_map<tree, wide_int> op_factor_map;
+ hash_map<tree, mult_factor> op_factor_map;
/* Constant factor without SSA name. */
- wide_int cst;
+ mult_factor cst;
/* Visited statements. */
auto_vec<gimple *> visited;
- plus_mult_tree_state (HOST_WIDE_INT prec)
+ plus_mult_tree_state (tree type)
: mults_before (0), mults_after (0),
plus_before (0), plus_after (0),
maybe_expensive_constants_before (0),
maybe_expensive_constants_after (0),
changed (false),
- cst (wi::zero (prec)) {}
+ cst (build_zero_cst (type)) {}
};
/* Recursively walk a tree of additions, products, as well as constants
@@ -1916,19 +2058,18 @@ struct plus_mult_tree_state
of is passed in LOOP. */
static void
-linearize_plus_mult_tree (tree op, wide_int factor,
+linearize_plus_mult_tree (tree op, mult_factor factor,
struct plus_mult_tree_state *state,
class loop *loop)
{
/* Add constants to the "global" constant. */
- if (TREE_CODE (op) == INTEGER_CST)
+ if (TREE_CODE (op) == INTEGER_CST || TREE_CODE (op) == REAL_CST)
{
- wide_int wcst = wi::to_wide (op);
- if (constant_maybe_expensive (wcst))
+ if (constant_maybe_expensive (op))
state->maybe_expensive_constants_before++;
- state->cst += wi::mul (wcst, factor);
- if (state->cst != wi::zero (state->cst.get_precision ())
- || factor != wi::one (state->cst.get_precision ()))
+ factor.mul (op);
+ state->cst.plus (factor);
+ if (!state->cst.is_zero () || !factor.is_one ())
state->changed = true;
return;
}
@@ -1937,7 +2078,9 @@ linearize_plus_mult_tree (tree op, wide_int factor,
if (TREE_CODE (op) == SSA_NAME
&& can_reassociate_op_p (op)
&& has_single_use (op)
- && TYPE_OVERFLOW_WRAPS (TREE_TYPE (op)))
+ && ((INTEGRAL_TYPE_P (TREE_TYPE (op))
+ && TYPE_OVERFLOW_WRAPS (TREE_TYPE (op)))
+ || SCALAR_FLOAT_TYPE_P (TREE_TYPE (op))))
{
gimple *stmt = SSA_NAME_DEF_STMT (op);
basic_block bb;
@@ -1953,13 +2096,14 @@ linearize_plus_mult_tree (tree op, wide_int factor,
if (can_reassociate_op_p (rhs1)
&& (!rhs2 || can_reassociate_op_p (rhs2)))
{
- if (opcode == MULT_EXPR && TREE_CODE (rhs2) == INTEGER_CST)
+ if (opcode == MULT_EXPR
+ && (TREE_CODE (rhs2) == INTEGER_CST
+ || TREE_CODE (rhs2) == REAL_CST))
{
state->mults_before++;
state->visited.safe_push (stmt);
- wide_int wcst = wi::to_wide (rhs2);
- linearize_plus_mult_tree (rhs1, wi::mul (wcst, factor),
- state, loop);
+ factor.mul (rhs2);
+ linearize_plus_mult_tree (rhs1, factor, state, loop);
return;
}
else if (opcode == PLUS_EXPR)
@@ -1973,10 +2117,8 @@ linearize_plus_mult_tree (tree op, wide_int factor,
else if (opcode == NEGATE_EXPR)
{
state->visited.safe_push (stmt);
- wide_int negated
- = wi::mul (wi::minus_one (state->cst.get_precision ()),
- factor);
- linearize_plus_mult_tree (rhs1, negated, state, loop);
+ factor.neg ();
+ linearize_plus_mult_tree (rhs1, factor, state, loop);
return;
}
}
@@ -1986,8 +2128,12 @@ linearize_plus_mult_tree (tree op, wide_int factor,
/* We have a leaf. If we have seen it before, adjust its factor.
Otherwise, add it to the cache. */
bool existed;
- wide_int &slot = state->op_factor_map.get_or_insert (op, &existed);
- slot = existed ? slot + factor : factor;
+ mult_factor &slot = state->op_factor_map.get_or_insert (op, &existed);
+ if (existed)
+ slot.plus (factor);
+ else
+ slot = factor;
+
if (!existed)
state->ops.safe_push (op);
else
@@ -2006,7 +2152,6 @@ expand_plus_mult_tree (gimple *stmt, plus_mult_tree_state
*state)
tree old_lhs = gimple_get_lhs (stmt);
tree type = TREE_TYPE (old_lhs);
- wide_int zero = wi::zero (state->cst.get_precision ());
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
location_t loc = gimple_location (stmt);
@@ -2015,10 +2160,12 @@ expand_plus_mult_tree (gimple *stmt,
plus_mult_tree_state *state)
auto_vec<tree> sum_factors;
for (tree op : state->ops)
{
- wide_int factor = *state->op_factor_map.get (op);
- if (factor == zero)
+ mult_factor &factor = *state->op_factor_map.get (op);
+
+ if (factor.is_zero ())
continue;
- if (factor == wi::minus_one (factor.get_precision ()))
+
+ if (factor.is_m1 ())
{
tree nlhs = make_ssa_name (type);
gimple *neg = gimple_build_assign (nlhs, NEGATE_EXPR, op);
@@ -2028,9 +2175,9 @@ expand_plus_mult_tree (gimple *stmt, plus_mult_tree_state
*state)
gimple_set_location (neg, loc);
sum_factors.safe_push (gimple_get_lhs (neg));
}
- else if (factor != wi::one (factor.get_precision ()))
+ else if (!factor.is_one ())
{
- tree cst = wide_int_to_tree (type, factor);
+ tree cst = factor.to_tree ();
tree nlhs = make_ssa_name (type);
gimple *prod = gimple_build_assign (nlhs, MULT_EXPR, op, cst);
gsi_insert_before (&gsi, prod, GSI_SAME_STMT);
@@ -2044,9 +2191,9 @@ expand_plus_mult_tree (gimple *stmt, plus_mult_tree_state
*state)
}
/* Include the constant factor if there is one. */
- if (state->cst != zero)
+ if (!state->cst.is_zero ())
{
- tree tcst = wide_int_to_tree (type, state->cst);
+ tree tcst = state->cst.to_tree ();
sum_factors.safe_push (tcst);
}
@@ -2054,7 +2201,7 @@ expand_plus_mult_tree (gimple *stmt, plus_mult_tree_state
*state)
/* Nothing to be done, zero the old LHS. */
if (!n)
{
- gimple_assign_set_rhs_from_tree (&gsi, wide_int_to_tree (type, zero));
+ gimple_assign_set_rhs_from_tree (&gsi, build_zero_cst (type));
update_stmt (stmt);
}
/* If we only have one factor, just assign it to the old LHS. */
@@ -2115,21 +2262,22 @@ gather_plus_mult_tree_stats (struct
plus_mult_tree_state *state)
gcc_checking_assert (state->plus_after == 0);
gcc_checking_assert (state->mults_after == 0);
- HOST_WIDE_INT prec = state->cst.get_precision ();
- if (constant_maybe_expensive (state->cst))
+ if (state->cst.maybe_expensive ())
state->maybe_expensive_constants_after = 1;
+
for (auto it : state->op_factor_map)
{
- if (constant_maybe_expensive (it.second))
+ if (it.second.maybe_expensive ())
state->maybe_expensive_constants_after++;
- if (it.second != wi::zero (prec)
- && it.second != wi::one (prec)
- && it.second != wi::minus_one (prec))
+ if (!it.second.is_zero ()
+ && !it.second.is_one ()
+ && !it.second.is_m1 ())
state->mults_after++;
- if (it.second != wi::zero (prec))
+ if (!it.second.is_zero ())
state->plus_after++;
}
- if (state->cst != wi::zero (prec))
+
+ if (!state->cst.is_zero ())
state->plus_after++;
state->plus_after--;
}
@@ -2172,14 +2320,19 @@ static bool
rewrite_plus_mult_tree (gimple *stmt)
{
tree lhs = gimple_get_lhs (stmt);
- gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ gcc_checking_assert ((INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (lhs))
+ && !HONOR_NANS (TREE_TYPE (lhs))
+ && !HONOR_SIGNED_ZEROS (TREE_TYPE (lhs))))
&& has_single_use (lhs));
- HOST_WIDE_INT prec = TYPE_PRECISION (TREE_TYPE (lhs));
- plus_mult_tree_state state (prec);
+ tree type = TREE_TYPE (lhs);
+ plus_mult_tree_state state (type);
+
+ mult_factor one (build_one_cst (type));
/* Linearize the tree and gather stats about it. */
- linearize_plus_mult_tree (lhs, wi::one (prec), &state,
+ linearize_plus_mult_tree (lhs, one, &state,
loop_containing_stmt (stmt));
if (!state.changed)
return false;
@@ -7506,7 +7659,10 @@ reassociate_bb (basic_block bb)
sum = cst + cst1 * A + cst2 * B + ...
do so. While at it, remove 0-factor elements. */
if ((rhs_code == PLUS_EXPR || rhs_code == MULT_EXPR)
- && INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (lhs))
+ && !HONOR_NANS (TREE_TYPE (lhs))
+ && !HONOR_SIGNED_ZEROS (TREE_TYPE (lhs))))
&& has_single_use (lhs)
&& !type_can_overflow)
{
--
2.54.0