-/* Anlaysis Utilities for Loop Vectorization.
+/* Analysis Utilities for Loop Vectorization.
Copyright (C) 2003,2004,2005 Free Software Foundation, Inc.
Contributed by Dorit Naishlos <dorit@il.ibm.com>
static bool vect_compute_data_refs_alignment (loop_vec_info);
static void vect_enhance_data_refs_alignment (loop_vec_info);
static bool vect_analyze_operations (loop_vec_info);
+static bool vect_determine_vectorization_factor (loop_vec_info);
/* Utility functions for the analyses. */
static bool exist_non_indexing_operands_for_use_p (tree, tree);
-static void vect_mark_relevant (varray_type *, tree);
+static void vect_mark_relevant (VEC(tree,heap) **, tree);
static bool vect_stmt_relevant_p (tree, loop_vec_info);
static tree vect_get_loop_niters (struct loop *, tree *);
static bool vect_analyze_data_ref_dependence
struct data_reference *drb, bool *);
static tree vect_object_analysis (tree, tree, bool, tree,
struct data_reference **, tree *, tree *,
- tree *, bool *, tree *);
+ tree *, bool *, tree *, struct ptr_info_def **,
+ subvar_t *);
static tree vect_address_analysis (tree, tree, bool, tree,
struct data_reference *, tree *, tree *,
tree *, bool *);
}
+/* Function vect_determine_vectorization_factor
+
+ 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,
+ 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
+ the size of the types operated upon, and fails if there are multiple sizes
+ in the loop.
+
+ VF is also the factor by which the loop iterations are strip-mined, e.g.:
+ original loop:
+ for (i=0; i<N; i++){
+ a[i] = b[i] + c[i];
+ }
+
+ vectorized loop:
+ for (i=0; i<N; i+=VF){
+ a[i:VF] = b[i:VF] + c[i:VF];
+ }
+*/
+
+static bool
+vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
+{
+ struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
+ basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
+ int nbbs = loop->num_nodes;
+ block_stmt_iterator si;
+ unsigned int vectorization_factor = 0;
+ int i;
+ tree scalar_type;
+
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ fprintf (vect_dump, "=== vect_determine_vectorization_factor ===");
+
+ for (i = 0; i < nbbs; i++)
+ {
+ basic_block bb = bbs[i];
+
+ for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+ {
+ tree stmt = bsi_stmt (si);
+ unsigned int nunits;
+ stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+ tree vectype;
+
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ {
+ fprintf (vect_dump, "==> examining statement: ");
+ print_generic_expr (vect_dump, stmt, TDF_SLIM);
+ }
+
+ gcc_assert (stmt_info);
+ /* skip stmts which do not need to be vectorized. */
+ if (!STMT_VINFO_RELEVANT_P (stmt_info))
+ continue;
+
+ if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (stmt))))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
+ LOOP_LOC (loop_vinfo)))
+ {
+ fprintf (vect_dump, "not vectorized: vector stmt in loop:");
+ print_generic_expr (vect_dump, stmt, TDF_SLIM);
+ }
+ return false;
+ }
+
+ if (STMT_VINFO_DATA_REF (stmt_info))
+ scalar_type = TREE_TYPE (DR_REF (STMT_VINFO_DATA_REF (stmt_info)));
+ else if (TREE_CODE (stmt) == MODIFY_EXPR)
+ scalar_type = TREE_TYPE (TREE_OPERAND (stmt, 0));
+ else
+ scalar_type = TREE_TYPE (stmt);
+
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ {
+ fprintf (vect_dump, "get vectype for scalar type: ");
+ print_generic_expr (vect_dump, scalar_type, TDF_SLIM);
+ }
+
+ vectype = get_vectype_for_scalar_type (scalar_type);
+ if (!vectype)
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
+ LOOP_LOC (loop_vinfo)))
+ {
+ fprintf (vect_dump, "not vectorized: unsupported data-type ");
+ print_generic_expr (vect_dump, scalar_type, TDF_SLIM);
+ }
+ return false;
+ }
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ {
+ fprintf (vect_dump, "vectype: ");
+ print_generic_expr (vect_dump, vectype, TDF_SLIM);
+ }
+ STMT_VINFO_VECTYPE (stmt_info) = vectype;
+
+ nunits = TYPE_VECTOR_SUBPARTS (vectype);
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ fprintf (vect_dump, "nunits = %d", nunits);
+
+ if (vectorization_factor)
+ {
+ /* FORNOW: don't allow mixed units.
+ This restriction will be relaxed in the future. */
+ if (nunits != vectorization_factor)
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
+ LOOP_LOC (loop_vinfo)))
+ fprintf (vect_dump, "not vectorized: mixed data-types");
+ return false;
+ }
+ }
+ else
+ vectorization_factor = nunits;
+
+#ifdef ENABLE_CHECKING
+ gcc_assert (GET_MODE_SIZE (TYPE_MODE (scalar_type))
+ * vectorization_factor == UNITS_PER_SIMD_WORD);
+#endif
+ }
+ }
+
+ /* TODO: Analyze cost. Decide if worth while to vectorize. */
+
+ if (vectorization_factor <= 1)
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
+ LOOP_LOC (loop_vinfo)))
+ fprintf (vect_dump, "not vectorized: unsupported data-type");
+ return false;
+ }
+ LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
+
+ return true;
+}
+
+
/* Function vect_analyze_operations.
Scan the loop stmts and make sure they are all vectorizable. */
unsigned int vectorization_factor = 0;
int i;
bool ok;
- tree scalar_type;
if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
fprintf (vect_dump, "=== vect_analyze_operations ===");
+ gcc_assert (LOOP_VINFO_VECT_FACTOR (loop_vinfo));
+ vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
+
for (i = 0; i < nbbs; i++)
{
basic_block bb = bbs[i];
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{
tree stmt = bsi_stmt (si);
- unsigned int nunits;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
- tree vectype;
if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
{
continue;
}
- if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (stmt))))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
- LOOP_LOC (loop_vinfo)))
- {
- fprintf (vect_dump, "not vectorized: vector stmt in loop:");
- print_generic_expr (vect_dump, stmt, TDF_SLIM);
- }
- return false;
- }
-
- if (STMT_VINFO_DATA_REF (stmt_info))
- scalar_type = TREE_TYPE (DR_REF (STMT_VINFO_DATA_REF (stmt_info)));
- else if (TREE_CODE (stmt) == MODIFY_EXPR)
- scalar_type = TREE_TYPE (TREE_OPERAND (stmt, 0));
- else
- scalar_type = TREE_TYPE (stmt);
-
- if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
- {
- fprintf (vect_dump, "get vectype for scalar type: ");
- print_generic_expr (vect_dump, scalar_type, TDF_SLIM);
- }
-
- vectype = get_vectype_for_scalar_type (scalar_type);
- if (!vectype)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
- LOOP_LOC (loop_vinfo)))
- {
- fprintf (vect_dump,
- "not vectorized: unsupported data-type ");
- print_generic_expr (vect_dump, scalar_type, TDF_SLIM);
- }
- return false;
- }
-
- if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
- {
- fprintf (vect_dump, "vectype: ");
- print_generic_expr (vect_dump, vectype, TDF_SLIM);
- }
- STMT_VINFO_VECTYPE (stmt_info) = vectype;
+#ifdef ENABLE_CHECKING
+ if (STMT_VINFO_RELEVANT_P (stmt_info))
+ {
+ gcc_assert (!VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (stmt))));
+ gcc_assert (STMT_VINFO_VECTYPE (stmt_info));
+ }
+#endif
ok = (vectorizable_operation (stmt, NULL, NULL)
|| vectorizable_assignment (stmt, NULL, NULL)
|| vectorizable_load (stmt, NULL, NULL)
- || vectorizable_store (stmt, NULL, NULL));
+ || vectorizable_store (stmt, NULL, NULL)
+ || vectorizable_condition (stmt, NULL, NULL));
if (!ok)
{
}
return false;
}
-
- nunits = GET_MODE_NUNITS (TYPE_MODE (vectype));
- if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
- fprintf (vect_dump, "nunits = %d", nunits);
-
- if (vectorization_factor)
- {
- /* FORNOW: don't allow mixed units.
- This restriction will be relaxed in the future. */
- if (nunits != vectorization_factor)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
- LOOP_LOC (loop_vinfo)))
- fprintf (vect_dump, "not vectorized: mixed data-types");
- return false;
- }
- }
- else
- vectorization_factor = nunits;
-
-#ifdef ENABLE_CHECKING
- gcc_assert (GET_MODE_SIZE (TYPE_MODE (scalar_type))
- * vectorization_factor == UNITS_PER_SIMD_WORD);
-#endif
}
}
/* TODO: Analyze cost. Decide if worth while to vectorize. */
- if (vectorization_factor <= 1)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
- LOOP_LOC (loop_vinfo)))
- fprintf (vect_dump, "not vectorized: unsupported data-type");
- return false;
- }
- LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
-
if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
&& vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
fprintf (vect_dump,
"not vectorized: can't create epilog loop 1.");
return false;
}
- if (!slpeel_can_duplicate_loop_p (loop, loop->exit_edges[0]))
+ if (!slpeel_can_duplicate_loop_p (loop, loop->single_exit))
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
LOOP_LOC (loop_vinfo)))
{
bool differ_p;
struct data_dependence_relation *ddr;
+ struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
+ int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
+ int dist = 0;
+ unsigned int loop_depth = 0;
+ struct loop *loop_nest = loop;
+
if (!vect_base_addr_differ_p (dra, drb, &differ_p))
{
if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
return false;
-
+
+ if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
+ LOOP_LOC (loop_vinfo)))
+ {
+ fprintf (vect_dump,
+ "not vectorized: can't determine dependence between ");
+ print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
+ fprintf (vect_dump, " and ");
+ print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
+ }
+ return true;
+ }
+
+ /* Find loop depth. */
+ while (loop_nest)
+ {
+ if (loop_nest->outer && loop_nest->outer->outer)
+ {
+ loop_nest = loop_nest->outer;
+ loop_depth++;
+ }
+ else
+ break;
+ }
+
+ /* Compute distance vector. */
+ compute_subscript_distance (ddr);
+ build_classic_dist_vector (ddr, vect_loops_num, loop_nest->depth);
+
+ if (!DDR_DIST_VECT (ddr))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
+ LOOP_LOC (loop_vinfo)))
+ {
+ fprintf (vect_dump, "not vectorized: bad dist vector for ");
+ print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
+ fprintf (vect_dump, " and ");
+ print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
+ }
+ return true;
+ }
+
+ dist = DDR_DIST_VECT (ddr)[loop_depth];
+
+ /* Same loop iteration. */
+ if (dist == 0)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS, LOOP_LOC (loop_vinfo)))
+ fprintf (vect_dump, "dependence distance 0.");
+ return false;
+ }
+
+ if (dist >= vectorization_factor)
+ /* Dependence distance does not create dependence, as far as vectorization
+ is concerned, in this case. */
+ return false;
+
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
LOOP_LOC (loop_vinfo)))
{
/* Function vect_analyze_data_ref_dependences.
Examine all the data references in the loop, and make sure there do not
- exist any data dependences between them.
-
- TODO: dependences which distance is greater than the vectorization factor
- can be ignored. */
+ exist any data dependences between them. */
static bool
vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo)
{
varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo);
varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo);
- unsigned int i;
+ varray_type datarefs;
+ struct data_reference *dr0 = NULL;
+ unsigned int i, j;
/*
This pass will require a cost model to guide it whether to apply peeling
for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
{
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
- if (!aligned_access_p (dr))
- {
- LOOP_VINFO_UNALIGNED_DR (loop_vinfo) = dr;
- LOOP_DO_PEELING_FOR_ALIGNMENT (loop_vinfo) = true;
+ dr0 = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
+ if (!aligned_access_p (dr0))
+ {
+ LOOP_VINFO_UNALIGNED_DR (loop_vinfo) = dr0;
+ LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo) = DR_MISALIGNMENT (dr0);
break;
- }
- }
-
- if (!LOOP_VINFO_UNALIGNED_DR (loop_vinfo))
- {
- if (vect_print_dump_info (REPORT_DETAILS, LOOP_LOC (loop_vinfo)))
- fprintf (vect_dump, "Peeling for alignment will not be applied.");
- return;
+ }
}
- else
- if (vect_print_dump_info (REPORT_DETAILS, LOOP_LOC (loop_vinfo)))
- fprintf (vect_dump, "Peeling for alignment will be applied.");
-
/* (1.2) Update the alignment info according to the peeling factor.
If the misalignment of the DR we peel for is M, then the
If the misalignment of the DR we peel for is unknown, then the
misalignment of each access DR_i in the loop is also unknown.
- FORNOW: set the misalignment of the accesses to unknown even
- if the peeling factor is known at compile time.
+ TODO: - consider accesses that are known to have the same
+ alignment, even if that alignment is unknown. */
- TODO: - if the peeling factor is known at compile time, use that
- when updating the misalignment info of the loop DRs.
- - consider accesses that are known to have the same
- alignment, even if that alignment is unknown. */
-
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
+ if (LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo))
{
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
- if (dr == LOOP_VINFO_UNALIGNED_DR (loop_vinfo))
+ int mis;
+ int npeel = 0;
+
+ if (known_alignment_for_access_p (dr0))
{
- DR_MISALIGNMENT (dr) = 0;
- if (vect_print_dump_info (REPORT_ALIGNMENT, LOOP_LOC (loop_vinfo)))
- fprintf (vect_dump, "Alignment of access forced using peeling.");
+ /* Since it's known at compile time, compute the number of iterations
+ in the peeled loop (the peeling factor) for use in updating
+ DR_MISALIGNMENT values. The peeling factor is the vectorization
+ factor minus the misalignment as an element count. */
+ mis = DR_MISALIGNMENT (dr0);
+ mis /= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (DR_REF (dr0))));
+ npeel = LOOP_VINFO_VECT_FACTOR (loop_vinfo) - mis;
}
- else
- DR_MISALIGNMENT (dr) = -1;
- }
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++)
- {
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i);
- if (dr == LOOP_VINFO_UNALIGNED_DR (loop_vinfo))
+
+ datarefs = loop_write_datarefs;
+ for (j = 0; j < 2; j++)
{
- DR_MISALIGNMENT (dr) = 0;
- if (vect_print_dump_info (REPORT_ALIGNMENT, LOOP_LOC (loop_vinfo)))
- fprintf (vect_dump, "Alignment of access forced using peeling.");
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
+ {
+ struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i);
+
+ if (dr == dr0)
+ continue;
+ if (known_alignment_for_access_p (dr)
+ && DR_MISALIGNMENT (dr) == DR_MISALIGNMENT (dr0))
+ DR_MISALIGNMENT (dr) = 0;
+ else if (known_alignment_for_access_p (dr)
+ && known_alignment_for_access_p (dr0))
+ {
+ int drsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (DR_REF (dr))));
+
+ DR_MISALIGNMENT (dr) += npeel * drsize;
+ DR_MISALIGNMENT (dr) %= UNITS_PER_SIMD_WORD;
+ }
+ else
+ DR_MISALIGNMENT (dr) = -1;
+ }
+ datarefs = loop_read_datarefs;
}
- else
- DR_MISALIGNMENT (dr) = -1;
+
+ DR_MISALIGNMENT (dr0) = 0;
}
}
&& (vect_print_dump_info (REPORT_ALIGNMENT, LOOP_LOC (loop_vinfo))))
fprintf (vect_dump, "Vectorizing an unaligned access.");
}
+ if (LOOP_VINFO_UNALIGNED_DR (loop_vinfo)
+ && vect_print_dump_info (REPORT_ALIGNMENT, LOOP_LOC (loop_vinfo)))
+ fprintf (vect_dump, "Alignment of access forced using peeling.");
return true;
}
return NULL;
}
- reftype = TREE_TYPE (init);
- if (!POINTER_TYPE_P (reftype))
+ if (!POINTER_TYPE_P (TREE_TYPE (init)))
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
LOOP_LOC (loop_vinfo)))
*ptr_step = fold_convert (ssizetype, step);
innertype = TREE_TYPE (reftype);
+ if (!COMPLETE_TYPE_P (innertype))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
+ LOOP_LOC (loop_vinfo)))
+ fprintf (vect_dump, "not vectorized: pointer to incomplete type.");
+ return NULL;
+ }
+
/* Check that STEP is a multiple of type size. */
if (!integer_zerop (size_binop (TRUNC_MOD_EXPR, *ptr_step,
fold_convert (ssizetype, TYPE_SIZE_UNIT (innertype)))))
tree oprnd0, oprnd1, base_address, offset_expr, base_addr0, base_addr1;
tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
tree dummy;
+ struct ptr_info_def *dummy1;
+ subvar_t dummy2;
switch (TREE_CODE (expr))
{
return base_addr0 ? base_addr0 : base_addr1;
case ADDR_EXPR:
- base_address = vect_object_analysis (TREE_OPERAND (expr, 0), stmt, is_read,
- vectype, &dr, offset, misalign, step,
- base_aligned, &dummy);
+ base_address = vect_object_analysis (TREE_OPERAND (expr, 0), stmt,
+ is_read, vectype, &dr, offset,
+ misalign, step, base_aligned,
+ &dummy, &dummy1, &dummy2);
return base_address;
case SSA_NAME:
STEP - evolution of the DR_REF in the loop
BASE_ALIGNED - indicates if BASE is aligned
MEMTAG - memory tag for aliasing purposes
+ PTR_INFO - NULL or points-to aliasing info from a pointer SSA_NAME
+ SUBVAR - Sub-variables of the variable
If something unexpected is encountered (an unsupported form of data-ref),
then NULL_TREE is returned. */
vect_object_analysis (tree memref, tree stmt, bool is_read,
tree vectype, struct data_reference **dr,
tree *offset, tree *misalign, tree *step,
- bool *base_aligned, tree *memtag)
+ bool *base_aligned, tree *memtag,
+ struct ptr_info_def **ptr_info, subvar_t *subvars)
{
tree base = NULL_TREE, base_address = NULL_TREE;
tree object_offset = ssize_int (0), object_misalign = ssize_int (0);
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
struct data_reference *ptr_dr = NULL;
tree access_fn, evolution_part, address_to_analyze;
+
+ *ptr_info = NULL;
/* Part 1: */
/* Case 1. handled_component_p refs. */
us to object. */
DR_BASE_NAME ((*dr)) = memref;
+ if (SSA_VAR_P (memref) && var_can_have_subvars (memref))
+ *subvars = get_subvars_for_var (memref);
base_address = build_fold_addr_expr (memref);
*memtag = memref;
}
/* Part 1: Case 3. INDIRECT_REFs. */
else if (TREE_CODE (memref) == INDIRECT_REF)
- {
+ {
+ tree ptr_ref = TREE_OPERAND (memref, 0);
+ if (TREE_CODE (ptr_ref) == SSA_NAME)
+ *ptr_info = SSA_NAME_PTR_INFO (ptr_ref);
+
/* 3.1 get the access function. */
- access_fn = analyze_scalar_evolution (loop, TREE_OPERAND (memref, 0));
+ access_fn = analyze_scalar_evolution (loop, ptr_ref);
if (!access_fn)
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
fprintf (vect_dump, "not vectorized: ptr is loop invariant.");
return NULL_TREE;
}
- /* Since there exists DR for MEMREF, we are analyzing the base of
- handled component, which not necessary has evolution in the
+ /* Since there exists DR for MEMREF, we are analyzing the init of
+ the access function, which not necessary has evolution in the
loop. */
- address_to_analyze = TREE_OPERAND (base, 0);
+ address_to_analyze = initial_condition_in_loop_num (access_fn,
+ loop->num);
}
/* 3.3 set data-reference structure for MEMREF. */
/* MEMREF cannot be analyzed. */
return NULL_TREE;
+ if (SSA_VAR_P (*memtag) && var_can_have_subvars (*memtag))
+ *subvars = get_subvars_for_var (*memtag);
+
/* Part 2: Combine the results of object and address analysis to calculate
- INITIAL_OFFSET, STEP and misalignment info. */
+ INITIAL_OFFSET, STEP and misalignment info. */
*offset = size_binop (PLUS_EXPR, object_offset, address_offset);
if (object_misalign && address_misalign)
*misalign = size_binop (PLUS_EXPR, object_misalign, address_misalign);
Call get_inner_reference for refs handled in this function.
Call vect_addr_analysis(addr) to analyze pointer type expressions.
Set ref_stmt.base, ref_stmt.initial_offset, ref_stmt.alignment,
- ref_stmt.memtag and ref_stmt.step accordingly.
+ ref_stmt.memtag, ref_stmt.ptr_info and ref_stmt.step accordingly.
2- vect_analyze_dependences(): apply dependence testing using ref_stmt.DR
3- vect_analyze_drs_alignment(): check that ref_stmt.alignment is ok.
4- vect_analyze_drs_access(): check that ref_stmt.step is ok.
bool is_read = false;
tree stmt = bsi_stmt (si);
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
- 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);
varray_type *datarefs = NULL;
- int nvuses, nv_may_defs, nv_must_defs;
tree memref = NULL;
tree scalar_type, vectype;
tree base, offset, misalign, step, tag;
+ struct ptr_info_def *ptr_info;
bool base_aligned;
+ subvar_t subvars = NULL;
+ bool no_vuse, no_vmaymust;
/* Assumption: there exists a data-ref in stmt, if and only if
it has vuses/vdefs. */
- if (!vuses && !v_may_defs && !v_must_defs)
+ no_vuse = ZERO_SSA_OPERANDS (stmt, SSA_OP_VUSE);
+ no_vmaymust = ZERO_SSA_OPERANDS (stmt,
+ SSA_OP_VMAYDEF | SSA_OP_VMUSTDEF);
+ if (no_vuse && no_vmaymust)
continue;
- nvuses = NUM_VUSES (vuses);
- nv_may_defs = NUM_V_MAY_DEFS (v_may_defs);
- nv_must_defs = NUM_V_MUST_DEFS (v_must_defs);
-
- if (nvuses && (nv_may_defs || nv_must_defs))
+ if (!no_vuse && !no_vmaymust)
{
if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
{
return false;
}
- if (vuses)
+ if (!no_vuse)
{
memref = TREE_OPERAND (stmt, 1);
datarefs = &(LOOP_VINFO_DATAREF_READS (loop_vinfo));
dr = NULL;
base = vect_object_analysis (memref, stmt, is_read, vectype, &dr,
&offset, &misalign, &step,
- &base_aligned, &tag);
+ &base_aligned, &tag, &ptr_info,
+ &subvars);
if (!base)
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
STMT_VINFO_VECT_MISALIGNMENT (stmt_info) = misalign;
STMT_VINFO_VECT_BASE_ALIGNED_P (stmt_info) = base_aligned;
STMT_VINFO_MEMTAG (stmt_info) = tag;
+ STMT_VINFO_PTR_INFO (stmt_info) = ptr_info;
+ STMT_VINFO_SUBVARS (stmt_info) = subvars;
STMT_VINFO_VECTYPE (stmt_info) = vectype;
VARRAY_PUSH_GENERIC_PTR (*datarefs, dr);
STMT_VINFO_DATA_REF (stmt_info) = dr;
Mark STMT as "relevant for vectorization" and add it to WORKLIST. */
static void
-vect_mark_relevant (varray_type *worklist, tree stmt)
+vect_mark_relevant (VEC(tree,heap) **worklist, tree stmt)
{
stmt_vec_info stmt_info;
if (TREE_CODE (stmt) == PHI_NODE)
{
- VARRAY_PUSH_TREE (*worklist, stmt);
+ VEC_safe_push (tree, heap, *worklist, stmt);
return;
}
}
STMT_VINFO_RELEVANT_P (stmt_info) = 1;
- VARRAY_PUSH_TREE (*worklist, stmt);
+ VEC_safe_push (tree, heap, *worklist, stmt);
}
static bool
vect_stmt_relevant_p (tree stmt, loop_vec_info loop_vinfo)
{
- v_may_def_optype v_may_defs;
- v_must_def_optype v_must_defs;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- int i;
- dataflow_t df;
- int num_uses;
+ ssa_op_iter op_iter;
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ def_operand_p def_p;
/* cond stmt other than loop exit cond. */
if (is_ctrl_stmt (stmt) && (stmt != LOOP_VINFO_EXIT_COND (loop_vinfo)))
/* changing memory. */
if (TREE_CODE (stmt) != PHI_NODE)
- {
- v_may_defs = STMT_V_MAY_DEF_OPS (stmt);
- v_must_defs = STMT_V_MUST_DEF_OPS (stmt);
- if (v_may_defs || v_must_defs)
- {
- if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
- fprintf (vect_dump, "vec_stmt_relevant_p: stmt has vdefs.");
- return true;
- }
- }
+ if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_DEFS))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ fprintf (vect_dump, "vec_stmt_relevant_p: stmt has vdefs.");
+ return true;
+ }
/* uses outside the loop. */
- df = get_immediate_uses (stmt);
- num_uses = num_immediate_uses (df);
- for (i = 0; i < num_uses; i++)
+ FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
{
- tree use = immediate_use (df, i);
- basic_block bb = bb_for_stmt (use);
- if (!flow_bb_inside_loop_p (loop, bb))
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
{
- if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
- fprintf (vect_dump, "vec_stmt_relevant_p: used out of loop.");
- return true;
+ basic_block bb = bb_for_stmt (USE_STMT (use_p));
+ if (!flow_bb_inside_loop_p (loop, bb))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
+ fprintf (vect_dump, "vec_stmt_relevant_p: used out of loop.");
+ return true;
+ }
}
}
static bool
vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
{
- varray_type worklist;
+ VEC(tree,heap) *worklist;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
unsigned int nbbs = loop->num_nodes;
block_stmt_iterator si;
- tree stmt;
- stmt_ann_t ann;
+ tree stmt, use;
+ ssa_op_iter iter;
unsigned int i;
int j;
- use_optype use_ops;
stmt_vec_info stmt_info;
basic_block bb;
tree phi;
}
}
- VARRAY_TREE_INIT (worklist, 64, "work list");
+ worklist = VEC_alloc (tree, heap, 64);
/* 1. Init worklist. */
/* 2. Process_worklist */
- while (VARRAY_ACTIVE_SIZE (worklist) > 0)
+ while (VEC_length (tree, worklist) > 0)
{
- stmt = VARRAY_TOP_TREE (worklist);
- VARRAY_POP (worklist);
+ stmt = VEC_pop (tree, worklist);
if (vect_print_dump_info (REPORT_DETAILS, UNKNOWN_LOC))
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
LOOP_LOC (loop_vinfo)))
fprintf (vect_dump, "not vectorized: unsupported use in stmt.");
- varray_clear (worklist);
+ VEC_free (tree, heap, worklist);
return false;
}
if (!def_stmt)
}
}
- ann = stmt_ann (stmt);
- use_ops = USE_OPS (ann);
-
- for (i = 0; i < NUM_USES (use_ops); i++)
+ FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
{
- tree use = USE_OP (use_ops, i);
/* We are only interested in uses that need to be vectorized. Uses
that are used for address computation are not considered relevant.
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
LOOP_LOC (loop_vinfo)))
fprintf (vect_dump, "not vectorized: unsupported use in stmt.");
- varray_clear (worklist);
+ VEC_free (tree, heap, worklist);
return false;
}
}
} /* while worklist */
- varray_clear (worklist);
+ VEC_free (tree, heap, worklist);
return true;
}
loop_vec_info loop_vinfo;
tree loop_cond;
tree number_of_iterations = NULL;
- bool rescan = false;
LOC loop_loc;
loop_loc = find_loop_location (loop);
if (!loop->single_exit
|| loop->num_nodes != 2
- || EDGE_COUNT (loop->header->preds) != 2
- || loop->num_entries != 1)
+ || EDGE_COUNT (loop->header->preds) != 2)
{
if (vect_print_dump_info (REPORT_BAD_FORM_LOOPS, loop_loc))
{
fprintf (vect_dump, "not vectorized: too many BBs in loop.");
else if (EDGE_COUNT (loop->header->preds) != 2)
fprintf (vect_dump, "not vectorized: too many incoming edges.");
- else if (loop->num_entries != 1)
- fprintf (vect_dump, "not vectorized: too many entries.");
}
return NULL;
return NULL;
}
- /* Make sure we have a preheader basic block. */
- if (!loop->pre_header)
- {
- rescan = true;
- loop_split_edge_with (loop_preheader_edge (loop), NULL);
- }
-
/* Make sure there exists a single-predecessor exit bb: */
- if (EDGE_COUNT (loop->exit_edges[0]->dest->preds) != 1)
- {
- rescan = true;
- loop_split_edge_with (loop->exit_edges[0], NULL);
- }
-
- if (rescan)
+ if (!single_pred_p (loop->single_exit->dest))
{
- flow_loop_scan (loop, LOOP_ALL);
- /* Flow loop scan does not update loop->single_exit field. */
- loop->single_exit = loop->exit_edges[0];
+ edge e = loop->single_exit;
+ if (!(e->flags & EDGE_ABNORMAL))
+ {
+ split_loop_exit_edge (e);
+ if (vect_print_dump_info (REPORT_DETAILS, loop_loc))
+ fprintf (vect_dump, "split exit edge.");
+ }
+ else
+ {
+ if (vect_print_dump_info (REPORT_BAD_FORM_LOOPS, loop_loc))
+ fprintf (vect_dump, "not vectorized: abnormal loop exit edge.");
+ return NULL;
+ }
}
if (empty_block_p (loop->header))
return NULL;
}
+ ok = vect_determine_vectorization_factor (loop_vinfo);
+ if (!ok)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS, LOOP_LOC (loop_vinfo)))
+ fprintf (vect_dump, "can't determine vectorization factor.");
+ destroy_loop_vec_info (loop_vinfo);
+ return NULL;
+ }
+
/* Analyze data dependences between the data-refs in the loop.
FORNOW: fail at the first data dependence that we encounter. */