[PATCH 4/5] reassoc: Rewrite vector plus/mult trees.
Robin Dapp <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
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