+2017-12-07 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * vector-builder.h (vector_builder::derived): New const overload.
+ (vector_builder::elt): New function.
+ * tree-vector-builder.h (tree_vector_builder::type): New function.
+ (tree_vector_builder::apply_step): Declare.
+ * tree-vector-builder.c (tree_vector_builder::apply_step): New
+ function.
+ * gimple-fold.h (tree_vector_builder): Declare.
+ (gimple_build_vector): Take a tree_vector_builder instead of a
+ type and vector of elements.
+ * gimple-fold.c (gimple_build_vector): Likewise.
+ * tree-vect-loop.c (get_initial_def_for_reduction): Update call
+ accordingly.
+ (get_initial_defs_for_reduction): Likewise.
+ (vectorizable_induction): Likewise.
+
2017-12-07 Richard Sandiford <richard.sandiford@linaro.org>
* tree-vector-builder.h
return res;
}
-/* Build a vector of type TYPE in which the elements have the values
- given by ELTS. Return a gimple value for the result, appending any
- new instructions to SEQ. */
+/* Build a vector from BUILDER, handling the case in which some elements
+ are non-constant. Return a gimple value for the result, appending any
+ new instructions to SEQ.
+
+ BUILDER must not have a stepped encoding on entry. This is because
+ the function is not geared up to handle the arithmetic that would
+ be needed in the variable case, and any code building a vector that
+ is known to be constant should use BUILDER->build () directly. */
tree
-gimple_build_vector (gimple_seq *seq, location_t loc, tree type,
- vec<tree> elts)
+gimple_build_vector (gimple_seq *seq, location_t loc,
+ tree_vector_builder *builder)
{
- unsigned int nelts = elts.length ();
- gcc_assert (nelts == TYPE_VECTOR_SUBPARTS (type));
- for (unsigned int i = 0; i < nelts; ++i)
- if (!TREE_CONSTANT (elts[i]))
+ gcc_assert (builder->nelts_per_pattern () <= 2);
+ unsigned int encoded_nelts = builder->encoded_nelts ();
+ for (unsigned int i = 0; i < encoded_nelts; ++i)
+ if (!TREE_CONSTANT ((*builder)[i]))
{
+ tree type = builder->type ();
+ unsigned int nelts = TYPE_VECTOR_SUBPARTS (type);
vec<constructor_elt, va_gc> *v;
vec_alloc (v, nelts);
for (i = 0; i < nelts; ++i)
- CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elts[i]);
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, builder->elt (i));
tree res;
if (gimple_in_ssa_p (cfun))
gimple_seq_add_stmt_without_update (seq, stmt);
return res;
}
- return build_vector (type, elts);
+ return builder->build ();
}
/* Return true if the result of assignment STMT is known to be non-negative.
return gimple_build_vector_from_val (seq, UNKNOWN_LOCATION, type, op);
}
-extern tree gimple_build_vector (gimple_seq *, location_t, tree, vec<tree>);
+class tree_vector_builder;
+extern tree gimple_build_vector (gimple_seq *, location_t,
+ tree_vector_builder *);
inline tree
-gimple_build_vector (gimple_seq *seq, tree type, vec<tree> elts)
+gimple_build_vector (gimple_seq *seq, tree_vector_builder *builder)
{
- return gimple_build_vector (seq, UNKNOWN_LOCATION, type, elts);
+ return gimple_build_vector (seq, UNKNOWN_LOCATION, builder);
}
extern bool gimple_stmt_nonnegative_warnv_p (gimple *, bool *, int = 0);
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
tree scalar_type = TREE_TYPE (init_val);
tree vectype = get_vectype_for_scalar_type (scalar_type);
- int nunits;
enum tree_code code = gimple_assign_rhs_code (stmt);
tree def_for_init;
tree init_def;
- int i;
bool nested_in_vect_loop = false;
REAL_VALUE_TYPE real_init_val = dconst0;
int int_init_val = 0;
gimple_seq stmts = NULL;
gcc_assert (vectype);
- nunits = TYPE_VECTOR_SUBPARTS (vectype);
gcc_assert (POINTER_TYPE_P (scalar_type) || INTEGRAL_TYPE_P (scalar_type)
|| SCALAR_FLOAT_TYPE_P (scalar_type));
else
{
/* Option2: the first element is INIT_VAL. */
- auto_vec<tree, 32> elts (nunits);
+ tree_vector_builder elts (vectype, 1, 2);
elts.quick_push (init_val);
- for (i = 1; i < nunits; ++i)
- elts.quick_push (def_for_init);
- init_def = gimple_build_vector (&stmts, vectype, elts);
+ elts.quick_push (def_for_init);
+ init_def = gimple_build_vector (&stmts, &elts);
}
}
break;
number_of_copies = nunits * number_of_vectors / group_size;
number_of_places_left_in_vector = nunits;
- auto_vec<tree, 32> elts (nunits);
+ tree_vector_builder elts (vector_type, nunits, 1);
elts.quick_grow (nunits);
for (j = 0; j < number_of_copies; j++)
{
if (number_of_places_left_in_vector == 0)
{
gimple_seq ctor_seq = NULL;
- tree init = gimple_build_vector (&ctor_seq, vector_type, elts);
+ tree init = gimple_build_vector (&ctor_seq, &elts);
if (ctor_seq != NULL)
gsi_insert_seq_on_edge_immediate (pe, ctor_seq);
voprnds.quick_push (init);
number_of_places_left_in_vector = nunits;
+ elts.new_vector (vector_type, nunits, 1);
+ elts.quick_grow (nunits);
}
}
}
unsigned ivn;
for (ivn = 0; ivn < nivs; ++ivn)
{
- auto_vec<tree, 32> elts (nunits);
+ tree_vector_builder elts (vectype, nunits, 1);
stmts = NULL;
for (unsigned eltn = 0; eltn < nunits; ++eltn)
{
elt, step_expr);
elts.quick_push (elt);
}
- vec_init = gimple_build_vector (&stmts, vectype, elts);
+ vec_init = gimple_build_vector (&stmts, &elts);
if (stmts)
{
new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
stmts = NULL;
new_name = gimple_convert (&stmts, TREE_TYPE (vectype), init_expr);
- auto_vec<tree, 32> elts (nunits);
+ tree_vector_builder elts (vectype, nunits, 1);
elts.quick_push (new_name);
for (i = 1; i < nunits; i++)
{
}
/* Create a vector from [new_name_0, new_name_1, ...,
new_name_nunits-1] */
- vec_init = gimple_build_vector (&stmts, vectype, elts);
+ vec_init = gimple_build_vector (&stmts, &elts);
if (stmts)
{
new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
return true;
}
+/* Return a vector element with the value BASE + FACTOR * STEP. */
+
+tree
+tree_vector_builder::apply_step (tree base, unsigned int factor,
+ const wide_int &step) const
+{
+ return wide_int_to_tree (TREE_TYPE (base),
+ wi::to_wide (base) + factor * step);
+}
+
/* Return a VECTOR_CST for the current constant. */
tree
bool allow_steps_p () const;
bool integral_p (const_tree) const;
wide_int step (const_tree, const_tree) const;
+ tree apply_step (tree, unsigned int, const wide_int &) const;
bool can_elide_p (const_tree) const;
void note_representative (tree *, tree);
given integral_p (ELT1) && integral_p (ELT2). There is no fixed
choice of StepType.
+ T apply_step (T base, unsigned int factor, StepType step) const;
+
+ Return a vector element with the value BASE + FACTOR * STEP.
+
bool can_elide_p (T elt) const;
Return true if we can drop element ELT, even if the retained
unsigned int nelts_per_pattern () const { return m_nelts_per_pattern; }
unsigned int encoded_nelts () const;
bool encoded_full_vector_p () const;
+ T elt (unsigned int) const;
void finalize ();
this->truncate (0);
}
+/* Return the value of vector element I, which might or might not be
+ encoded explicitly. */
+
+template<typename T, typename Derived>
+T
+vector_builder<T, Derived>::elt (unsigned int i) const
+{
+ /* This only makes sense if the encoding has been fully populated. */
+ gcc_checking_assert (encoded_nelts () <= this->length ());
+
+ /* First handle elements that are already present in the underlying
+ vector, regardless of whether they're part of the encoding or not. */
+ if (i < this->length ())
+ return (*this)[i];
+
+ /* Identify the pattern that contains element I and work out the index of
+ the last encoded element for that pattern. */
+ unsigned int pattern = i % m_npatterns;
+ unsigned int count = i / m_npatterns;
+ unsigned int final_i = encoded_nelts () - m_npatterns + pattern;
+ T final = (*this)[final_i];
+
+ /* If there are no steps, the final encoded value is the right one. */
+ if (m_nelts_per_pattern <= 2)
+ return final;
+
+ /* Otherwise work out the value from the last two encoded elements. */
+ T prev = (*this)[final_i - m_npatterns];
+ return derived ()->apply_step (final, count - 2,
+ derived ()->step (prev, final));
+}
+
/* Change the encoding to NPATTERNS patterns of NELTS_PER_PATTERN each,
but without changing the underlying vector. */