Commit b3def403 by Richard Sandiford Committed by Richard Sandiford

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  <richard.sandiford@linaro.org>

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
parent 059c18ab
2017-12-07 Richard Sandiford <richard.sandiford@linaro.org> 2017-12-07 Richard Sandiford <richard.sandiford@linaro.org>
* 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 <richard.sandiford@linaro.org>
* fold-const.c (fold_negate_expr_1): Use tree_vector_builder and * fold-const.c (fold_negate_expr_1): Use tree_vector_builder and
new_unary_operation, operating only on the encoded elements. new_unary_operation, operating only on the encoded elements.
(const_unop): Likewise. (const_unop): Likewise.
...@@ -1435,13 +1435,40 @@ const_binop (enum tree_code code, tree arg1, tree arg2) ...@@ -1435,13 +1435,40 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
} }
if (TREE_CODE (arg1) == VECTOR_CST 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); tree type = TREE_TYPE (arg1);
int count = VECTOR_CST_NELTS (arg1), i; bool step_ok_p;
if (VECTOR_CST_STEPPED_P (arg1)
auto_vec<tree, 32> elts (count); && VECTOR_CST_STEPPED_P (arg2))
for (i = 0; i < count; i++) /* 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 elem1 = VECTOR_CST_ELT (arg1, i);
tree elem2 = VECTOR_CST_ELT (arg2, i); tree elem2 = VECTOR_CST_ELT (arg2, i);
...@@ -1455,7 +1482,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2) ...@@ -1455,7 +1482,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
elts.quick_push (elt); elts.quick_push (elt);
} }
return build_vector (type, elts); return elts.build ();
} }
/* Shifts allow a scalar offset for a vector. */ /* 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) ...@@ -13770,11 +13797,10 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
} }
return constant_boolean_node (true, type); return constant_boolean_node (true, type);
} }
unsigned count = VECTOR_CST_NELTS (op0); tree_vector_builder elts;
gcc_assert (VECTOR_CST_NELTS (op1) == count if (!elts.new_binary_operation (type, op0, op1, false))
&& TYPE_VECTOR_SUBPARTS (type) == count); return NULL_TREE;
unsigned int count = elts.encoded_nelts ();
auto_vec<tree, 32> elts (count);
for (unsigned i = 0; i < count; i++) for (unsigned i = 0; i < count; i++)
{ {
tree elem_type = TREE_TYPE (type); tree elem_type = TREE_TYPE (type);
...@@ -13791,7 +13817,7 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1) ...@@ -13791,7 +13817,7 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
integer_zerop (tem) ? 0 : -1)); 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. /* From here on we only handle LT, LE, GT, GE, EQ and NE.
......
...@@ -49,6 +49,53 @@ tree_vector_builder::new_unary_operation (tree type, tree t, ...@@ -49,6 +49,53 @@ tree_vector_builder::new_unary_operation (tree type, tree t,
return true; 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. */ /* Return a VECTOR_CST for the current constant. */
tree tree
......
...@@ -38,6 +38,7 @@ public: ...@@ -38,6 +38,7 @@ public:
void new_vector (tree, unsigned int, unsigned int); void new_vector (tree, unsigned int, unsigned int);
bool new_unary_operation (tree, tree, bool); bool new_unary_operation (tree, tree, bool);
bool new_binary_operation (tree, tree, tree, bool);
private: private:
bool equal_p (const_tree, const_tree) const; bool equal_p (const_tree, const_tree) const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment