}
/* { dg-final { scan-tree-dump "basic block vectorized" "slp2" { target vect_perm } } } */
-/* { dg-final { scan-tree-dump-times "basic block part vectorized" 2 "slp2" { target vect_perm } } } */
+/* { dg-final { scan-tree-dump "basic block part vectorized" "slp2" { target vect_perm } } } */
--- /dev/null
+/* { dg-require-effective-target vect_double } */
+
+#include "tree-vect.h"
+
+extern void abort (void);
+
+double a[8], b[8];
+int x;
+
+void __attribute__((noinline,noclone))
+bar (void)
+{
+ x = 1;
+}
+
+void __attribute__((noinline,noclone))
+foo(int i)
+{
+ double tem1 = a[2*i];
+ double tem2 = 2*a[2*i+1];
+ bar ();
+ b[2*i] = 2*tem1;
+ b[2*i+1] = tem2;
+}
+
+int main()
+{
+ int i;
+ check_vect ();
+ for (i = 0; i < 8; ++i)
+ b[i] = i;
+ foo (2);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "basic block vectorized" "slp2" } } */
return vect_analyze_group_access (vinfo, dr_info);
}
+typedef std::pair<data_reference_p, int> data_ref_pair;
+
/* Compare two data-references DRA and DRB to group them into chunks
suitable for grouping. */
static int
dr_group_sort_cmp (const void *dra_, const void *drb_)
{
- data_reference_p dra = *(data_reference_p *)const_cast<void *>(dra_);
- data_reference_p drb = *(data_reference_p *)const_cast<void *>(drb_);
+ data_ref_pair dra_pair = *(data_ref_pair *)const_cast<void *>(dra_);
+ data_ref_pair drb_pair = *(data_ref_pair *)const_cast<void *>(drb_);
+ data_reference_p dra = dra_pair.first;
+ data_reference_p drb = drb_pair.first;
int cmp;
/* Stabilize sort. */
if (dra == drb)
return 0;
- /* DRs in different loops never belong to the same group. */
- loop_p loopa = gimple_bb (DR_STMT (dra))->loop_father;
- loop_p loopb = gimple_bb (DR_STMT (drb))->loop_father;
- if (loopa != loopb)
- return loopa->num < loopb->num ? -1 : 1;
+ /* DRs in different basic-blocks never belong to the same group. */
+ int bb_index1 = gimple_bb (DR_STMT (dra))->index;
+ int bb_index2 = gimple_bb (DR_STMT (drb))->index;
+ if (bb_index1 != bb_index2)
+ return bb_index1 < bb_index2 ? -1 : 1;
+
+ /* Different group IDs lead never belong to the same group. */
+ if (dra_pair.second != drb_pair.second)
+ return dra_pair.second < drb_pair.second ? -1 : 1;
/* Ordering of DRs according to base. */
cmp = data_ref_compare_tree (DR_BASE_ADDRESS (dra),
FORNOW: handle only arrays and pointer accesses. */
opt_result
-vect_analyze_data_ref_accesses (vec_info *vinfo)
+vect_analyze_data_ref_accesses (vec_info *vinfo,
+ vec<int> *dataref_groups)
{
unsigned int i;
vec<data_reference_p> datarefs = vinfo->shared->datarefs;
- struct data_reference *dr;
DUMP_VECT_SCOPE ("vect_analyze_data_ref_accesses");
/* Sort the array of datarefs to make building the interleaving chains
linear. Don't modify the original vector's order, it is needed for
determining what dependencies are reversed. */
- vec<data_reference_p> datarefs_copy = datarefs.copy ();
+ vec<data_ref_pair> datarefs_copy;
+ datarefs_copy.create (datarefs.length ());
+ for (unsigned i = 0; i < datarefs.length (); i++)
+ {
+ int group_id = dataref_groups ? (*dataref_groups)[i] : 0;
+ datarefs_copy.quick_push (data_ref_pair (datarefs[i], group_id));
+ }
datarefs_copy.qsort (dr_group_sort_cmp);
hash_set<stmt_vec_info> to_fixup;
/* Build the interleaving chains. */
for (i = 0; i < datarefs_copy.length () - 1;)
{
- data_reference_p dra = datarefs_copy[i];
+ data_reference_p dra = datarefs_copy[i].first;
+ int dra_group_id = datarefs_copy[i].second;
dr_vec_info *dr_info_a = vinfo->lookup_dr (dra);
stmt_vec_info stmtinfo_a = dr_info_a->stmt;
stmt_vec_info lastinfo = NULL;
}
for (i = i + 1; i < datarefs_copy.length (); ++i)
{
- data_reference_p drb = datarefs_copy[i];
+ data_reference_p drb = datarefs_copy[i].first;
+ int drb_group_id = datarefs_copy[i].second;
dr_vec_info *dr_info_b = vinfo->lookup_dr (drb);
stmt_vec_info stmtinfo_b = dr_info_b->stmt;
if (!STMT_VINFO_VECTORIZABLE (stmtinfo_b)
matters we can push those to a worklist and re-iterate
over them. The we can just skip ahead to the next DR here. */
- /* DRs in a different loop should not be put into the same
+ /* DRs in a different BBs should not be put into the same
interleaving group. */
- if (gimple_bb (DR_STMT (dra))->loop_father
- != gimple_bb (DR_STMT (drb))->loop_father)
+ int bb_index1 = gimple_bb (DR_STMT (dra))->index;
+ int bb_index2 = gimple_bb (DR_STMT (drb))->index;
+ if (bb_index1 != bb_index2)
+ break;
+
+ if (dra_group_id != drb_group_id)
break;
/* Check that the data-refs have same first location (except init)
HOST_WIDE_INT init_a = TREE_INT_CST_LOW (DR_INIT (dra));
HOST_WIDE_INT init_b = TREE_INT_CST_LOW (DR_INIT (drb));
HOST_WIDE_INT init_prev
- = TREE_INT_CST_LOW (DR_INIT (datarefs_copy[i-1]));
+ = TREE_INT_CST_LOW (DR_INIT (datarefs_copy[i-1].first));
gcc_assert (init_a <= init_b
&& init_a <= init_prev
&& init_prev <= init_b);
/* Do not place the same access in the interleaving chain twice. */
if (init_b == init_prev)
{
- gcc_assert (gimple_uid (DR_STMT (datarefs_copy[i-1]))
+ gcc_assert (gimple_uid (DR_STMT (datarefs_copy[i-1].first))
< gimple_uid (DR_STMT (drb)));
/* Simply link in duplicates and fix up the chain below. */
}
to_fixup.add (newgroup);
}
- FOR_EACH_VEC_ELT (datarefs_copy, i, dr)
+ data_ref_pair *dr_pair;
+ FOR_EACH_VEC_ELT (datarefs_copy, i, dr_pair)
{
- dr_vec_info *dr_info = vinfo->lookup_dr (dr);
+ dr_vec_info *dr_info = vinfo->lookup_dr (dr_pair->first);
if (STMT_VINFO_VECTORIZABLE (dr_info->stmt)
&& !vect_analyze_data_ref_access (vinfo, dr_info))
{
opt_result
vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
- vec<data_reference_p> *datarefs)
+ vec<data_reference_p> *datarefs,
+ vec<int> *dataref_groups, int group_id)
{
/* We can ignore clobbers for dataref analysis - they are removed during
loop vectorization and BB vectorization checks dependences with a
newdr->aux = (void *) (-1 - tree_to_uhwi (arg2));
free_data_ref (dr);
datarefs->safe_push (newdr);
+ if (dataref_groups)
+ dataref_groups->safe_push (group_id);
return opt_result::success ();
}
}
}
datarefs->safe_push (dr);
+ if (dataref_groups)
+ dataref_groups->safe_push (group_id);
return opt_result::success ();
}
if (is_gimple_debug (stmt))
continue;
++(*n_stmts);
- opt_result res = vect_find_stmt_data_reference (loop, stmt, datarefs);
+ opt_result res = vect_find_stmt_data_reference (loop, stmt, datarefs,
+ NULL, 0);
if (!res)
{
if (is_gimple_call (stmt) && loop->safelen)
/* Analyze the access patterns of the data-refs in the loop (consecutive,
complex, etc.). FORNOW: Only handle consecutive access pattern. */
- ok = vect_analyze_data_ref_accesses (loop_vinfo);
+ ok = vect_analyze_data_ref_accesses (loop_vinfo, NULL);
if (!ok)
{
if (dump_enabled_p ())
region. */
static bool
-vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal)
+vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal,
+ vec<int> *dataref_groups)
{
DUMP_VECT_SCOPE ("vect_slp_analyze_bb");
return false;
}
- if (!vect_analyze_data_ref_accesses (bb_vinfo))
+ if (!vect_analyze_data_ref_accesses (bb_vinfo, dataref_groups))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
given by DATAREFS. */
static bool
-vect_slp_bb_region (gimple_stmt_iterator region_begin,
- gimple_stmt_iterator region_end,
- vec<data_reference_p> datarefs,
- unsigned int n_stmts)
+vect_slp_region (gimple_stmt_iterator region_begin,
+ gimple_stmt_iterator region_end,
+ vec<data_reference_p> datarefs,
+ vec<int> *dataref_groups,
+ unsigned int n_stmts)
{
bb_vec_info bb_vinfo;
auto_vector_modes vector_modes;
bb_vinfo->shared->check_datarefs ();
bb_vinfo->vector_mode = next_vector_mode;
- if (vect_slp_analyze_bb_1 (bb_vinfo, n_stmts, fatal)
+ if (vect_slp_analyze_bb_1 (bb_vinfo, n_stmts, fatal, dataref_groups)
&& dbg_cnt (vect_slp))
{
if (dump_enabled_p ())
bool
vect_slp_bb (basic_block bb)
{
- gimple_stmt_iterator gsi;
- bool any_vectorized = false;
-
- gsi = gsi_after_labels (bb);
- while (!gsi_end_p (gsi))
+ vec<data_reference_p> datarefs = vNULL;
+ vec<int> dataref_groups = vNULL;
+ int insns = 0;
+ int current_group = 0;
+ gimple_stmt_iterator region_begin = gsi_start_nondebug_after_labels_bb (bb);
+ gimple_stmt_iterator region_end = gsi_last_bb (bb);
+ if (!gsi_end_p (region_end))
+ gsi_next (®ion_end);
+
+ for (gimple_stmt_iterator gsi = gsi_after_labels (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
{
- gimple_stmt_iterator region_begin = gsi;
- vec<data_reference_p> datarefs = vNULL;
- int insns = 0;
-
- for (; !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
- if (is_gimple_debug (stmt))
- {
- /* Skip leading debug stmts. */
- if (gsi_stmt (region_begin) == stmt)
- gsi_next (®ion_begin);
- continue;
- }
- insns++;
-
- if (gimple_location (stmt) != UNKNOWN_LOCATION)
- vect_location = stmt;
+ gimple *stmt = gsi_stmt (gsi);
+ if (is_gimple_debug (stmt))
+ continue;
- if (!vect_find_stmt_data_reference (NULL, stmt, &datarefs))
- break;
- }
- if (gsi_end_p (region_begin))
- break;
+ insns++;
- /* Skip leading unhandled stmts. */
- if (gsi_stmt (region_begin) == gsi_stmt (gsi))
- {
- gsi_next (&gsi);
- continue;
- }
+ if (gimple_location (stmt) != UNKNOWN_LOCATION)
+ vect_location = stmt;
- gimple_stmt_iterator region_end = gsi;
+ if (!vect_find_stmt_data_reference (NULL, stmt, &datarefs,
+ &dataref_groups, current_group))
+ ++current_group;
if (insns > param_slp_max_insns_in_bb)
{
"not vectorized: too many instructions in "
"basic block.\n");
}
- else if (vect_slp_bb_region (region_begin, region_end, datarefs, insns))
- any_vectorized = true;
-
- if (gsi_end_p (region_end))
- break;
-
- /* Skip the unhandled stmt. */
- gsi_next (&gsi);
}
- return any_vectorized;
+ return vect_slp_region (region_begin, region_end, datarefs,
+ &dataref_groups, insns);
}
extern opt_result vect_enhance_data_refs_alignment (loop_vec_info);
extern opt_result vect_analyze_data_refs_alignment (loop_vec_info);
extern bool vect_slp_analyze_instance_alignment (vec_info *, slp_instance);
-extern opt_result vect_analyze_data_ref_accesses (vec_info *);
+extern opt_result vect_analyze_data_ref_accesses (vec_info *, vec<int> *);
extern opt_result vect_prune_runtime_alias_test_list (loop_vec_info);
extern bool vect_gather_scatter_fn_p (vec_info *, bool, bool, tree, tree,
tree, int, internal_fn *, tree *);
extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info,
gather_scatter_info *);
extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
- vec<data_reference_p> *);
+ vec<data_reference_p> *,
+ vec<int> *, int);
extern opt_result vect_analyze_data_refs (vec_info *, poly_uint64 *, bool *);
extern void vect_record_base_alignments (vec_info *);
extern tree vect_create_data_ref_ptr (vec_info *,