diff options
author | Richard Sandiford <richard.sandiford@linaro.org> | 2018-01-02 18:27:15 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2018-01-02 18:27:15 +0000 |
commit | 1a1c441dbe5933ebf9180831236aa5be7d70a434 (patch) | |
tree | 1666d763225f1b16cafb34b101ec4e31817f8679 /gcc/fold-const.c | |
parent | d980067b1e9394b2b8482b3fc888ac5e8e3ebe59 (diff) | |
download | gcc-1a1c441dbe5933ebf9180831236aa5be7d70a434.zip gcc-1a1c441dbe5933ebf9180831236aa5be7d70a434.tar.gz gcc-1a1c441dbe5933ebf9180831236aa5be7d70a434.tar.bz2 |
Rework VEC_PERM_EXPR folding
This patch reworks the VEC_PERM_EXPR folding so that more of it
works for variable-length vectors. E.g. it means that we can
now recognise variable-length permutes that reduce to a single
vector, or cases in which a variable-length permute only needs
one input. There should be no functional change for fixed-length
vectors.
2018-01-02 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
* selftest.h (selftest::vec_perm_indices_c_tests): Declare.
* selftest-run-tests.c (selftest::run_tests): Call it.
* vector-builder.h (vector_builder::operator ==): New function.
(vector_builder::operator !=): Likewise.
* vec-perm-indices.h (vec_perm_indices::series_p): Declare.
(vec_perm_indices::all_from_input_p): New function.
* vec-perm-indices.c (vec_perm_indices::series_p): Likewise.
(test_vec_perm_12, selftest::vec_perm_indices_c_tests): Likewise.
* fold-const.c (fold_ternary_loc): Use tree_to_vec_perm_builder
instead of reading the VECTOR_CST directly. Detect whether both
vector inputs are the same before constructing the vec_perm_indices,
and update the number of inputs argument accordingly. Use the
utility functions added above. Only construct sel2 if we need to.
From-SVN: r256098
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 118 |
1 files changed, 42 insertions, 76 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index ca0d8fd..f28970b 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -11705,99 +11705,65 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, case VEC_PERM_EXPR: if (TREE_CODE (arg2) == VECTOR_CST) { - unsigned int nelts = VECTOR_CST_NELTS (arg2), i, mask, mask2; - bool need_mask_canon = false; - bool need_mask_canon2 = false; - bool all_in_vec0 = true; - bool all_in_vec1 = true; - bool maybe_identity = true; - bool single_arg = (op0 == op1); - bool changed = false; - - mask2 = 2 * nelts - 1; - mask = single_arg ? (nelts - 1) : mask2; - gcc_assert (nelts == TYPE_VECTOR_SUBPARTS (type)); - vec_perm_builder sel (nelts, nelts, 1); - vec_perm_builder sel2 (nelts, nelts, 1); - for (i = 0; i < nelts; i++) - { - tree val = VECTOR_CST_ELT (arg2, i); - if (TREE_CODE (val) != INTEGER_CST) - return NULL_TREE; - - /* Make sure that the perm value is in an acceptable - range. */ - wi::tree_to_wide_ref t = wi::to_wide (val); - need_mask_canon |= wi::gtu_p (t, mask); - need_mask_canon2 |= wi::gtu_p (t, mask2); - unsigned int elt = t.to_uhwi () & mask; - unsigned int elt2 = t.to_uhwi () & mask2; - - if (elt < nelts) - all_in_vec1 = false; - else - all_in_vec0 = false; - - if ((elt & (nelts - 1)) != i) - maybe_identity = false; + /* Build a vector of integers from the tree mask. */ + vec_perm_builder builder; + if (!tree_to_vec_perm_builder (&builder, arg2)) + return NULL_TREE; - sel.quick_push (elt); - sel2.quick_push (elt2); - } + /* Create a vec_perm_indices for the integer vector. */ + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type); + bool single_arg = (op0 == op1); + vec_perm_indices sel (builder, single_arg ? 1 : 2, nelts); - if (maybe_identity) - { - if (all_in_vec0) - return op0; - if (all_in_vec1) - return op1; - } + /* Check for cases that fold to OP0 or OP1 in their original + element order. */ + if (sel.series_p (0, 1, 0, 1)) + return op0; + if (sel.series_p (0, 1, nelts, 1)) + return op1; - if (all_in_vec0) - op1 = op0; - else if (all_in_vec1) + if (!single_arg) { - op0 = op1; - for (i = 0; i < nelts; i++) - sel[i] -= nelts; - need_mask_canon = true; + if (sel.all_from_input_p (0)) + op1 = op0; + else if (sel.all_from_input_p (1)) + { + op0 = op1; + sel.rotate_inputs (1); + } } - vec_perm_indices indices (sel, 2, nelts); if ((TREE_CODE (op0) == VECTOR_CST || TREE_CODE (op0) == CONSTRUCTOR) && (TREE_CODE (op1) == VECTOR_CST || TREE_CODE (op1) == CONSTRUCTOR)) { - tree t = fold_vec_perm (type, op0, op1, indices); + tree t = fold_vec_perm (type, op0, op1, sel); if (t != NULL_TREE) return t; } - if (op0 == op1 && !single_arg) - changed = true; - - /* Some targets are deficient and fail to expand a single - argument permutation while still allowing an equivalent - 2-argument version. */ - if (need_mask_canon && arg2 == op2 - && !can_vec_perm_const_p (TYPE_MODE (type), indices, false) - && can_vec_perm_const_p (TYPE_MODE (type), - vec_perm_indices (sel2, 2, nelts), - false)) - { - need_mask_canon = need_mask_canon2; - sel.truncate (0); - sel.splice (sel2); - } + bool changed = (op0 == op1 && !single_arg); - if (need_mask_canon && arg2 == op2) + /* Generate a canonical form of the selector. */ + if (arg2 == op2 && sel.encoding () != builder) { - tree eltype = TREE_TYPE (TREE_TYPE (arg2)); - tree_vector_builder tsel (TREE_TYPE (arg2), nelts, 1); - for (i = 0; i < nelts; i++) - tsel.quick_push (build_int_cst (eltype, sel[i])); - op2 = tsel.build (); + /* Some targets are deficient and fail to expand a single + argument permutation while still allowing an equivalent + 2-argument version. */ + if (sel.ninputs () == 2 + || can_vec_perm_const_p (TYPE_MODE (type), sel, false)) + op2 = vec_perm_indices_to_tree (TREE_TYPE (arg2), sel); + else + { + vec_perm_indices sel2 (builder, 2, nelts); + if (can_vec_perm_const_p (TYPE_MODE (type), sel2, false)) + op2 = vec_perm_indices_to_tree (TREE_TYPE (arg2), sel2); + else + /* Not directly supported with either encoding, + so use the preferred form. */ + op2 = vec_perm_indices_to_tree (TREE_TYPE (arg2), sel); + } changed = true; } |