+2019-07-29 Richard Sandiford <richard.sandiford@arm.com>
+
+ * vector-builder.h (vector_builder): Add a shape template parameter.
+ (vector_builder::new_unary_operation): New function, generalizing
+ the old tree_vector_builder function.
+ (vector_builder::new_binary_operation): Likewise.
+ (vector_builder::binary_encoded_nelts): Likewise.
+ * int-vector-builder.h (int_vector_builder): Update template
+ parameters to vector_builder.
+ (int_vector_builder::shape_nelts): New function.
+ * rtx-vector-builder.h (rtx_vector_builder): Update template
+ parameters to vector_builder.
+ (rtx_vector_builder::shape_nelts): New function.
+ (rtx_vector_builder::nelts_of): Likewise.
+ (rtx_vector_builder::npatterns_of): Likewise.
+ (rtx_vector_builder::nelts_per_pattern_of): Likewise.
+ * tree-vector-builder.h (tree_vector_builder): Update template
+ parameters to vector_builder.
+ (tree_vector_builder::shape_nelts): New function.
+ (tree_vector_builder::nelts_of): Likewise.
+ (tree_vector_builder::npatterns_of): Likewise.
+ (tree_vector_builder::nelts_per_pattern_of): Likewise.
+ * tree-vector-builder.c (tree_vector_builder::new_unary_operation)
+ (tree_vector_builder::new_binary_operation): Delete.
+ (tree_vector_builder::binary_encoded_nelts): Likewise.
+ * simplify-rtx.c: Include rtx-vector-builder.h.
+ (distributes_over_addition_p): New function.
+ (simplify_const_unary_operation)
+ (simplify_const_binary_operation): Generalize handling of vector
+ constants to include variable-length vectors.
+ (test_vector_ops_series): Add more tests.
+
2019-07-28 Jan Hubicka <hubicka@ucw.cz>
PR lto/91222
encoding as tree and rtx constants. See vector_builder for more
details. */
template<typename T>
-class int_vector_builder : public vector_builder<T, int_vector_builder<T> >
+class int_vector_builder : public vector_builder<T, poly_uint64,
+ int_vector_builder<T> >
{
- typedef vector_builder<T, int_vector_builder> parent;
- friend class vector_builder<T, int_vector_builder>;
+ typedef vector_builder<T, poly_uint64, int_vector_builder> parent;
+ friend class vector_builder<T, poly_uint64, int_vector_builder>;
public:
int_vector_builder () {}
T apply_step (T, unsigned int, T) const;
bool can_elide_p (T) const { return true; }
void note_representative (T *, T) {}
+
+ static poly_uint64 shape_nelts (poly_uint64 x) { return x; }
};
/* Create a new builder for a vector with FULL_NELTS elements.
/* This class is used to build VECTOR_CSTs from a sequence of elements.
See vector_builder for more details. */
-class rtx_vector_builder : public vector_builder<rtx, rtx_vector_builder>
+class rtx_vector_builder : public vector_builder<rtx, machine_mode,
+ rtx_vector_builder>
{
- typedef vector_builder<rtx, rtx_vector_builder> parent;
- friend class vector_builder<rtx, rtx_vector_builder>;
+ typedef vector_builder<rtx, machine_mode, rtx_vector_builder> parent;
+ friend class vector_builder<rtx, machine_mode, rtx_vector_builder>;
public:
rtx_vector_builder () : m_mode (VOIDmode) {}
bool can_elide_p (rtx) const { return true; }
void note_representative (rtx *, rtx) {}
+ static poly_uint64 shape_nelts (machine_mode mode)
+ { return GET_MODE_NUNITS (mode); }
+ static poly_uint64 nelts_of (const_rtx x)
+ { return CONST_VECTOR_NUNITS (x); }
+ static unsigned int npatterns_of (const_rtx x)
+ { return CONST_VECTOR_NPATTERNS (x); }
+ static unsigned int nelts_per_pattern_of (const_rtx x)
+ { return CONST_VECTOR_NELTS_PER_PATTERN (x); }
+
rtx find_cached_value ();
machine_mode m_mode;
#include "flags.h"
#include "selftest.h"
#include "selftest-rtl.h"
+#include "rtx-vector-builder.h"
/* Simplification and canonicalization of RTL. */
if (VECTOR_MODE_P (mode) && GET_CODE (op) == CONST_VECTOR)
{
- unsigned int n_elts;
- if (!CONST_VECTOR_NUNITS (op).is_constant (&n_elts))
- return NULL_RTX;
-
- machine_mode opmode = GET_MODE (op);
- gcc_assert (known_eq (GET_MODE_NUNITS (mode), n_elts));
- gcc_assert (known_eq (GET_MODE_NUNITS (opmode), n_elts));
+ gcc_assert (GET_MODE (op) == op_mode);
- rtvec v = rtvec_alloc (n_elts);
- unsigned int i;
+ rtx_vector_builder builder;
+ if (!builder.new_unary_operation (mode, op, false))
+ return 0;
- for (i = 0; i < n_elts; i++)
+ unsigned int count = builder.encoded_nelts ();
+ for (unsigned int i = 0; i < count; i++)
{
rtx x = simplify_unary_operation (code, GET_MODE_INNER (mode),
CONST_VECTOR_ELT (op, i),
- GET_MODE_INNER (opmode));
+ GET_MODE_INNER (op_mode));
if (!x || !valid_for_const_vector_p (mode, x))
return 0;
- RTVEC_ELT (v, i) = x;
+ builder.quick_push (x);
}
- return gen_rtx_CONST_VECTOR (mode, v);
+ return builder.build ();
}
/* The order of these tests is critical so that, for example, we don't
return 0;
}
+/* Return true if binary operation OP distributes over addition in operand
+ OPNO, with the other operand being held constant. OPNO counts from 1. */
+
+static bool
+distributes_over_addition_p (rtx_code op, int opno)
+{
+ switch (op)
+ {
+ case PLUS:
+ case MINUS:
+ case MULT:
+ return true;
+
+ case ASHIFT:
+ return opno == 1;
+
+ default:
+ return false;
+ }
+}
+
rtx
simplify_const_binary_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
&& GET_CODE (op0) == CONST_VECTOR
&& GET_CODE (op1) == CONST_VECTOR)
{
- unsigned int n_elts;
- if (!CONST_VECTOR_NUNITS (op0).is_constant (&n_elts))
- return NULL_RTX;
-
- gcc_assert (known_eq (n_elts, CONST_VECTOR_NUNITS (op1)));
- gcc_assert (known_eq (n_elts, GET_MODE_NUNITS (mode)));
- rtvec v = rtvec_alloc (n_elts);
- unsigned int i;
+ bool step_ok_p;
+ if (CONST_VECTOR_STEPPED_P (op0)
+ && CONST_VECTOR_STEPPED_P (op1))
+ /* 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 || code == MINUS);
+ else if (CONST_VECTOR_STEPPED_P (op0))
+ /* 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);
+ rtx_vector_builder builder;
+ if (!builder.new_binary_operation (mode, op0, op1, step_ok_p))
+ return 0;
- for (i = 0; i < n_elts; i++)
+ unsigned int count = builder.encoded_nelts ();
+ for (unsigned int i = 0; i < count; i++)
{
rtx x = simplify_binary_operation (code, GET_MODE_INNER (mode),
CONST_VECTOR_ELT (op0, i),
CONST_VECTOR_ELT (op1, i));
if (!x || !valid_for_const_vector_p (mode, x))
return 0;
- RTVEC_ELT (v, i) = x;
+ builder.quick_push (x);
}
-
- return gen_rtx_CONST_VECTOR (mode, v);
+ return builder.build ();
}
if (VECTOR_MODE_P (mode)
ASSERT_RTX_EQ (series_0_m1,
simplify_binary_operation (VEC_SERIES, mode, const0_rtx,
constm1_rtx));
+
+ /* Test NEG on constant vector series. */
+ ASSERT_RTX_EQ (series_0_m1,
+ simplify_unary_operation (NEG, mode, series_0_1, mode));
+ ASSERT_RTX_EQ (series_0_1,
+ simplify_unary_operation (NEG, mode, series_0_m1, mode));
+
+ /* Test PLUS and MINUS on constant vector series. */
+ rtx scalar2 = gen_int_mode (2, inner_mode);
+ rtx scalar3 = gen_int_mode (3, inner_mode);
+ rtx series_1_1 = gen_const_vec_series (mode, const1_rtx, const1_rtx);
+ rtx series_0_2 = gen_const_vec_series (mode, const0_rtx, scalar2);
+ rtx series_1_3 = gen_const_vec_series (mode, const1_rtx, scalar3);
+ ASSERT_RTX_EQ (series_1_1,
+ simplify_binary_operation (PLUS, mode, series_0_1,
+ CONST1_RTX (mode)));
+ ASSERT_RTX_EQ (series_0_m1,
+ simplify_binary_operation (PLUS, mode, CONST0_RTX (mode),
+ series_0_m1));
+ ASSERT_RTX_EQ (series_1_3,
+ simplify_binary_operation (PLUS, mode, series_1_1,
+ series_0_2));
+ ASSERT_RTX_EQ (series_0_1,
+ simplify_binary_operation (MINUS, mode, series_1_1,
+ CONST1_RTX (mode)));
+ ASSERT_RTX_EQ (series_1_1,
+ simplify_binary_operation (MINUS, mode, CONST1_RTX (mode),
+ series_0_m1));
+ ASSERT_RTX_EQ (series_1_1,
+ simplify_binary_operation (MINUS, mode, series_1_3,
+ series_0_2));
+
+ /* Test MULT between constant vectors. */
+ rtx vec2 = gen_const_vec_duplicate (mode, scalar2);
+ rtx vec3 = gen_const_vec_duplicate (mode, scalar3);
+ rtx scalar9 = gen_int_mode (9, inner_mode);
+ rtx series_3_9 = gen_const_vec_series (mode, scalar3, scalar9);
+ ASSERT_RTX_EQ (series_0_2,
+ simplify_binary_operation (MULT, mode, series_0_1, vec2));
+ ASSERT_RTX_EQ (series_3_9,
+ simplify_binary_operation (MULT, mode, vec3, series_1_3));
+ if (!GET_MODE_NUNITS (mode).is_constant ())
+ ASSERT_FALSE (simplify_binary_operation (MULT, mode, series_0_1,
+ series_0_1));
+
+ /* Test ASHIFT between constant vectors. */
+ ASSERT_RTX_EQ (series_0_2,
+ simplify_binary_operation (ASHIFT, mode, series_0_1,
+ CONST1_RTX (mode)));
+ if (!GET_MODE_NUNITS (mode).is_constant ())
+ ASSERT_FALSE (simplify_binary_operation (ASHIFT, mode, CONST1_RTX (mode),
+ series_0_1));
}
/* Verify simplify_merge_mask works correctly. */
#include "fold-const.h"
#include "tree-vector-builder.h"
-/* Try to start building a new vector of type TYPE that holds the result of
- a unary operation on VECTOR_CST T. 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, which it always is when
- ALLOW_STEPPED_P is true. Leave the builder unchanged otherwise. */
-
-bool
-tree_vector_builder::new_unary_operation (tree type, tree t,
- bool allow_stepped_p)
-{
- poly_uint64 full_nelts = TYPE_VECTOR_SUBPARTS (type);
- gcc_assert (known_eq (full_nelts, TYPE_VECTOR_SUBPARTS (TREE_TYPE (t))));
- unsigned int npatterns = VECTOR_CST_NPATTERNS (t);
- unsigned int nelts_per_pattern = VECTOR_CST_NELTS_PER_PATTERN (t);
- if (!allow_stepped_p && nelts_per_pattern > 2)
- {
- if (!full_nelts.is_constant ())
- return false;
- npatterns = full_nelts.to_constant ();
- nelts_per_pattern = 1;
- }
- new_vector (type, npatterns, nelts_per_pattern);
- 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)
-{
- poly_uint64 full_nelts = TYPE_VECTOR_SUBPARTS (type);
- gcc_assert (known_eq (full_nelts, TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1)))
- && known_eq (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)
- {
- if (!full_nelts.is_constant ())
- return false;
- npatterns = full_nelts.to_constant ();
- nelts_per_pattern = 1;
- }
- new_vector (type, npatterns, nelts_per_pattern);
- return true;
-}
-
-/* Return the number of elements that the caller needs to operate on in
- order to handle a binary operation on VECTOR_CSTs T1 and T2. This static
- function is used instead of new_binary_operation if the result of the
- operation is not a VECTOR_CST. */
-
-unsigned int
-tree_vector_builder::binary_encoded_nelts (tree t1, tree t2)
-{
- poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1));
- gcc_assert (known_eq (nelts, TYPE_VECTOR_SUBPARTS (TREE_TYPE (t2))));
- /* See new_binary_operation for details. */
- 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));
- unsigned HOST_WIDE_INT const_nelts;
- if (nelts.is_constant (&const_nelts))
- return MIN (npatterns * nelts_per_pattern, const_nelts);
- return npatterns * nelts_per_pattern;
-}
-
/* Return a vector element with the value BASE + FACTOR * STEP. */
tree
/* This class is used to build VECTOR_CSTs from a sequence of elements.
See vector_builder for more details. */
-class tree_vector_builder : public vector_builder<tree, tree_vector_builder>
+class tree_vector_builder : public vector_builder<tree, tree,
+ tree_vector_builder>
{
- typedef vector_builder<tree, tree_vector_builder> parent;
- friend class vector_builder<tree, tree_vector_builder>;
+ typedef vector_builder<tree, tree, tree_vector_builder> parent;
+ friend class vector_builder<tree, tree, tree_vector_builder>;
public:
tree_vector_builder () : m_type (0) {}
tree type () const { return m_type; }
void new_vector (tree, unsigned int, unsigned int);
- bool new_unary_operation (tree, tree, bool);
- bool new_binary_operation (tree, tree, tree, bool);
-
- static unsigned int binary_encoded_nelts (tree, tree);
private:
bool equal_p (const_tree, const_tree) const;
bool can_elide_p (const_tree) const;
void note_representative (tree *, tree);
+ static poly_uint64 shape_nelts (const_tree t)
+ { return TYPE_VECTOR_SUBPARTS (t); }
+ static poly_uint64 nelts_of (const_tree t)
+ { return VECTOR_CST_NELTS (t); }
+ static unsigned int npatterns_of (const_tree t)
+ { return VECTOR_CST_NPATTERNS (t); }
+ static unsigned int nelts_per_pattern_of (const_tree t)
+ { return VECTOR_CST_NELTS_PER_PATTERN (t); }
+
tree m_type;
};
variable-length vectors. finalize () then canonicalizes the encoding
to a simpler form if possible.
- The derived class Derived provides this functionality for specific Ts.
- Derived needs to provide the following interface:
+ Shape is the type that specifies the number of elements in the vector
+ and (where relevant) the type of each element.
+
+ The derived class Derived provides the functionality of this class
+ for specific Ts. Derived needs to provide the following interface:
bool equal_p (T elt1, T elt2) const;
Record that ELT2 is being elided, given that ELT1_PTR points to
the last encoded element for the containing pattern. This is
- again provided for TREE_OVERFLOW handling. */
+ again provided for TREE_OVERFLOW handling.
+
+ static poly_uint64 shape_nelts (Shape shape);
+
+ Return the number of elements in SHAPE.
+
+ The class provides additional functionality for the case in which
+ T can describe a vector constant as well as an individual element.
+ This functionality requires:
+
+ static poly_uint64 nelts_of (T x);
+
+ Return the number of elements in vector constant X.
-template<typename T, typename Derived>
+ static unsigned int npatterns_of (T x);
+
+ Return the number of patterns used to encode vector constant X.
+
+ static unsigned int nelts_per_pattern_of (T x);
+
+ Return the number of elements used to encode each pattern
+ in vector constant X. */
+
+template<typename T, typename Shape, typename Derived>
class vector_builder : public auto_vec<T, 32>
{
public:
bool operator == (const Derived &) const;
bool operator != (const Derived &x) const { return !operator == (x); }
+ bool new_unary_operation (Shape, T, bool);
+ bool new_binary_operation (Shape, T, T, bool);
+
void finalize ();
+ static unsigned int binary_encoded_nelts (T, T);
+
protected:
void new_vector (poly_uint64, unsigned int, unsigned int);
void reshape (unsigned int, unsigned int);
unsigned int m_nelts_per_pattern;
};
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
inline const Derived *
-vector_builder<T, Derived>::derived () const
+vector_builder<T, Shape, Derived>::derived () const
{
return static_cast<const Derived *> (this);
}
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
inline
-vector_builder<T, Derived>::vector_builder ()
+vector_builder<T, Shape, Derived>::vector_builder ()
: m_full_nelts (0),
m_npatterns (0),
m_nelts_per_pattern (0)
starts with these explicitly-encoded elements and may contain additional
elided elements. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
inline unsigned int
-vector_builder<T, Derived>::encoded_nelts () const
+vector_builder<T, Shape, Derived>::encoded_nelts () const
{
return m_npatterns * m_nelts_per_pattern;
}
/* Return true if every element of the vector is explicitly encoded. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
inline bool
-vector_builder<T, Derived>::encoded_full_vector_p () const
+vector_builder<T, Shape, Derived>::encoded_full_vector_p () const
{
return known_eq (m_npatterns * m_nelts_per_pattern, m_full_nelts);
}
/* Start building a vector that has FULL_NELTS elements. Initially
encode it using NPATTERNS patterns with NELTS_PER_PATTERN each. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
void
-vector_builder<T, Derived>::new_vector (poly_uint64 full_nelts,
- unsigned int npatterns,
- unsigned int nelts_per_pattern)
+vector_builder<T, Shape, Derived>::new_vector (poly_uint64 full_nelts,
+ unsigned int npatterns,
+ unsigned int nelts_per_pattern)
{
m_full_nelts = full_nelts;
m_npatterns = npatterns;
/* Return true if this vector and OTHER have the same elements and
are encoded in the same way. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
bool
-vector_builder<T, Derived>::operator == (const Derived &other) const
+vector_builder<T, Shape, Derived>::operator == (const Derived &other) const
{
if (maybe_ne (m_full_nelts, other.m_full_nelts)
|| m_npatterns != other.m_npatterns
/* Return the value of vector element I, which might or might not be
encoded explicitly. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
T
-vector_builder<T, Derived>::elt (unsigned int i) const
+vector_builder<T, Shape, Derived>::elt (unsigned int i) const
{
/* First handle elements that are already present in the underlying
vector, regardless of whether they're part of the encoding or not. */
derived ()->step (prev, final));
}
+/* Try to start building a new vector of shape SHAPE that holds the result of
+ a unary operation on vector constant VEC. 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, which it always is when
+ ALLOW_STEPPED_P is true. Leave the builder unchanged otherwise. */
+
+template<typename T, typename Shape, typename Derived>
+bool
+vector_builder<T, Shape, Derived>::new_unary_operation (Shape shape, T vec,
+ bool allow_stepped_p)
+{
+ poly_uint64 full_nelts = Derived::shape_nelts (shape);
+ gcc_assert (known_eq (full_nelts, Derived::nelts_of (vec)));
+ unsigned int npatterns = Derived::npatterns_of (vec);
+ unsigned int nelts_per_pattern = Derived::nelts_per_pattern_of (vec);
+ if (!allow_stepped_p && nelts_per_pattern > 2)
+ {
+ if (!full_nelts.is_constant ())
+ return false;
+ npatterns = full_nelts.to_constant ();
+ nelts_per_pattern = 1;
+ }
+ derived ()->new_vector (shape, npatterns, nelts_per_pattern);
+ return true;
+}
+
+/* Try to start building a new vector of shape SHAPE that holds the result of
+ a binary operation on vector constants VEC1 and VEC2. 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. */
+
+template<typename T, typename Shape, typename Derived>
+bool
+vector_builder<T, Shape, Derived>::new_binary_operation (Shape shape,
+ T vec1, T vec2,
+ bool allow_stepped_p)
+{
+ poly_uint64 full_nelts = Derived::shape_nelts (shape);
+ gcc_assert (known_eq (full_nelts, Derived::nelts_of (vec1))
+ && known_eq (full_nelts, Derived::nelts_of (vec2)));
+ /* Conceptually we split the patterns in VEC1 and VEC2 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 (Derived::npatterns_of (vec1),
+ Derived::npatterns_of (vec2));
+ unsigned int nelts_per_pattern
+ = MAX (Derived::nelts_per_pattern_of (vec1),
+ Derived::nelts_per_pattern_of (vec2));
+ if (!allow_stepped_p && nelts_per_pattern > 2)
+ {
+ if (!full_nelts.is_constant ())
+ return false;
+ npatterns = full_nelts.to_constant ();
+ nelts_per_pattern = 1;
+ }
+ derived ()->new_vector (shape, npatterns, nelts_per_pattern);
+ return true;
+}
+
+/* Return the number of elements that the caller needs to operate on in
+ order to handle a binary operation on vector constants VEC1 and VEC2.
+ This static function is used instead of new_binary_operation if the
+ result of the operation is not a constant vector. */
+
+template<typename T, typename Shape, typename Derived>
+unsigned int
+vector_builder<T, Shape, Derived>::binary_encoded_nelts (T vec1, T vec2)
+{
+ poly_uint64 nelts = Derived::nelts_of (vec1);
+ gcc_assert (known_eq (nelts, Derived::nelts_of (vec2)));
+ /* See new_binary_operation for details. */
+ unsigned int npatterns
+ = least_common_multiple (Derived::npatterns_of (vec1),
+ Derived::npatterns_of (vec2));
+ unsigned int nelts_per_pattern
+ = MAX (Derived::nelts_per_pattern_of (vec1),
+ Derived::nelts_per_pattern_of (vec2));
+ unsigned HOST_WIDE_INT const_nelts;
+ if (nelts.is_constant (&const_nelts))
+ return MIN (npatterns * nelts_per_pattern, const_nelts);
+ return npatterns * nelts_per_pattern;
+}
+
/* Return the number of leading duplicate elements in the range
[START:END:STEP]. The value is always at least 1. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
unsigned int
-vector_builder<T, Derived>::count_dups (int start, int end, int step) const
+vector_builder<T, Shape, Derived>::count_dups (int start, int end,
+ int step) const
{
gcc_assert ((end - start) % step == 0);
/* Change the encoding to NPATTERNS patterns of NELTS_PER_PATTERN each,
but without changing the underlying vector. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
void
-vector_builder<T, Derived>::reshape (unsigned int npatterns,
- unsigned int nelts_per_pattern)
+vector_builder<T, Shape, Derived>::reshape (unsigned int npatterns,
+ unsigned int nelts_per_pattern)
{
unsigned int old_encoded_nelts = encoded_nelts ();
unsigned int new_encoded_nelts = npatterns * nelts_per_pattern;
/* Return true if elements [START, END) contain a repeating sequence of
STEP elements. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
bool
-vector_builder<T, Derived>::repeating_sequence_p (unsigned int start,
- unsigned int end,
- unsigned int step)
+vector_builder<T, Shape, Derived>::repeating_sequence_p (unsigned int start,
+ unsigned int end,
+ unsigned int step)
{
for (unsigned int i = start; i < end - step; ++i)
if (!derived ()->equal_p ((*this)[i], (*this)[i + step]))
/* Return true if elements [START, END) contain STEP interleaved linear
series. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
bool
-vector_builder<T, Derived>::stepped_sequence_p (unsigned int start,
- unsigned int end,
- unsigned int step)
+vector_builder<T, Shape, Derived>::stepped_sequence_p (unsigned int start,
+ unsigned int end,
+ unsigned int step)
{
if (!derived ()->allow_steps_p ())
return false;
/* Try to change the number of encoded patterns to NPATTERNS, returning
true on success. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
bool
-vector_builder<T, Derived>::try_npatterns (unsigned int npatterns)
+vector_builder<T, Shape, Derived>::try_npatterns (unsigned int npatterns)
{
if (m_nelts_per_pattern == 1)
{
/* Replace the current encoding with the canonical form. */
-template<typename T, typename Derived>
+template<typename T, typename Shape, typename Derived>
void
-vector_builder<T, Derived>::finalize ()
+vector_builder<T, Shape, Derived>::finalize ()
{
/* The encoding requires the same number of elements to come from each
pattern. */