-/* 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);
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 = 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;
+
+ 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)
}
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)))
{
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;
+
+ /* Sigh, a hack to make targets that do not define UNITS_PER_SIMD_WORD
+ bootstrap. Copy UNITS_PER_SIMD_WORD to a local variable to avoid a
+ "division by zero" error. This error would be issued because we
+ we do "... % UNITS_PER_SIMD_WORD" below, and UNITS_PER_SIMD_WORD
+ defaults to 0 if it is not defined by the target. */
+ int units_per_simd_word = UNITS_PER_SIMD_WORD;
/*
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
peeling factor is VF - M, and the misalignment of each access DR_i
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.
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;
/* Assumption: there exists a data-ref in stmt, if and only if
it has vuses/vdefs. */
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;
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)
+ if (!single_pred_p (loop->single_exit->dest))
{
- rescan = true;
- loop_split_edge_with (loop->exit_edges[0], NULL);
- }
-
- if (rescan)
- {
- 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))
+ {
+ loop_split_edge_with (e, NULL);
+ 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 the alignment of the data-refs in the loop.
FORNOW: Only aligned accesses are handled. */