static tree vect_init_vector (tree, tree);
static void vect_finish_stmt_generation
(tree stmt, tree vec_stmt, block_stmt_iterator *bsi);
+static void update_vuses_to_preheader (tree, struct loop*);
/* Utility function dealing with loop peeling (not peeling itself). */
static void vect_generate_tmps_on_preheader
static tree vect_build_loop_niters (loop_vec_info);
static void vect_update_ivs_after_vectorizer (loop_vec_info, tree, edge);
static tree vect_gen_niters_for_prolog_loop (loop_vec_info, tree);
-static void vect_update_inits_of_dr (struct data_reference *, tree niters);
+static void vect_update_init_of_dr (struct data_reference *, tree niters);
static void vect_update_inits_of_drs (loop_vec_info, tree);
static void vect_do_peeling_for_alignment (loop_vec_info, struct loops *);
static void vect_do_peeling_for_loop_bound
tree vect_ptr_type;
tree vect_ptr;
tree tag;
- v_may_def_optype v_may_defs = STMT_V_MAY_DEF_OPS (stmt);
- v_must_def_optype v_must_defs = STMT_V_MUST_DEF_OPS (stmt);
- vuse_optype vuses = STMT_VUSE_OPS (stmt);
- int nvuses, nv_may_defs, nv_must_defs;
- int i;
tree new_temp;
tree vec_stmt;
tree new_stmt_list = NULL_TREE;
add_referenced_tmp_var (vect_ptr);
- /** (2) Handle aliasing information of the new vector-pointer: **/
+ /** (2) Add aliasing information to the new vector-pointer:
+ (The points-to info (SSA_NAME_PTR_INFO) may be defined later.) **/
tag = STMT_VINFO_MEMTAG (stmt_info);
gcc_assert (tag);
get_var_ann (vect_ptr)->type_mem_tag = tag;
get_var_ann (vect_ptr)->subvars = STMT_VINFO_SUBVARS (stmt_info);
- /* Mark for renaming all aliased variables
- (i.e, the may-aliases of the type-mem-tag). */
- nvuses = NUM_VUSES (vuses);
- nv_may_defs = NUM_V_MAY_DEFS (v_may_defs);
- nv_must_defs = NUM_V_MUST_DEFS (v_must_defs);
-
- for (i = 0; i < nvuses; i++)
- {
- tree use = VUSE_OP (vuses, i);
- if (TREE_CODE (use) == SSA_NAME)
- bitmap_set_bit (vars_to_rename, var_ann (SSA_NAME_VAR (use))->uid);
- }
- for (i = 0; i < nv_may_defs; i++)
- {
- tree def = V_MAY_DEF_RESULT (v_may_defs, i);
- if (TREE_CODE (def) == SSA_NAME)
- bitmap_set_bit (vars_to_rename, var_ann (SSA_NAME_VAR (def))->uid);
- }
- for (i = 0; i < nv_must_defs; i++)
- {
- tree def = V_MUST_DEF_RESULT (v_must_defs, i);
- if (TREE_CODE (def) == SSA_NAME)
- bitmap_set_bit (vars_to_rename, var_ann (SSA_NAME_VAR (def))->uid);
- }
-
/** (3) Calculate the initial address the vector-pointer, and set
the vector-pointer to point to it before the loop: **/
/** (4) Handle the updating of the vector-pointer inside the loop: **/
if (only_init) /* No update in loop is required. */
- return vect_ptr_init;
+ {
+ /* Copy the points-to information if it exists. */
+ if (STMT_VINFO_PTR_INFO (stmt_info))
+ duplicate_ssa_name_ptr_info (vect_ptr_init,
+ STMT_VINFO_PTR_INFO (stmt_info));
+ return vect_ptr_init;
+ }
idx = vect_create_index_for_vector_ref (loop_vinfo);
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
data_ref_ptr = TREE_OPERAND (vec_stmt, 0);
+ /* Copy the points-to information if it exists. */
+ if (STMT_VINFO_PTR_INFO (stmt_info))
+ duplicate_ssa_name_ptr_info (data_ref_ptr, STMT_VINFO_PTR_INFO (stmt_info));
return data_ref_ptr;
}
enum machine_mode vec_mode;
tree dummy;
enum dr_alignment_support alignment_support_cheme;
+ v_may_def_optype v_may_defs;
+ int nv_may_defs, i;
/* Is vectorizable store? */
alignment_support_cheme = vect_supportable_dr_alignment (dr);
gcc_assert (alignment_support_cheme);
- gcc_assert (alignment_support_cheme = dr_aligned); /* FORNOW */
+ gcc_assert (alignment_support_cheme == dr_aligned); /* FORNOW */
/* Handle use - get the vectorized def from the defining stmt. */
vec_oprnd1 = vect_get_vec_def_for_operand (op, stmt);
*vec_stmt = build2 (MODIFY_EXPR, vectype, data_ref, vec_oprnd1);
vect_finish_stmt_generation (stmt, *vec_stmt, bsi);
+ /* Copy the V_MAY_DEFS representing the aliasing of the original array
+ element's definition to the vector's definition then update the
+ defining statement. The original is being deleted so the same
+ SSA_NAMEs can be used. */
+ copy_virtual_operands (*vec_stmt, stmt);
+ v_may_defs = STMT_V_MAY_DEF_OPS (*vec_stmt);
+ nv_may_defs = NUM_V_MAY_DEFS (v_may_defs);
+
+ for (i = 0; i < nv_may_defs; i++)
+ {
+ tree ssa_name = V_MAY_DEF_RESULT (v_may_defs, i);
+ SSA_NAME_DEF_STMT (ssa_name) = *vec_stmt;
+ }
+
return true;
}
new_temp = make_ssa_name (vec_dest, new_stmt);
TREE_OPERAND (new_stmt, 0) = new_temp;
vect_finish_stmt_generation (stmt, new_stmt, bsi);
+ copy_virtual_operands (new_stmt, stmt);
}
else if (alignment_support_cheme == dr_unaligned_software_pipeline)
{
new_bb = bsi_insert_on_edge_immediate (pe, new_stmt);
gcc_assert (!new_bb);
msq_init = TREE_OPERAND (new_stmt, 0);
+ copy_virtual_operands (new_stmt, stmt);
+ update_vuses_to_preheader (new_stmt, loop);
/* <2> Create lsq = *(floor(p2')) in the loop */
TREE_OPERAND (new_stmt, 0) = new_temp;
vect_finish_stmt_generation (stmt, new_stmt, bsi);
lsq = TREE_OPERAND (new_stmt, 0);
+ copy_virtual_operands (new_stmt, stmt);
/* <3> */
gcc_assert (!new_bb);
magic = TREE_OPERAND (new_stmt, 0);
- /* Since we have just created a CALL_EXPR, we may need to
- rename call-clobbered variables. */
- mark_call_clobbered_vars_to_rename ();
+ /* The result of the CALL_EXPR to this builtin is determined from
+ the value of the parameter and no global variables are touched
+ which makes the builtin a "const" function. Requiring the
+ builtin to have the "const" attribute makes it unnecessary
+ to call mark_call_clobbered_vars_to_rename. */
+ gcc_assert (TREE_READONLY (builtin_decl));
}
else
{
}
+/* Function update_vuses_to_preheader.
+
+ Input:
+ STMT - a statement with potential VUSEs.
+ LOOP - the loop whose preheader will contain STMT.
+
+ It's possible to vectorize a loop even though an SSA_NAME from a VUSE
+ appears to be defined in a V_MAY_DEF in another statement in a loop.
+ One such case is when the VUSE is at the dereference of a __restricted__
+ pointer in a load and the V_MAY_DEF is at the dereference of a different
+ __restricted__ pointer in a store. Vectorization may result in
+ copy_virtual_uses being called to copy the problematic VUSE to a new
+ statement that is being inserted in the loop preheader. This procedure
+ is called to change the SSA_NAME in the new statement's VUSE from the
+ SSA_NAME updated in the loop to the related SSA_NAME available on the
+ path entering the loop.
+
+ When this function is called, we have the following situation:
+
+ # vuse <name1>
+ S1: vload
+ do {
+ # name1 = phi < name0 , name2>
+
+ # vuse <name1>
+ S2: vload
+
+ # name2 = vdef <name1>
+ S3: vstore
+
+ }while...
+
+ Stmt S1 was created in the loop preheader block as part of misaligned-load
+ handling. This function fixes the name of the vuse of S1 from 'name1' to
+ 'name0'. */
+
+static void
+update_vuses_to_preheader (tree stmt, struct loop *loop)
+{
+ basic_block header_bb = loop->header;
+ edge preheader_e = loop_preheader_edge (loop);
+ vuse_optype vuses = STMT_VUSE_OPS (stmt);
+ int nvuses = NUM_VUSES (vuses);
+ int i;
+
+ for (i = 0; i < nvuses; i++)
+ {
+ tree ssa_name = VUSE_OP (vuses, i);
+ tree def_stmt = SSA_NAME_DEF_STMT (ssa_name);
+ tree name_var = SSA_NAME_VAR (ssa_name);
+ basic_block bb = bb_for_stmt (def_stmt);
+
+ /* For a use before any definitions, def_stmt is a NOP_EXPR. */
+ if (!IS_EMPTY_STMT (def_stmt)
+ && flow_bb_inside_loop_p (loop, bb))
+ {
+ /* If the block containing the statement defining the SSA_NAME
+ is in the loop then it's necessary to find the definition
+ outside the loop using the PHI nodes of the header. */
+ tree phi;
+ bool updated = false;
+
+ for (phi = phi_nodes (header_bb); phi; phi = TREE_CHAIN (phi))
+ {
+ if (SSA_NAME_VAR (PHI_RESULT (phi)) == name_var)
+ {
+ SET_VUSE_OP (vuses, i,
+ PHI_ARG_DEF (phi, preheader_e->dest_idx));
+ updated = true;
+ break;
+ }
+ }
+ gcc_assert (updated);
+ }
+ }
+}
+
+
/* Function vect_update_ivs_after_vectorizer.
"Advance" the induction variables of LOOP to the value they should take
Set the number of iterations for the loop represented by LOOP_VINFO
to the minimum between LOOP_NITERS (the original iteration count of the loop)
- and the misalignment of DR - the first data reference recorded in
+ and the misalignment of DR - the data reference recorded in
LOOP_VINFO_UNALIGNED_DR (LOOP_VINFO). As a result, after the execution of
this loop, the data reference DR will refer to an aligned location.
The following computation is generated:
- compute address misalignment in bytes:
- addr_mis = addr & (vectype_size - 1)
+ If the misalignment of DR is known at compile time:
+ addr_mis = int mis = DR_MISALIGNMENT (dr);
+ Else, compute address misalignment in bytes:
+ addr_mis = addr & (vectype_size - 1)
prolog_niters = min ( LOOP_NITERS , (VF - addr_mis/elem_size)&(VF-1) )
stmt_vec_info stmt_info = vinfo_for_stmt (dr_stmt);
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
int vectype_align = TYPE_ALIGN (vectype) / BITS_PER_UNIT;
- tree elem_misalign;
- tree byte_misalign;
- tree new_stmts = NULL_TREE;
- tree start_addr =
- vect_create_addr_base_for_vector_ref (dr_stmt, &new_stmts, NULL_TREE);
- tree ptr_type = TREE_TYPE (start_addr);
- tree size = TYPE_SIZE (ptr_type);
- tree type = lang_hooks.types.type_for_size (tree_low_cst (size, 1), 1);
- tree vectype_size_minus_1 = build_int_cst (type, vectype_align - 1);
tree vf_minus_1 = build_int_cst (unsigned_type_node, vf - 1);
tree niters_type = TREE_TYPE (loop_niters);
- tree elem_size_log =
- build_int_cst (unsigned_type_node, exact_log2 (vectype_align/vf));
- tree vf_tree = build_int_cst (unsigned_type_node, vf);
pe = loop_preheader_edge (loop);
- new_bb = bsi_insert_on_edge_immediate (pe, new_stmts);
- gcc_assert (!new_bb);
- /* Create: byte_misalign = addr & (vectype_size - 1) */
- byte_misalign = build2 (BIT_AND_EXPR, type, start_addr, vectype_size_minus_1);
+ if (LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo) > 0)
+ {
+ int byte_misalign = LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo);
+ int element_size = vectype_align/vf;
+ int elem_misalign = byte_misalign / element_size;
- /* Create: elem_misalign = byte_misalign / element_size */
- elem_misalign =
- build2 (RSHIFT_EXPR, unsigned_type_node, byte_misalign, elem_size_log);
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ fprintf (vect_dump, "known alignment = %d.", byte_misalign);
+ iters = build_int_cst (niters_type, (vf - elem_misalign)&(vf-1));
+ }
+ else
+ {
+ tree new_stmts = NULL_TREE;
+ tree start_addr =
+ vect_create_addr_base_for_vector_ref (dr_stmt, &new_stmts, NULL_TREE);
+ tree ptr_type = TREE_TYPE (start_addr);
+ tree size = TYPE_SIZE (ptr_type);
+ tree type = lang_hooks.types.type_for_size (tree_low_cst (size, 1), 1);
+ tree vectype_size_minus_1 = build_int_cst (type, vectype_align - 1);
+ tree elem_size_log =
+ build_int_cst (unsigned_type_node, exact_log2 (vectype_align/vf));
+ tree vf_tree = build_int_cst (unsigned_type_node, vf);
+ tree byte_misalign;
+ tree elem_misalign;
+
+ new_bb = bsi_insert_on_edge_immediate (pe, new_stmts);
+ gcc_assert (!new_bb);
- /* Create: (niters_type) (VF - elem_misalign)&(VF - 1) */
- iters = build2 (MINUS_EXPR, unsigned_type_node, vf_tree, elem_misalign);
- iters = build2 (BIT_AND_EXPR, unsigned_type_node, iters, vf_minus_1);
- iters = fold_convert (niters_type, iters);
+ /* Create: byte_misalign = addr & (vectype_size - 1) */
+ byte_misalign =
+ build2 (BIT_AND_EXPR, type, start_addr, vectype_size_minus_1);
+ /* Create: elem_misalign = byte_misalign / element_size */
+ elem_misalign =
+ build2 (RSHIFT_EXPR, unsigned_type_node, byte_misalign, elem_size_log);
+
+ /* Create: (niters_type) (VF - elem_misalign)&(VF - 1) */
+ iters = build2 (MINUS_EXPR, unsigned_type_node, vf_tree, elem_misalign);
+ iters = build2 (BIT_AND_EXPR, unsigned_type_node, iters, vf_minus_1);
+ iters = fold_convert (niters_type, iters);
+ }
+
/* Create: prolog_loop_niters = min (iters, loop_niters) */
/* If the loop bound is known at compile time we already verified that it is
greater than vf; since the misalignment ('iters') is at most vf, there's
if (TREE_CODE (loop_niters) != INTEGER_CST)
iters = build2 (MIN_EXPR, niters_type, iters, loop_niters);
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ {
+ fprintf (vect_dump, "niters for prolog loop: ");
+ print_generic_expr (vect_dump, iters, TDF_SLIM);
+ }
+
var = create_tmp_var (niters_type, "prolog_loop_niters");
add_referenced_tmp_var (var);
iters_name = force_gimple_operand (iters, &stmt, false, var);
/* Insert stmt on loop preheader edge. */
- pe = loop_preheader_edge (loop);
if (stmt)
{
basic_block new_bb = bsi_insert_on_edge_immediate (pe, stmt);
}
-/* Function vect_update_inits_of_dr
+/* Function vect_update_init_of_dr
NITERS iterations were peeled from LOOP. DR represents a data reference
in LOOP. This function updates the information recorded in DR to
executed. Specifically, it updates the OFFSET field of stmt_info. */
static void
-vect_update_inits_of_dr (struct data_reference *dr, tree niters)
+vect_update_init_of_dr (struct data_reference *dr, tree niters)
{
stmt_vec_info stmt_info = vinfo_for_stmt (DR_STMT (dr));
tree offset = STMT_VINFO_VECT_INIT_OFFSET (stmt_info);
for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
{
struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
- vect_update_inits_of_dr (dr, niters);
+ vect_update_init_of_dr (dr, niters);
}
for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++)
{
struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i);
- vect_update_inits_of_dr (dr, niters);
+ vect_update_init_of_dr (dr, niters);
}
}
/* Update number of times loop executes. */
n_iters = LOOP_VINFO_NITERS (loop_vinfo);
- LOOP_VINFO_NITERS (loop_vinfo) =
- build2 (MINUS_EXPR, TREE_TYPE (n_iters), n_iters, niters_of_prolog_loop);
+ LOOP_VINFO_NITERS (loop_vinfo) = fold (build2 (MINUS_EXPR,
+ TREE_TYPE (n_iters), n_iters, niters_of_prolog_loop));
/* Update the init conditions of the access functions of all data refs. */
vect_update_inits_of_drs (loop_vinfo, niters_of_prolog_loop);
/* Peel the loop if there are data refs with unknown alignment.
Only one data ref with unknown store is allowed. */
- if (LOOP_DO_PEELING_FOR_ALIGNMENT (loop_vinfo))
+ if (LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo))
vect_do_peeling_for_alignment (loop_vinfo, loops);
/* If the loop has a symbolic number of iterations 'n' (i.e. it's not a