aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@linaro.org>2018-01-02 18:27:15 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2018-01-02 18:27:15 +0000
commit1a1c441dbe5933ebf9180831236aa5be7d70a434 (patch)
tree1666d763225f1b16cafb34b101ec4e31817f8679 /gcc/fold-const.c
parentd980067b1e9394b2b8482b3fc888ac5e8e3ebe59 (diff)
downloadgcc-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.c118
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;
}