From: Richard Sandiford Date: Thu, 7 Dec 2017 18:41:35 +0000 (+0000) Subject: Use tree_vector_builder::new_binary_operation for folding X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b3def403fa7ae89679468b8f986cab7361c1034d;p=gcc.git Use tree_vector_builder::new_binary_operation for folding This patch makes fold-const.c operate directly on the VECTOR_CST encoding when folding an operation that has two VECTOR_CST inputs. 2017-12-07 Richard Sandiford gcc/ * tree-vector-builder.h (tree_vector_builder::new_binary_operation): Declare. * tree-vector-builder.c (tree_vector_builder::new_binary_operation): New function. * fold-const.c (fold_relational_const): Use it. (const_binop): Likewise. Check that both input vectors have the same number of elements, thus excluding things like WIDEN_SUM. Check whether it is possible to operate directly on the encodings of stepped inputs. From-SVN: r255477 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c541ad72c08..6fb51605354 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2017-12-07 Richard Sandiford + + * tree-vector-builder.h + (tree_vector_builder::new_binary_operation): Declare. + * tree-vector-builder.c + (tree_vector_builder::new_binary_operation): New function. + * fold-const.c (fold_relational_const): Use it. + (const_binop): Likewise. Check that both input vectors have + the same number of elements, thus excluding things like WIDEN_SUM. + Check whether it is possible to operate directly on the encodings + of stepped inputs. + 2017-12-07 Richard Sandiford * fold-const.c (fold_negate_expr_1): Use tree_vector_builder and diff --git a/gcc/fold-const.c b/gcc/fold-const.c index af1f426300b..1b098d9f4c9 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -1435,13 +1435,40 @@ const_binop (enum tree_code code, tree arg1, tree arg2) } if (TREE_CODE (arg1) == VECTOR_CST - && TREE_CODE (arg2) == VECTOR_CST) + && TREE_CODE (arg2) == VECTOR_CST + && (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)) + == TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg2)))) { tree type = TREE_TYPE (arg1); - int count = VECTOR_CST_NELTS (arg1), i; - - auto_vec elts (count); - for (i = 0; i < count; i++) + bool step_ok_p; + if (VECTOR_CST_STEPPED_P (arg1) + && VECTOR_CST_STEPPED_P (arg2)) + /* We can operate directly on the encoding if: + + a3 - a2 == a2 - a1 && b3 - b2 == b2 - b1 + implies + (a3 op b3) - (a2 op b2) == (a2 op b2) - (a1 op b1) + + Addition and subtraction are the supported operators + for which this is true. */ + step_ok_p = (code == PLUS_EXPR || code == MINUS_EXPR); + else if (VECTOR_CST_STEPPED_P (arg1)) + /* We can operate directly on stepped encodings if: + + a3 - a2 == a2 - a1 + implies: + (a3 op c) - (a2 op c) == (a2 op c) - (a1 op c) + + which is true if (x -> x op c) distributes over addition. */ + step_ok_p = distributes_over_addition_p (code, 1); + else + /* Similarly in reverse. */ + step_ok_p = distributes_over_addition_p (code, 2); + tree_vector_builder elts; + if (!elts.new_binary_operation (type, arg1, arg2, step_ok_p)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) { tree elem1 = VECTOR_CST_ELT (arg1, i); tree elem2 = VECTOR_CST_ELT (arg2, i); @@ -1455,7 +1482,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2) elts.quick_push (elt); } - return build_vector (type, elts); + return elts.build (); } /* Shifts allow a scalar offset for a vector. */ @@ -13770,11 +13797,10 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1) } return constant_boolean_node (true, type); } - unsigned count = VECTOR_CST_NELTS (op0); - gcc_assert (VECTOR_CST_NELTS (op1) == count - && TYPE_VECTOR_SUBPARTS (type) == count); - - auto_vec elts (count); + tree_vector_builder elts; + if (!elts.new_binary_operation (type, op0, op1, false)) + return NULL_TREE; + unsigned int count = elts.encoded_nelts (); for (unsigned i = 0; i < count; i++) { tree elem_type = TREE_TYPE (type); @@ -13791,7 +13817,7 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1) integer_zerop (tem) ? 0 : -1)); } - return build_vector (type, elts); + return elts.build (); } /* From here on we only handle LT, LE, GT, GE, EQ and NE. diff --git a/gcc/tree-vector-builder.c b/gcc/tree-vector-builder.c index 708bf0e1a05..a8a98970f37 100644 --- a/gcc/tree-vector-builder.c +++ b/gcc/tree-vector-builder.c @@ -49,6 +49,53 @@ tree_vector_builder::new_unary_operation (tree type, tree t, return true; } +/* Try to start building a new vector of type TYPE that holds the result of + a binary operation on VECTOR_CSTs T1 and T2. ALLOW_STEPPED_P is true if + the operation can handle stepped encodings directly, without having to + expand the full sequence. + + Return true if the operation is possible. Leave the builder unchanged + otherwise. */ + +bool +tree_vector_builder::new_binary_operation (tree type, tree t1, tree t2, + bool allow_stepped_p) +{ + unsigned int full_nelts = TYPE_VECTOR_SUBPARTS (type); + gcc_assert (full_nelts == TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1)) + && full_nelts == TYPE_VECTOR_SUBPARTS (TREE_TYPE (t2))); + /* Conceptually we split the patterns in T1 and T2 until we have + an equal number for both. Each split pattern requires the same + number of elements per pattern as the original. E.g. splitting: + + { 1, 2, 3, ... } + + into two gives: + + { 1, 3, 5, ... } + { 2, 4, 6, ... } + + while splitting: + + { 1, 0, ... } + + into two gives: + + { 1, 0, ... } + { 0, 0, ... }. */ + unsigned int npatterns = least_common_multiple (VECTOR_CST_NPATTERNS (t1), + VECTOR_CST_NPATTERNS (t2)); + unsigned int nelts_per_pattern = MAX (VECTOR_CST_NELTS_PER_PATTERN (t1), + VECTOR_CST_NELTS_PER_PATTERN (t2)); + if (!allow_stepped_p && nelts_per_pattern > 2) + { + npatterns = full_nelts; + nelts_per_pattern = 1; + } + new_vector (type, npatterns, nelts_per_pattern); + return true; +} + /* Return a VECTOR_CST for the current constant. */ tree diff --git a/gcc/tree-vector-builder.h b/gcc/tree-vector-builder.h index b7b56259b8c..b89d3ab3af6 100644 --- a/gcc/tree-vector-builder.h +++ b/gcc/tree-vector-builder.h @@ -38,6 +38,7 @@ public: void new_vector (tree, unsigned int, unsigned int); bool new_unary_operation (tree, tree, bool); + bool new_binary_operation (tree, tree, tree, bool); private: bool equal_p (const_tree, const_tree) const;