From: Robin Dapp <[email protected]>
Similar to float handling, this patch now adds vector handling. As the
wrapper is already there, all we need to do is add a few vector special
cases to it.
gcc/ChangeLog:
* tree-ssa-reassoc.cc (constant_maybe_expensive): Add vector
handling.
(struct mult_factor): Add is_vector and vector handling to
constructor and tree building.
(linearize_plus_mult_tree): Allow vectors.
(rewrite_plus_mult_tree): Likewise.
(reassociate_bb): Likewise.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/reassoc-56.c: New test.
* gcc.dg/tree-ssa/reassoc-57.c: New test.
---
gcc/testsuite/gcc.dg/tree-ssa/reassoc-56.c | 53 ++++++++++
gcc/testsuite/gcc.dg/tree-ssa/reassoc-57.c | 53 ++++++++++
gcc/tree-ssa-reassoc.cc | 107 +++++++++++++++------
3 files changed, 186 insertions(+), 27 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-56.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-57.c
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-56.c
b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-56.c
new file mode 100644
index 00000000000..9d86aa7d5a9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-56.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* Signed and unsigned vector reassociation plus/mult-tree rewrite tests.
+ The signed tests are xfailed for now. */
+
+typedef unsigned int v4ui __attribute__((vector_size (4 * sizeof (unsigned
int))));
+typedef short v8si __attribute__((vector_size (8 * sizeof (short))));
+
+v4ui
+bar (v4ui fs)
+{
+ return 3u * (fs + 1u) + 4u * (fs + 2u);
+}
+
+v4ui
+foo1 (v4ui fs)
+{
+ return 2u * (3u * (fs + 1u) + 4u * (fs + 2u));
+}
+
+v4ui
+foo2 (v4ui fs)
+{
+ return 2u * (3u * (2u * (fs + 1u) + 2u * (fs + 2u)) + fs);
+}
+
+v4ui
+foo3 (v4ui fs)
+{
+ v4ui tmp = 3u * (fs + 1u);
+ return fs + 2u * (tmp + 4u) - 3u * (fs + 2u) + 5u + fs;
+}
+
+v8si
+foo (v8si fs)
+{
+ return 2 * (fs + 1) + 4 * (fs + 2);
+}
+
+v8si
+baz (v8si fs)
+{
+ return 16 * (fs + 1) + 64 * (fs + 2);
+}
+
+/* { dg-final { scan-tree-dump-times "\{ 7, 7, 7, 7 \}" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\{ 14, 14, 14, 14 \}" 1 "optimized" } }
*/
+/* { dg-final { scan-tree-dump-times "\{ 26, 26, 26, 26 \}" 1 "optimized" } }
*/
+/* { dg-final { scan-tree-dump-times "\{ 5, 5, 5, 5 \}" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\{ 6, 6, 6, 6, 6, 6, 6, 6 \}" 1
"optimized" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "\{ 80, 80, 80, 80, 80, 80, 80, 80 \}" 1
"optimized" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-57.c
b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-57.c
new file mode 100644
index 00000000000..2f280722ce6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-57.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-require-effective-target vect_double } */
+/* { dg-options "-O2 -ffast-math -fdump-tree-reassoc1-details" } */
+
+/* Float vector reassociation plus/mult-tree rewrite tests. */
+
+typedef float v4sf __attribute__((vector_size (4 * sizeof (float))));
+typedef double v2df __attribute__((vector_size (2 * sizeof (double))));
+
+v4sf
+bar (v4sf fs)
+{
+ return 3u * (fs + 1u) + 4u * (fs + 2u);
+}
+
+v4sf
+foo1 (v4sf fs)
+{
+ return 2u * (3u * (fs + 1u) + 4u * (fs + 2u));
+}
+
+v4sf
+foo2 (v4sf fs)
+{
+ return 2u * (3u * (2u * (fs + 1u) + 2u * (fs + 2u)) + fs);
+}
+
+v4sf
+foo3 (v4sf fs)
+{
+ v4sf tmp = 3u * (fs + 1u);
+ return fs + 2u * (tmp + 4u) - 3u * (fs + 2u) + 5u + fs;
+}
+
+v2df
+foo (v2df fs)
+{
+ return 2 * (fs + 1) + 4 * (fs + 2);
+}
+
+v2df
+baz (v2df fs)
+{
+ return 16 * (fs + 1) + 64 * (fs + 2);
+}
+
+/* { dg-final { scan-tree-dump-times "\{ 7\\.0e\\+0, 7\\.0e\\+0, 7\\.0e\\+0,
7\\.0e\\+0 \}" 1 "reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "\{ 1\\.4e\\+1, 1\\.4e\\+1, 1\\.4e\\+1,
1\\.4e\\+1 \}" 1 "reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "\{ 2\\.6e\\+1, 2\\.6e\\+1, 2\\.6e\\+1,
2\\.6e\\+1 \}" 1 "reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "\{ 5\\.0e\\+0, 5\\.0e\\+0, 5\\.0e\\+0,
5\\.0e\\+0 \}" 1 "reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "\{ 6\\.0e\\+0, 6\\.0e\\+0 \}" 1
"reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "\{ 8\\.0e\\+1, 8\\.0e\\+1 \}" 1
"reassoc1" } } */
diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc
index 440c6271e28..54a7be64e54 100644
--- a/gcc/tree-ssa-reassoc.cc
+++ b/gcc/tree-ssa-reassoc.cc
@@ -1860,13 +1860,14 @@ undistribute_ops_list (enum tree_code opcode,
/* Simplistic function to estimate whether a constant might be expensive to
materialize. */
static inline bool
-constant_maybe_expensive (wide_int cst)
+constant_maybe_expensive (wide_int cst, bool vector = false)
{
- return wi::gts_p (wi::abs (cst), 2048) && wi::popcount (cst) > 1;
+ return wi::gts_p (wi::abs (cst), !vector ? 2048: 64)
+ && wi::popcount (cst) > 1;
}
static inline bool
-constant_maybe_expensive (REAL_VALUE_TYPE)
+constant_maybe_expensive (REAL_VALUE_TYPE, bool = false)
{
return false;
}
@@ -1876,11 +1877,22 @@ 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));
+ || VECTOR_INTEGER_TYPE_P (type)
+ || FLOAT_TYPE_P (type));
+
+ bool vector_p = false;
+ if (VECTOR_TYPE_P (type))
+ {
+ t = uniform_vector_p (t);
+ vector_p = true;
+ }
+
+ if (INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
+ {
+ return constant_maybe_expensive (wi::to_wide (t), vector_p);
+ }
else
- return constant_maybe_expensive (TREE_REAL_CST (t));
+ return constant_maybe_expensive (TREE_REAL_CST (t), vector_p);
}
/* Helper to wrap operations for the constant multiplicative factors in
@@ -1892,7 +1904,9 @@ struct mult_factor
HOST_WIDE_INT prec;
tree type;
+
bool is_float;
+ bool is_vector;
bool is_zero ()
{
@@ -1905,8 +1919,15 @@ struct mult_factor
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)));
+ gcc_checking_assert ((!is_float
+ && (INTEGRAL_TYPE_P (other_type)
+ || VECTOR_INTEGER_TYPE_P (other_type)))
+ || (is_float && FLOAT_TYPE_P (other_type)));
+
+ gcc_checking_assert (VECTOR_TYPE_P (type) == VECTOR_TYPE_P (other_type));
+ if (VECTOR_TYPE_P (type))
+ other = uniform_vector_p (other);
+
if (!is_float)
cst = wi::mul (cst, wi::to_wide (other));
else
@@ -1917,6 +1938,7 @@ struct mult_factor
void mul (mult_factor &other)
{
gcc_checking_assert (is_float == other.is_float);
+ gcc_checking_assert (is_vector == other.is_vector);
if (!is_float)
cst = wi::mul (cst, other.cst);
else
@@ -1927,8 +1949,15 @@ struct mult_factor
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)));
+ gcc_checking_assert ((!is_float
+ && (INTEGRAL_TYPE_P (other_type)
+ || VECTOR_INTEGER_TYPE_P (other_type)))
+ || (is_float && FLOAT_TYPE_P (other_type)));
+
+ gcc_checking_assert (VECTOR_TYPE_P (type) == VECTOR_TYPE_P (other_type));
+ if (VECTOR_TYPE_P (type))
+ other = uniform_vector_p (other);
+
if (!is_float)
cst = wi::add (cst, wi::to_wide (other));
else
@@ -1939,6 +1968,7 @@ struct mult_factor
void plus (mult_factor &other)
{
gcc_checking_assert (is_float == other.is_float);
+ gcc_checking_assert (is_vector == other.is_vector);
if (!is_float)
cst = wi::add (cst, other.cst);
else
@@ -1980,27 +2010,41 @@ struct mult_factor
tree to_tree ()
{
+ tree scalar_type = is_vector ? TREE_TYPE (type) : type;
+ tree el;
if (!is_float)
- return wide_int_to_tree (type, cst);
+ el = wide_int_to_tree (scalar_type, cst);
else
{
REAL_VALUE_TYPE r;
- real_convert (&r, TYPE_MODE (type), &fcst);
- return build_real (type, r);
+ real_convert (&r, TYPE_MODE (scalar_type), &fcst);
+ el = build_real (scalar_type, r);
}
+
+ if (is_vector)
+ return build_vector_from_val (type, el);
+ else
+ return el;
}
mult_factor (tree t)
{
type = TREE_TYPE (t);
- prec = TYPE_PRECISION (type);
- if (INTEGRAL_TYPE_P (type))
+ is_vector = false;
+ if (VECTOR_TYPE_P (type))
+ {
+ is_vector = true;
+ t = uniform_vector_p (t);
+ }
+ prec = TYPE_PRECISION (TREE_TYPE (t));
+ if (INTEGRAL_TYPE_P (type)
+ || VECTOR_INTEGER_TYPE_P (type))
{
is_float = false;
cst = wi::to_wide (t);
fcst = dconst0;
}
- else if (SCALAR_FLOAT_TYPE_P (type))
+ else if (FLOAT_TYPE_P (type))
{
is_float = true;
fcst = TREE_REAL_CST (t);
@@ -2010,7 +2054,8 @@ struct mult_factor
}
mult_factor ()
- : fcst (dconst0), prec (0), type (NULL_TREE), is_float (false) {}
+ : fcst (dconst0), prec (0), type (NULL_TREE),
+ is_float (false), is_vector (false) {}
};
struct plus_mult_tree_state
@@ -2063,7 +2108,10 @@ linearize_plus_mult_tree (tree op, mult_factor factor,
class loop *loop)
{
/* Add constants to the "global" constant. */
- if (TREE_CODE (op) == INTEGER_CST || TREE_CODE (op) == REAL_CST)
+ if (TREE_CODE (op) == INTEGER_CST || TREE_CODE (op) == REAL_CST
+ || (TREE_CODE (op) == VECTOR_CST
+ && VECTOR_CST_NELTS (op).is_constant ()
+ && uniform_vector_p (op)))
{
if (constant_maybe_expensive (op))
state->maybe_expensive_constants_before++;
@@ -2078,9 +2126,10 @@ linearize_plus_mult_tree (tree op, mult_factor factor,
if (TREE_CODE (op) == SSA_NAME
&& can_reassociate_op_p (op)
&& has_single_use (op)
- && ((INTEGRAL_TYPE_P (TREE_TYPE (op))
+ && (((INTEGRAL_TYPE_P (TREE_TYPE (op))
+ || VECTOR_INTEGER_TYPE_P (TREE_TYPE (op)))
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (op)))
- || SCALAR_FLOAT_TYPE_P (TREE_TYPE (op))))
+ || FLOAT_TYPE_P (TREE_TYPE (op))))
{
gimple *stmt = SSA_NAME_DEF_STMT (op);
basic_block bb;
@@ -2098,7 +2147,10 @@ linearize_plus_mult_tree (tree op, mult_factor factor,
{
if (opcode == MULT_EXPR
&& (TREE_CODE (rhs2) == INTEGER_CST
- || TREE_CODE (rhs2) == REAL_CST))
+ || TREE_CODE (rhs2) == REAL_CST
+ || (TREE_CODE (rhs2) == VECTOR_CST
+ && VECTOR_CST_NELTS (rhs2).is_constant ()
+ && uniform_vector_p (rhs2))))
{
state->mults_before++;
state->visited.safe_push (stmt);
@@ -2320,15 +2372,15 @@ static bool
rewrite_plus_mult_tree (gimple *stmt)
{
tree lhs = gimple_get_lhs (stmt);
- gcc_checking_assert ((INTEGRAL_TYPE_P (TREE_TYPE (lhs))
- || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (lhs))
+ gcc_checking_assert (((INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ || VECTOR_INTEGER_TYPE_P (TREE_TYPE (lhs)))
+ || (FLOAT_TYPE_P (TREE_TYPE (lhs))
&& !HONOR_NANS (TREE_TYPE (lhs))
&& !HONOR_SIGNED_ZEROS (TREE_TYPE (lhs))))
&& has_single_use (lhs));
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. */
@@ -7624,7 +7676,7 @@ reassociate_bb (basic_block bb)
rhs2 = gimple_assign_rhs2 (stmt);
tree type = TREE_TYPE (rhs1);
- bool type_can_overflow = INTEGRAL_TYPE_P (type)
+ bool type_can_overflow = ANY_INTEGRAL_TYPE_P (type)
&& TYPE_OVERFLOW_UNDEFINED (type);
bool operation_can_overflow = rhs_code != BIT_IOR_EXPR
@@ -7660,7 +7712,8 @@ reassociate_bb (basic_block bb)
do so. While at it, remove 0-factor elements. */
if ((rhs_code == PLUS_EXPR || rhs_code == MULT_EXPR)
&& (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
- || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (lhs))
+ || VECTOR_INTEGER_TYPE_P (TREE_TYPE (lhs))
+ || (FLOAT_TYPE_P (TREE_TYPE (lhs))
&& !HONOR_NANS (TREE_TYPE (lhs))
&& !HONOR_SIGNED_ZEROS (TREE_TYPE (lhs))))
&& has_single_use (lhs)
--
2.54.0