#include "optabs.h"
#include "params.h"
#include "diagnostic-core.h"
-#include "toplev.h"
#include "tree-chrec.h"
#include "tree-scalar-evolution.h"
#include "tree-vectorizer.h"
had successfully passed the analysis phase.
Throughout this pass we make a distinction between two types of
data: scalars (which are represented by SSA_NAMES), and memory references
- ("data-refs"). These two types of data require different handling both
+ ("data-refs"). These two types of data require different handling both
during analysis and transformation. The types of data-refs that the
vectorizer currently supports are ARRAY_REFS which base is an array DECL
(not a pointer), and INDIRECT_REFS through pointers; both array and pointer
=====================
The loop transformation phase scans all the stmts in the loop, and
creates a vector stmt (or a sequence of stmts) for each scalar stmt S in
- the loop that needs to be vectorized. It inserts the vector code sequence
+ the loop that needs to be vectorized. It inserts the vector code sequence
just before the scalar stmt S, and records a pointer to the vector code
in STMT_VINFO_VEC_STMT (stmt_info) (stmt_info is the stmt_vec_info struct
- attached to S). This pointer will be used for the vectorization of following
+ attached to S). This pointer will be used for the vectorization of following
stmts which use the def of stmt S. Stmt S is removed if it writes to memory;
otherwise, we rely on dead code elimination for removing it.
To vectorize stmt S2, the vectorizer first finds the stmt that defines
the operand 'b' (S1), and gets the relevant vector def 'vb' from the
- vector stmt VS1 pointed to by STMT_VINFO_VEC_STMT (stmt_info (S1)). The
+ vector stmt VS1 pointed to by STMT_VINFO_VEC_STMT (stmt_info (S1)). The
resulting sequence would be:
VS1: vb = px[i];
Target modeling:
=================
Currently the only target specific information that is used is the
- size of the vector (in bytes) - "UNITS_PER_SIMD_WORD". Targets that can
- support different sizes of vectors, for now will need to specify one value
- for "UNITS_PER_SIMD_WORD". More flexibility will be added in the future.
+ size of the vector (in bytes) - "TARGET_VECTORIZE_UNITS_PER_SIMD_WORD".
+ Targets that can support different sizes of vectors, for now will need
+ to specify one value for "TARGET_VECTORIZE_UNITS_PER_SIMD_WORD". More
+ flexibility will be added in the future.
Since we only vectorize operations which vector form can be
expressed using existing tree codes, to verify that an operation is
supported, the vectorizer checks the relevant optab at the relevant
- machine_mode (e.g, optab_handler (add_optab, V8HImode)). If
+ machine_mode (e.g, optab_handler (add_optab, V8HImode)). If
the value found is CODE_FOR_nothing, then there's no target support, and
we can't vectorize the stmt.
/* Function vect_determine_vectorization_factor
- Determine the vectorization factor (VF). VF is the number of data elements
+ Determine the vectorization factor (VF). VF is the number of data elements
that are operated upon in parallel in a single iteration of the vectorized
- loop. For example, when vectorizing a loop that operates on 4byte elements,
+ loop. For example, when vectorizing a loop that operates on 4byte elements,
on a target with vector size (VS) 16byte, the VF is set to 4, since 4
elements can fit in a single vector register.
We currently support vectorization of loops in which all types operated upon
- are of the same size. Therefore this function currently sets VF according to
+ are of the same size. Therefore this function currently sets VF according to
the size of the types operated upon, and fails if there are multiple sizes
in the loop.
/* Function vect_analyze_scalar_cycles_1.
Examine the cross iteration def-use cycles of scalar variables
- in LOOP. LOOP_VINFO represents the loop that is now being
+ in LOOP. LOOP_VINFO represents the loop that is now being
considered for vectorization (can be LOOP, or an outer-loop
enclosing LOOP). */
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vect_analyze_scalar_cycles ===");
- /* First - identify all inductions. Reduction detection assumes that all the
+ /* First - identify all inductions. Reduction detection assumes that all the
inductions have been identified, therefore, this order must not be
changed. */
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
print_gimple_stmt (vect_dump, phi, 0, TDF_SLIM);
}
- /* Skip virtual phi's. The data dependences that are associated with
+ /* Skip virtual phi's. The data dependences that are associated with
virtual defs/uses (i.e., memory accesses) are analyzed elsewhere. */
if (!is_gimple_reg (SSA_NAME_VAR (def)))
continue;
/* Analyze the evolution function. */
access_fn = analyze_scalar_evolution (loop, def);
+ if (access_fn)
+ STRIP_NOPS (access_fn);
if (access_fn && vect_print_dump_info (REPORT_DETAILS))
{
fprintf (vect_dump, "Access function of PHI: ");
/* Function vect_analyze_scalar_cycles.
Examine the cross iteration def-use cycles of scalar variables, by
- analyzing the loop-header PHIs of scalar variables; Classify each
+ analyzing the loop-header PHIs of scalar variables. Classify each
cycle as one of the following: invariant, induction, reduction, unknown.
We do that for the loop represented by LOOP_VINFO, and also to its
inner-loop, if exists.
LOOP_VINFO_VECTORIZABLE_P (res) = 0;
LOOP_PEELING_FOR_ALIGNMENT (res) = 0;
LOOP_VINFO_VECT_FACTOR (res) = 0;
+ LOOP_VINFO_LOOP_NEST (res) = VEC_alloc (loop_p, heap, 3);
LOOP_VINFO_DATAREFS (res) = VEC_alloc (data_reference_p, heap, 10);
LOOP_VINFO_DDRS (res) = VEC_alloc (ddr_p, heap, 10 * 10);
LOOP_VINFO_UNALIGNED_DR (res) = NULL;
free (LOOP_VINFO_BBS (loop_vinfo));
free_data_refs (LOOP_VINFO_DATAREFS (loop_vinfo));
free_dependence_relations (LOOP_VINFO_DDRS (loop_vinfo));
+ VEC_free (loop_p, heap, LOOP_VINFO_LOOP_NEST (loop_vinfo));
VEC_free (gimple, heap, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo));
+ VEC_free (ddr_p, heap, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo));
free (loop_vinfo);
loop->aux = NULL;
free (LOOP_VINFO_BBS (loop_vinfo));
free_data_refs (LOOP_VINFO_DATAREFS (loop_vinfo));
free_dependence_relations (LOOP_VINFO_DDRS (loop_vinfo));
+ VEC_free (loop_p, heap, LOOP_VINFO_LOOP_NEST (loop_vinfo));
VEC_free (gimple, heap, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo));
VEC_free (ddr_p, heap, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo));
slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
- for (j = 0; VEC_iterate (slp_instance, slp_instances, j, instance); j++)
+ FOR_EACH_VEC_ELT (slp_instance, slp_instances, j, instance)
vect_free_slp_instance (instance);
VEC_free (slp_instance, heap, LOOP_VINFO_SLP_INSTANCES (loop_vinfo));
/* Get cost by calling cost target builtin. */
-static inline
-int vect_get_cost (enum vect_cost_for_stmt type_of_cost)
+static inline int
+vect_get_cost (enum vect_cost_for_stmt type_of_cost)
{
tree dummy_type = NULL;
int dummy = 0;
return false;
}
- /* Analyze cost. Decide if worth while to vectorize. */
+ /* Analyze cost. Decide if worth while to vectorize. */
/* Once VF is set, SLP costs should be updated since the number of created
vector stmts depends on VF. */
}
-/* Function vect_analyze_loop.
+/* Function vect_analyze_loop_2.
Apply a set of analyses on LOOP, and create a loop_vec_info struct
- for it. The different analyses will record information in the
+ for it. The different analyses will record information in the
loop_vec_info struct. */
-loop_vec_info
-vect_analyze_loop (struct loop *loop)
+static bool
+vect_analyze_loop_2 (loop_vec_info loop_vinfo)
{
- bool ok;
- loop_vec_info loop_vinfo;
+ bool ok, dummy;
int max_vf = MAX_VECTORIZATION_FACTOR;
int min_vf = 2;
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "===== analyze_loop_nest =====");
-
- if (loop_outer (loop)
- && loop_vec_info_for_loop (loop_outer (loop))
- && LOOP_VINFO_VECTORIZABLE_P (loop_vec_info_for_loop (loop_outer (loop))))
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "outer-loop already vectorized.");
- return NULL;
- }
-
- /* Check the CFG characteristics of the loop (nesting, entry/exit, etc. */
-
- loop_vinfo = vect_analyze_loop_form (loop);
- if (!loop_vinfo)
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "bad loop form.");
- return NULL;
- }
-
/* Find all data references in the loop (which correspond to vdefs/vuses)
and analyze their evolution in the loop. Also adjust the minimal
vectorization factor according to the loads and stores.
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "bad data references.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
/* Classify all cross-iteration scalar data-flow cycles.
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "unexpected pattern.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
/* Analyze data dependences between the data-refs in the loop
the dependences.
FORNOW: fail at the first data dependence that we encounter. */
- ok = vect_analyze_data_ref_dependences (loop_vinfo, NULL, &max_vf);
+ ok = vect_analyze_data_ref_dependences (loop_vinfo, NULL, &max_vf, &dummy);
if (!ok
|| max_vf < min_vf)
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "bad data dependence.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
ok = vect_determine_vectorization_factor (loop_vinfo);
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "can't determine vectorization factor.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
if (max_vf < LOOP_VINFO_VECT_FACTOR (loop_vinfo))
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "bad data dependence.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
/* Analyze the alignment of the data-refs in the loop.
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "bad data alignment.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
/* Analyze the access patterns of the data-refs in the loop (consecutive,
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "bad data access.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
/* Prune the list of ddrs to be tested at run-time by versioning for alias.
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "too long list of versioning for alias "
"run-time tests.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
/* This pass will decide on using loop versioning and/or loop peeling in
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "bad data alignment.");
- destroy_loop_vec_info (loop_vinfo, true);
- return NULL;
+ return false;
}
/* Check the SLP opportunities in the loop, analyze and build SLP trees. */
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "bad operation or unsupported loop bound.");
- destroy_loop_vec_info (loop_vinfo, true);
+ return false;
+ }
+
+ return true;
+}
+
+/* Function vect_analyze_loop.
+
+ Apply a set of analyses on LOOP, and create a loop_vec_info struct
+ for it. The different analyses will record information in the
+ loop_vec_info struct. */
+loop_vec_info
+vect_analyze_loop (struct loop *loop)
+{
+ loop_vec_info loop_vinfo;
+ unsigned int vector_sizes;
+
+ /* Autodetect first vector size we try. */
+ current_vector_size = 0;
+ vector_sizes = targetm.vectorize.autovectorize_vector_sizes ();
+
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "===== analyze_loop_nest =====");
+
+ if (loop_outer (loop)
+ && loop_vec_info_for_loop (loop_outer (loop))
+ && LOOP_VINFO_VECTORIZABLE_P (loop_vec_info_for_loop (loop_outer (loop))))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "outer-loop already vectorized.");
return NULL;
}
- LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
+ while (1)
+ {
+ /* Check the CFG characteristics of the loop (nesting, entry/exit). */
+ loop_vinfo = vect_analyze_loop_form (loop);
+ if (!loop_vinfo)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "bad loop form.");
+ return NULL;
+ }
- return loop_vinfo;
+ if (vect_analyze_loop_2 (loop_vinfo))
+ {
+ LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
+
+ return loop_vinfo;
+ }
+
+ destroy_loop_vec_info (loop_vinfo, true);
+
+ vector_sizes &= ~current_vector_size;
+ if (vector_sizes == 0
+ || current_vector_size == 0)
+ return NULL;
+
+ /* Try the next biggest vector size. */
+ current_vector_size = 1 << floor_log2 (vector_sizes);
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "***** Re-trying analysis with "
+ "vector size %d\n", current_vector_size);
+ }
}
}
-/* Error reporting helper for vect_is_simple_reduction below. GIMPLE statement
+/* Error reporting helper for vect_is_simple_reduction below. GIMPLE statement
STMT is printed with a message MSG. */
static void
/* Function vect_is_simple_reduction_1
(1) Detect a cross-iteration def-use cycle that represents a simple
- reduction computation. We look for the following pattern:
+ reduction computation. We look for the following pattern:
loop_header:
a1 = phi < a0, a2 >
1. operation is commutative and associative and it is safe to
change the order of the computation (if CHECK_REDUCTION is true)
2. no uses for a2 in the loop (a2 is used out of the loop)
- 3. no uses of a1 in the loop besides the reduction operation.
+ 3. no uses of a1 in the loop besides the reduction operation
+ 4. no uses of a1 outside the loop.
- Condition 1 is tested here.
+ Conditions 1,4 are tested here.
Conditions 2,3 are tested in vect_mark_stmts_to_be_vectorized.
(2) Detect a cross-iteration def-use cycle in nested loops, i.e.,
gimple use_stmt = USE_STMT (use_p);
if (is_gimple_debug (use_stmt))
continue;
- if (flow_bb_inside_loop_p (loop, gimple_bb (use_stmt))
- && vinfo_for_stmt (use_stmt)
+
+ if (!flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "intermediate value used outside loop.");
+
+ return NULL;
+ }
+
+ if (vinfo_for_stmt (use_stmt)
&& !is_pattern_stmt_p (vinfo_for_stmt (use_stmt)))
nloop_uses++;
if (nloop_uses > 1)
simply rewriting this into "res += -x[i]". Avoid changing
gimple instruction for the first simple tests and only do this
if we're allowed to change code at all. */
- if (code == MINUS_EXPR && modify)
+ if (code == MINUS_EXPR
+ && modify
+ && (op1 = gimple_assign_rhs1 (def_stmt))
+ && TREE_CODE (op1) == SSA_NAME
+ && SSA_NAME_DEF_STMT (op1) == phi)
code = PLUS_EXPR;
if (check_reduction
&& (code == COND_EXPR
|| (def1 && flow_bb_inside_loop_p (loop, gimple_bb (def1))
&& (is_gimple_assign (def1)
+ || is_gimple_call (def1)
|| STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def1))
== vect_induction_def
|| (gimple_code (def1) == GIMPLE_PHI
&& (code == COND_EXPR
|| (def2 && flow_bb_inside_loop_p (loop, gimple_bb (def2))
&& (is_gimple_assign (def2)
+ || is_gimple_call (def2)
|| STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def2))
== vect_induction_def
|| (gimple_code (def2) == GIMPLE_PHI
int nbbs = loop->num_nodes, factor, scalar_single_iter_cost = 0;
int innerloop_iters, i, stmt_cost;
- /* Count statements in scalar loop. Using this as scalar cost for a single
+ /* Count statements in scalar loop. Using this as scalar cost for a single
iteration for now.
TODO: Add outer loop support.
statements. */
/* FORNOW. */
+ innerloop_iters = 1;
if (loop->inner)
innerloop_iters = 50; /* FIXME */
something more reasonable. */
/* If the number of iterations is known and we do not do versioning, we can
- decide whether to vectorize at compile time. Hence the scalar version
+ decide whether to vectorize at compile time. Hence the scalar version
do not carry cost model guard costs. */
if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
|| LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT (loop_vinfo)
/* Add SLP costs. */
slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
- for (i = 0; VEC_iterate (slp_instance, slp_instances, i, instance); i++)
+ FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
{
vec_outside_cost += SLP_INSTANCE_OUTSIDE_OF_LOOP_COST (instance);
vec_inside_cost += SLP_INSTANCE_INSIDE_OF_LOOP_COST (instance);
}
/* Calculate number of iterations required to make the vector version
- profitable, relative to the loop bodies only. The following condition
+ profitable, relative to the loop bodies only. The following condition
must hold true:
SIC * niters + SOC > VIC * ((niters-PL_ITERS-EP_ITERS)/VF) + VOC
where
Output:
Return a vector variable, initialized with the first VF values of
- the induction variable. E.g., for an iv with IV_PHI='X' and
+ the induction variable. E.g., for an iv with IV_PHI='X' and
evolution S, for a vector of 4 units, we want to return:
[X, X + S, X + 2*S, X + 3*S]. */
stmt_vec_info stmt_vinfo = vinfo_for_stmt (iv_phi);
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- tree scalar_type = TREE_TYPE (gimple_phi_result (iv_phi));
+ tree scalar_type;
tree vectype;
int nunits;
edge pe = loop_preheader_edge (loop);
gimple_stmt_iterator si;
basic_block bb = gimple_bb (iv_phi);
tree stepvectype;
-
- vectype = get_vectype_for_scalar_type (scalar_type);
- gcc_assert (vectype);
- nunits = TYPE_VECTOR_SUBPARTS (vectype);
- ncopies = vf / nunits;
-
- gcc_assert (phi_info);
- gcc_assert (ncopies >= 1);
-
- /* Find the first insertion point in the BB. */
- si = gsi_after_labels (bb);
-
- if (INTEGRAL_TYPE_P (scalar_type))
- step_expr = build_int_cst (scalar_type, 0);
- else if (POINTER_TYPE_P (scalar_type))
- step_expr = size_zero_node;
- else
- step_expr = build_real (scalar_type, dconst0);
+ tree resvectype;
/* Is phi in an inner-loop, while vectorizing an enclosing outer-loop? */
if (nested_in_vect_loop_p (loop, iv_phi))
access_fn = analyze_scalar_evolution (iv_loop, PHI_RESULT (iv_phi));
gcc_assert (access_fn);
+ STRIP_NOPS (access_fn);
ok = vect_is_simple_iv_evolution (iv_loop->num, access_fn,
&init_expr, &step_expr);
gcc_assert (ok);
pe = loop_preheader_edge (iv_loop);
+ scalar_type = TREE_TYPE (init_expr);
+ vectype = get_vectype_for_scalar_type (scalar_type);
+ resvectype = get_vectype_for_scalar_type (TREE_TYPE (PHI_RESULT (iv_phi)));
+ gcc_assert (vectype);
+ nunits = TYPE_VECTOR_SUBPARTS (vectype);
+ ncopies = vf / nunits;
+
+ gcc_assert (phi_info);
+ gcc_assert (ncopies >= 1);
+
+ /* Find the first insertion point in the BB. */
+ si = gsi_after_labels (bb);
+
/* Create the vector that holds the initial_value of the induction. */
if (nested_in_vect_loop)
{
/* iv_loop is nested in the loop to be vectorized. init_expr had already
- been created during vectorization of previous stmts; We obtain it from
- the STMT_VINFO_VEC_STMT of the defining stmt. */
+ been created during vectorization of previous stmts. We obtain it
+ from the STMT_VINFO_VEC_STMT of the defining stmt. */
tree iv_def = PHI_ARG_DEF_FROM_EDGE (iv_phi,
loop_preheader_edge (iv_loop));
vec_init = vect_get_vec_def_for_operand (iv_def, iv_phi, NULL);
}
t = NULL_TREE;
- t = tree_cons (NULL_TREE, init_expr, t);
+ t = tree_cons (NULL_TREE, new_name, t);
for (i = 1; i < nunits; i++)
{
/* Create: new_name_i = new_name + step_expr */
expr, step_expr);
}
- t = NULL_TREE;
- for (i = 0; i < nunits; i++)
- t = tree_cons (NULL_TREE, unshare_expr (new_name), t);
+ t = unshare_expr (new_name);
gcc_assert (CONSTANT_CLASS_P (new_name));
stepvectype = get_vectype_for_scalar_type (TREE_TYPE (new_name));
gcc_assert (stepvectype);
- vec = build_vector (stepvectype, t);
+ vec = build_vector_from_val (stepvectype, t);
vec_step = vect_init_vector (iv_phi, vec, stepvectype, NULL);
expr = build_int_cst (TREE_TYPE (step_expr), nunits);
new_name = fold_build2 (MULT_EXPR, TREE_TYPE (step_expr),
expr, step_expr);
- t = NULL_TREE;
- for (i = 0; i < nunits; i++)
- t = tree_cons (NULL_TREE, unshare_expr (new_name), t);
+ t = unshare_expr (new_name);
gcc_assert (CONSTANT_CLASS_P (new_name));
- vec = build_vector (stepvectype, t);
+ vec = build_vector_from_val (stepvectype, t);
vec_step = vect_init_vector (iv_phi, vec, stepvectype, NULL);
vec_def = induc_def;
gimple_assign_set_lhs (new_stmt, vec_def);
gsi_insert_before (&si, new_stmt, GSI_SAME_STMT);
+ if (!useless_type_conversion_p (resvectype, vectype))
+ {
+ new_stmt = gimple_build_assign_with_ops
+ (VIEW_CONVERT_EXPR,
+ vect_get_new_vect_var (resvectype, vect_simple_var,
+ "vec_iv_"),
+ build1 (VIEW_CONVERT_EXPR, resvectype,
+ gimple_assign_lhs (new_stmt)), NULL_TREE);
+ gimple_assign_set_lhs (new_stmt,
+ make_ssa_name
+ (gimple_assign_lhs (new_stmt), new_stmt));
+ gsi_insert_before (&si, new_stmt, GSI_SAME_STMT);
+ }
set_vinfo_for_stmt (new_stmt,
new_stmt_vec_info (new_stmt, loop_vinfo, NULL));
STMT_VINFO_RELATED_STMT (prev_stmt_vinfo) = new_stmt;
}
STMT_VINFO_VEC_STMT (phi_info) = induction_phi;
+ if (!useless_type_conversion_p (resvectype, vectype))
+ {
+ new_stmt = gimple_build_assign_with_ops
+ (VIEW_CONVERT_EXPR,
+ vect_get_new_vect_var (resvectype, vect_simple_var, "vec_iv_"),
+ build1 (VIEW_CONVERT_EXPR, resvectype, induc_def), NULL_TREE);
+ induc_def = make_ssa_name (gimple_assign_lhs (new_stmt), new_stmt);
+ gimple_assign_set_lhs (new_stmt, induc_def);
+ si = gsi_start_bb (bb);
+ gsi_insert_before (&si, new_stmt, GSI_SAME_STMT);
+ set_vinfo_for_stmt (new_stmt,
+ new_stmt_vec_info (new_stmt, loop_vinfo, NULL));
+ STMT_VINFO_RELATED_STMT (vinfo_for_stmt (new_stmt))
+ = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (induction_phi));
+ }
+
return induc_def;
}
gcc_assert (loop == (gimple_bb (stmt))->loop_father);
/* In case of double reduction we only create a vector variable to be put
- in the reduction phi node. The actual statement creation is done in
+ in the reduction phi node. The actual statement creation is done in
vect_create_epilog_for_reduction. */
if (adjustment_def && nested_in_vect_loop
&& TREE_CODE (init_val) == SSA_NAME
break;
}
- for (i = nunits - 1; i >= 0; --i)
- t = tree_cons (NULL_TREE, init_value, t);
-
- if (TREE_CONSTANT (init_val))
- init_def = build_vector (vectype, t);
- else
- init_def = build_constructor_from_list (vectype, t);
-
+ init_def = build_vector_from_val (vectype, init_value);
break;
default:
reduction statements.
STMT is the scalar reduction stmt that is being vectorized.
NCOPIES is > 1 in case the vectorization factor (VF) is bigger than the
- number of elements that we can fit in a vectype (nunits). In this case
+ number of elements that we can fit in a vectype (nunits). In this case
we have to generate more than one vector stmt - i.e - we need to "unroll"
the vector stmt by a factor VF/nunits. For more details see documentation
in vectorizable_operation.
/* Get the loop-entry arguments. */
if (slp_node)
- vect_get_slp_defs (slp_node, &vec_initial_defs, NULL, reduc_index);
+ vect_get_slp_defs (reduction_op, NULL_TREE, slp_node, &vec_initial_defs,
+ NULL, reduc_index);
else
{
vec_initial_defs = VEC_alloc (tree, heap, 1);
}
/* Set phi nodes arguments. */
- for (i = 0; VEC_iterate (gimple, reduction_phis, i, phi); i++)
+ FOR_EACH_VEC_ELT (gimple, reduction_phis, i, phi)
{
tree vec_init_def = VEC_index (tree, vec_initial_defs, i);
tree def = VEC_index (tree, vect_defs, i);
exit_bb = single_exit (loop)->dest;
prev_phi_info = NULL;
new_phis = VEC_alloc (gimple, heap, VEC_length (tree, vect_defs));
- for (i = 0; VEC_iterate (tree, vect_defs, i, def); i++)
+ FOR_EACH_VEC_ELT (tree, vect_defs, i, def)
{
for (j = 0; j < ncopies; j++)
{
/* In case this is a reduction in an inner-loop while vectorizing an outer
loop - we don't need to extract a single scalar result at the end of the
inner-loop (unless it is double reduction, i.e., the use of reduction is
- outside the outer-loop). The final vector of partial results will be used
+ outside the outer-loop). The final vector of partial results will be used
in the vectorized outer-loop, or reduced to a scalar result at the end of
the outer-loop. */
if (nested_in_vect_loop && !double_reduc)
fprintf (vect_dump, "Reduce using scalar code. ");
vec_size_in_bits = tree_low_cst (TYPE_SIZE (vectype), 1);
- for (i = 0; VEC_iterate (gimple, new_phis, i, new_phi); i++)
+ FOR_EACH_VEC_ELT (gimple, new_phis, i, new_phi)
{
vec_temp = PHI_RESULT (new_phi);
rhs = build3 (BIT_FIELD_REF, scalar_type, vec_temp, bitsize,
}
/* The only case where we need to reduce scalar results in SLP, is
- unrolling. If the size of SCALAR_RESULTS is greater than
+ unrolling. If the size of SCALAR_RESULTS is greater than
GROUP_SIZE, we reduce them combining elements modulo
GROUP_SIZE. */
if (slp_node)
VEC_replace (gimple, new_phis, 0, epilog_stmt);
}
- /* 2.6 Handle the loop-exit phis. Replace the uses of scalar loop-exit
+ /* 2.6 Handle the loop-exit phis. Replace the uses of scalar loop-exit
phis with new adjusted scalar results, i.e., replace use <s_out0>
with use <s_out4>.
use <s_out4> */
/* In SLP we may have several statements in NEW_PHIS and REDUCTION_PHIS (in
- case that GROUP_SIZE is greater than vectorization factor). Therefore, we
- need to match SCALAR_RESULTS with corresponding statements. The first
+ case that GROUP_SIZE is greater than vectorization factor). Therefore, we
+ need to match SCALAR_RESULTS with corresponding statements. The first
(GROUP_SIZE / number of new vector stmts) scalar results correspond to
the first vector stmt, etc.
(RATIO is equal to (GROUP_SIZE / number of new vector stmts)). */
phis = VEC_alloc (gimple, heap, 3);
/* Find the loop-closed-use at the loop exit of the original scalar
- result. (The reduction result is expected to have two immediate uses -
+ result. (The reduction result is expected to have two immediate uses -
one at the latch block, and one at the loop exit). */
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, scalar_dest)
if (!flow_bb_inside_loop_p (loop, gimple_bb (USE_STMT (use_p))))
form. */
gcc_assert (!VEC_empty (gimple, phis));
- for (i = 0; VEC_iterate (gimple, phis, i, exit_phi); i++)
+ FOR_EACH_VEC_ELT (gimple, phis, i, exit_phi)
{
if (outer_loop)
{
vect_phi_res = PHI_RESULT (vect_phi);
/* Replace the use, i.e., set the correct vs1 in the regular
- reduction phi node. FORNOW, NCOPIES is always 1, so the
+ reduction phi node. FORNOW, NCOPIES is always 1, so the
loop is redundant. */
use = reduction_phi;
for (j = 0; j < ncopies; j++)
phis = VEC_alloc (gimple, heap, 3);
/* Find the loop-closed-use at the loop exit of the original scalar
- result. (The reduction result is expected to have two immediate uses -
- one at the latch block, and one at the loop exit). For double
+ result. (The reduction result is expected to have two immediate uses,
+ one at the latch block, and one at the loop exit). For double
reductions we are looking for exit phis of the outer loop. */
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, scalar_dest)
{
}
}
- for (i = 0; VEC_iterate (gimple, phis, i, exit_phi); i++)
+ FOR_EACH_VEC_ELT (gimple, phis, i, exit_phi)
{
/* Replace the uses: */
orig_name = PHI_RESULT (exit_phi);
Return FALSE if not a vectorizable STMT, TRUE otherwise.
This function also handles reduction idioms (patterns) that have been
- recognized in advance during vect_pattern_recog. In this case, STMT may be
+ recognized in advance during vect_pattern_recog. In this case, STMT may be
of this form:
X = pattern_expr (arg0, arg1, ..., X)
and it's STMT_VINFO_RELATED_STMT points to the last stmt in the original
Upon entry to this function, STMT_VINFO_VECTYPE records the vectype that
indicates what is the actual level of parallelism (V8HI in the example), so
- that the right vectorization factor would be derived. This vectype
+ that the right vectorization factor would be derived. This vectype
corresponds to the type of arguments to the reduction stmt, and should *NOT*
- be used to create the vectorized stmt. The right vectype for the vectorized
+ be used to create the vectorized stmt. The right vectype for the vectorized
stmt is obtained from the type of the result X:
get_vectype_for_scalar_type (TREE_TYPE (X))
VEC (tree, heap) *vec_oprnds0 = NULL, *vec_oprnds1 = NULL, *vect_defs = NULL;
VEC (gimple, heap) *phis = NULL;
int vec_num;
- tree def0, def1;
+ tree def0, def1, tem;
if (nested_in_vect_loop_p (loop, stmt))
{
gcc_assert (!STMT_VINFO_IN_PATTERN_P (stmt_info));
}
- /* 3. Check the operands of the operation. The first operands are defined
+ /* 3. Check the operands of the operation. The first operands are defined
inside the loop body. The last operand is the reduction variable,
which is defined by the loop-header-phi. */
gcc_assert (is_gimple_assign (stmt));
- /* Flatten RHS */
+ /* Flatten RHS. */
switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)))
{
case GIMPLE_SINGLE_RHS:
return false;
/* All uses but the last are expected to be defined in the loop.
- The last use is the reduction variable. In case of nested cycle this
+ The last use is the reduction variable. In case of nested cycle this
assumption is not true: we use reduc_index to record the index of the
reduction variable. */
for (i = 0; i < op_type-1; i++)
{
- tree tem;
-
/* The condition of COND_EXPR is checked in vectorizable_condition(). */
if (i == 0 && code == COND_EXPR)
continue;
}
}
- is_simple_use = vect_is_simple_use (ops[i], loop_vinfo, NULL, &def_stmt,
- &def, &dt);
+ is_simple_use = vect_is_simple_use_1 (ops[i], loop_vinfo, NULL, &def_stmt,
+ &def, &dt, &tem);
+ if (!vectype_in)
+ vectype_in = tem;
gcc_assert (is_simple_use);
gcc_assert (dt == vect_reduction_def
|| dt == vect_nested_cycle
1. The tree-code that is used to create the vector operation in the
epilog code (that reduces the partial results) is not the
tree-code of STMT, but is rather the tree-code of the original
- stmt from the pattern that STMT is replacing. I.e, in the example
+ stmt from the pattern that STMT is replacing. I.e, in the example
above we want to use 'widen_sum' in the loop, but 'plus' in the
epilog.
2. The type (mode) we use to check available target support
/* Handle uses. */
if (j == 0)
{
+ tree op0, op1 = NULL_TREE;
+
+ op0 = ops[!reduc_index];
+ if (op_type == ternary_op)
+ {
+ if (reduc_index == 0)
+ op1 = ops[2];
+ else
+ op1 = ops[1];
+ }
+
if (slp_node)
- vect_get_slp_defs (slp_node, &vec_oprnds0, &vec_oprnds1, -1);
+ vect_get_slp_defs (op0, op1, slp_node, &vec_oprnds0, &vec_oprnds1,
+ -1);
else
{
loop_vec_def0 = vect_get_vec_def_for_operand (ops[!reduc_index],
VEC_quick_push (tree, vec_oprnds0, loop_vec_def0);
if (op_type == ternary_op)
{
- if (reduc_index == 0)
- loop_vec_def1 = vect_get_vec_def_for_operand (ops[2], stmt,
- NULL);
- else
- loop_vec_def1 = vect_get_vec_def_for_operand (ops[1], stmt,
- NULL);
-
+ loop_vec_def1 = vect_get_vec_def_for_operand (op1, stmt,
+ NULL);
VEC_quick_push (tree, vec_oprnds1, loop_vec_def1);
}
}
STMT_VINFO_RELATED_STMT (prev_phi_info) = new_phi;
}
- for (i = 0; VEC_iterate (tree, vec_oprnds0, i, def0); i++)
+ FOR_EACH_VEC_ELT (tree, vec_oprnds0, i, def0)
{
if (slp_node)
reduc_def = PHI_RESULT (VEC_index (gimple, phis, i));
/* Function vectorizable_live_operation.
- STMT computes a value that is used outside the loop. Check if
+ STMT computes a value that is used outside the loop. Check if
it can be supported. */
bool
gcc_assert (rhs_class != GIMPLE_UNARY_RHS || op_type == unary_op);
gcc_assert (rhs_class != GIMPLE_BINARY_RHS || op_type == binary_op);
- /* FORNOW: support only if all uses are invariant. This means
+ /* FORNOW: support only if all uses are invariant. This means
that the scalar operations can remain in place, unvectorized.
The original last scalar value that they compute will be used. */
compile time constant), or it is a constant that doesn't divide by the
vectorization factor, then an epilog loop needs to be created.
We therefore duplicate the loop: the original loop will be vectorized,
- and will compute the first (n/VF) iterations. The second copy of the loop
+ and will compute the first (n/VF) iterations. The second copy of the loop
will remain scalar and will compute the remaining (n%VF) iterations.
(VF is the vectorization factor). */