On Tue, 12 Nov 2013, Cong Hou wrote: > The current alias check merger does not consider the DR_STEP of > data-refs when sorting data-refs. For the following loop: > > for (i = 0; i < N; ++i) > a[i] = b[0] + b[i] + b[1]; > > The data ref b[0] and b[i] have the same DR_INIT and DR_OFFSET, and > after sorting three DR pairs, the following order can be a possible > result: > > (a[i], b[0]), (a[i], b[i]), (a[i], b[1]) > > This prevents the alias checks for (a[i], b[0]) and (a[i], b[1]) being > merged. > > This patch added the comparison between DR_STEP of two data refs > during the sort. > > The test case is also updated. The previous one used explicit > dg-options which blocks the options from the target vect_int. The test > case also assumes a vector can hold at least 4 integers of int type, > which may not be true on some targets. > > The patch is pasted below. Bootstrapped and tested on a x86-64 machine.
Ok. Thanks, Richard. > > > thanks, > Cong > > > > diff --git a/gcc/ChangeLog b/gcc/ChangeLog > index 2c0554b..5faa5ca 100644 > --- a/gcc/ChangeLog > +++ b/gcc/ChangeLog > @@ -1,3 +1,14 @@ > +2013-11-12 Cong Hou <co...@google.com> > + > + * tree-vectorizer.h (struct dr_with_seg_len): Remove the base > + address field as it can be obtained from dr. Rename the struct. > + * tree-vect-data-refs.c (comp_dr_with_seg_len_pair): Consider > + steps of data references during sort. > + (vect_prune_runtime_alias_test_list): Adjust with the change to > + struct dr_with_seg_len. > + * tree-vect-loop-manip.c (vect_create_cond_for_alias_checks): > + Adjust with the change to struct dr_with_seg_len. > + > 2013-11-12 Jeff Law <l...@redhat.com> > > * tree-ssa-threadedge.c (thread_around_empty_blocks): New > diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog > index 09c7f20..8075409 100644 > --- a/gcc/testsuite/ChangeLog > +++ b/gcc/testsuite/ChangeLog > @@ -1,3 +1,7 @@ > +2013-11-12 Cong Hou <co...@google.com> > + > + * gcc.dg/vect/vect-alias-check.c: Update. > + > 2013-11-12 Balaji V. Iyer <balaji.v.i...@intel.com> > > * gcc.dg/cilk-plus/cilk-plus.exp: Added a check for LTO before running > diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check.c > b/gcc/testsuite/gcc.dg/vect/vect-alias-check.c > index 64a4e0c..c1bffed 100644 > --- a/gcc/testsuite/gcc.dg/vect/vect-alias-check.c > +++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check.c > @@ -1,17 +1,17 @@ > /* { dg-require-effective-target vect_int } */ > /* { dg-do compile } */ > -/* { dg-options "-O2 -ftree-vectorize > --param=vect-max-version-for-alias-checks=2 -fdump-tree-vect-details" > } */ > +/* { dg-additional-options "--param=vect-max-version-for-alias-checks=2" } */ > > -/* A test case showing three potential alias checks between > - a[i] and b[i], b[i+7], b[i+14]. With alias checks merging > - enabled, those tree checks can be merged into one, and the > - loop will be vectorized with vect-max-version-for-alias-checks=2. */ > +/* A test case showing four potential alias checks between a[i] and b[0], > b[1], > + b[i+1] and b[i+2]. With alias check merging enabled, those four checks > + can be merged into two, and the loop will be vectorized with > + vect-max-version-for-alias-checks=2. */ > > void foo (int *a, int *b) > { > int i; > for (i = 0; i < 1000; ++i) > - a[i] = b[i] + b[i+7] + b[i+14]; > + a[i] = b[0] + b[1] + b[i+1] + b[i+2]; > } > > /* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ > diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c > index c479775..7f0920d 100644 > --- a/gcc/tree-vect-data-refs.c > +++ b/gcc/tree-vect-data-refs.c > @@ -2620,7 +2620,7 @@ vect_analyze_data_ref_accesses (loop_vec_info > loop_vinfo, bb_vec_info bb_vinfo) > } > > > -/* Operator == between two dr_addr_with_seg_len objects. > +/* Operator == between two dr_with_seg_len objects. > > This equality operator is used to make sure two data refs > are the same one so that we will consider to combine the > @@ -2628,62 +2628,51 @@ vect_analyze_data_ref_accesses (loop_vec_info > loop_vinfo, bb_vec_info bb_vinfo) > refs. */ > > static bool > -operator == (const dr_addr_with_seg_len& d1, > - const dr_addr_with_seg_len& d2) > +operator == (const dr_with_seg_len& d1, > + const dr_with_seg_len& d2) > { > - return operand_equal_p (d1.basic_addr, d2.basic_addr, 0) > - && compare_tree (d1.offset, d2.offset) == 0 > - && compare_tree (d1.seg_len, d2.seg_len) == 0; > + return operand_equal_p (DR_BASE_ADDRESS (d1.dr), > + DR_BASE_ADDRESS (d2.dr), 0) > + && compare_tree (d1.offset, d2.offset) == 0 > + && compare_tree (d1.seg_len, d2.seg_len) == 0; > } > > -/* Function comp_dr_addr_with_seg_len_pair. > +/* Function comp_dr_with_seg_len_pair. > > - Comparison function for sorting objects of dr_addr_with_seg_len_pair_t > + Comparison function for sorting objects of dr_with_seg_len_pair_t > so that we can combine aliasing checks in one scan. */ > > static int > -comp_dr_addr_with_seg_len_pair (const void *p1_, const void *p2_) > +comp_dr_with_seg_len_pair (const void *p1_, const void *p2_) > { > - const dr_addr_with_seg_len_pair_t* p1 = > - (const dr_addr_with_seg_len_pair_t *) p1_; > - const dr_addr_with_seg_len_pair_t* p2 = > - (const dr_addr_with_seg_len_pair_t *) p2_; > - > - const dr_addr_with_seg_len &p11 = p1->first, > - &p12 = p1->second, > - &p21 = p2->first, > - &p22 = p2->second; > - > - int comp_res = compare_tree (p11.basic_addr, p21.basic_addr); > - if (comp_res != 0) > + const dr_with_seg_len_pair_t* p1 = (const dr_with_seg_len_pair_t *) p1_; > + const dr_with_seg_len_pair_t* p2 = (const dr_with_seg_len_pair_t *) p2_; > + > + const dr_with_seg_len &p11 = p1->first, > + &p12 = p1->second, > + &p21 = p2->first, > + &p22 = p2->second; > + > + /* For DR pairs (a, b) and (c, d), we only consider to merge the alias > checks > + if a and c have the same basic address snd step, and b and d have the > same > + address and step. Therefore, if any a&c or b&d don't have the > same address > + and step, we don't care the order of those two pairs after sorting. */ > + int comp_res; > + > + if ((comp_res = compare_tree (DR_BASE_ADDRESS (p11.dr), > + DR_BASE_ADDRESS (p21.dr))) != 0) > return comp_res; > - > - comp_res = compare_tree (p12.basic_addr, p22.basic_addr); > - if (comp_res != 0) > + if ((comp_res = compare_tree (DR_BASE_ADDRESS (p12.dr), > + DR_BASE_ADDRESS (p22.dr))) != 0) > + return comp_res; > + if ((comp_res = compare_tree (DR_STEP (p11.dr), DR_STEP (p21.dr))) != 0) > + return comp_res; > + if ((comp_res = compare_tree (DR_STEP (p12.dr), DR_STEP (p22.dr))) != 0) > + return comp_res; > + if ((comp_res = compare_tree (p11.offset, p21.offset)) != 0) > + return comp_res; > + if ((comp_res = compare_tree (p12.offset, p22.offset)) != 0) > return comp_res; > - > - if (TREE_CODE (p11.offset) != INTEGER_CST > - || TREE_CODE (p21.offset) != INTEGER_CST) > - { > - comp_res = compare_tree (p11.offset, p21.offset); > - if (comp_res != 0) > - return comp_res; > - } > - else if (tree_int_cst_compare (p11.offset, p21.offset) < 0) > - return -1; > - else if (tree_int_cst_compare (p11.offset, p21.offset) > 0) > - return 1; > - if (TREE_CODE (p12.offset) != INTEGER_CST > - || TREE_CODE (p22.offset) != INTEGER_CST) > - { > - comp_res = compare_tree (p12.offset, p22.offset); > - if (comp_res != 0) > - return comp_res; > - } > - else if (tree_int_cst_compare (p12.offset, p22.offset) < 0) > - return -1; > - else if (tree_int_cst_compare (p12.offset, p22.offset) > 0) > - return 1; > > return 0; > } > @@ -2718,11 +2707,11 @@ vect_vfa_segment_size (struct data_reference > *dr, tree length_factor) > segment_length = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr))); > else > segment_length = size_binop (MULT_EXPR, > - fold_convert (sizetype, DR_STEP (dr)), > - fold_convert (sizetype, length_factor)); > + fold_convert (sizetype, DR_STEP (dr)), > + fold_convert (sizetype, length_factor)); > > if (vect_supportable_dr_alignment (dr, false) > - == dr_explicit_realign_optimized) > + == dr_explicit_realign_optimized) > { > tree vector_size = TYPE_SIZE_UNIT > (STMT_VINFO_VECTYPE (vinfo_for_stmt (DR_STMT (dr)))); > @@ -2744,7 +2733,7 @@ vect_prune_runtime_alias_test_list > (loop_vec_info loop_vinfo) > { > vec<ddr_p> may_alias_ddrs = > LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo); > - vec<dr_addr_with_seg_len_pair_t>& comp_alias_ddrs = > + vec<dr_with_seg_len_pair_t>& comp_alias_ddrs = > LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo); > int vect_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo); > tree scalar_loop_iters = LOOP_VINFO_NITERS (loop_vinfo); > @@ -2823,18 +2812,11 @@ vect_prune_runtime_alias_test_list > (loop_vec_info loop_vinfo) > segment_length_a = vect_vfa_segment_size (dr_a, length_factor); > segment_length_b = vect_vfa_segment_size (dr_b, length_factor); > > - dr_addr_with_seg_len_pair_t dr_with_seg_len_pair > - (dr_addr_with_seg_len > - (dr_a, DR_BASE_ADDRESS (dr_a), > - size_binop (PLUS_EXPR, DR_OFFSET (dr_a), DR_INIT (dr_a)), > - segment_length_a), > - dr_addr_with_seg_len > - (dr_b, DR_BASE_ADDRESS (dr_b), > - size_binop (PLUS_EXPR, DR_OFFSET (dr_b), DR_INIT (dr_b)), > - segment_length_b)); > - > - if (compare_tree (dr_with_seg_len_pair.first.basic_addr, > - dr_with_seg_len_pair.second.basic_addr) > 0) > + dr_with_seg_len_pair_t dr_with_seg_len_pair > + (dr_with_seg_len (dr_a, segment_length_a), > + dr_with_seg_len (dr_b, segment_length_b)); > + > + if (compare_tree (DR_BASE_ADDRESS (dr_a), DR_BASE_ADDRESS (dr_b)) > 0) > swap (dr_with_seg_len_pair.first, dr_with_seg_len_pair.second); > > comp_alias_ddrs.safe_push (dr_with_seg_len_pair); > @@ -2842,17 +2824,17 @@ vect_prune_runtime_alias_test_list > (loop_vec_info loop_vinfo) > > /* Second, we sort the collected data ref pairs so that we can scan > them once to combine all possible aliasing checks. */ > - comp_alias_ddrs.qsort (comp_dr_addr_with_seg_len_pair); > + comp_alias_ddrs.qsort (comp_dr_with_seg_len_pair); > > /* Third, we scan the sorted dr pairs and check if we can combine > alias checks of two neighbouring dr pairs. */ > for (size_t i = 1; i < comp_alias_ddrs.length (); ++i) > { > /* Deal with two ddrs (dr_a1, dr_b1) and (dr_a2, dr_b2). */ > - dr_addr_with_seg_len *dr_a1 = &comp_alias_ddrs[i-1].first, > - *dr_b1 = &comp_alias_ddrs[i-1].second, > - *dr_a2 = &comp_alias_ddrs[i].first, > - *dr_b2 = &comp_alias_ddrs[i].second; > + dr_with_seg_len *dr_a1 = &comp_alias_ddrs[i-1].first, > + *dr_b1 = &comp_alias_ddrs[i-1].second, > + *dr_a2 = &comp_alias_ddrs[i].first, > + *dr_b2 = &comp_alias_ddrs[i].second; > > /* Remove duplicate data ref pairs. */ > if (*dr_a1 == *dr_a2 && *dr_b1 == *dr_b2) > @@ -2889,7 +2871,9 @@ vect_prune_runtime_alias_test_list > (loop_vec_info loop_vinfo) > swap (dr_a2, dr_b2); > } > > - if (!operand_equal_p (dr_a1->basic_addr, dr_a2->basic_addr, 0) > + if (!operand_equal_p (DR_BASE_ADDRESS (dr_a1->dr), > + DR_BASE_ADDRESS (dr_a2->dr), > + 0) > || !host_integerp (dr_a1->offset, 0) > || !host_integerp (dr_a2->offset, 0)) > continue; > @@ -2916,8 +2900,8 @@ vect_prune_runtime_alias_test_list > (loop_vec_info loop_vinfo) > > HOST_WIDE_INT > min_seg_len_b = (TREE_CODE (dr_b1->seg_len) == INTEGER_CST) ? > - TREE_INT_CST_LOW (dr_b1->seg_len) : > - vect_factor; > + TREE_INT_CST_LOW (dr_b1->seg_len) : > + vect_factor; > > if (diff <= min_seg_len_b > || (TREE_CODE (dr_a1->seg_len) == INTEGER_CST > diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c > index 15227856..b8e56c4 100644 > --- a/gcc/tree-vect-loop-manip.c > +++ b/gcc/tree-vect-loop-manip.c > @@ -2242,7 +2242,7 @@ vect_create_cond_for_align_checks (loop_vec_info > loop_vinfo, > void > vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * > cond_expr) > { > - vec<dr_addr_with_seg_len_pair_t> comp_alias_ddrs = > + vec<dr_with_seg_len_pair_t> comp_alias_ddrs = > LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo); > tree part_cond_expr; > > @@ -2260,15 +2260,15 @@ vect_create_cond_for_alias_checks > (loop_vec_info loop_vinfo, tree * cond_expr) > > for (size_t i = 0, s = comp_alias_ddrs.length (); i < s; ++i) > { > - const dr_addr_with_seg_len& dr_a = comp_alias_ddrs[i].first; > - const dr_addr_with_seg_len& dr_b = comp_alias_ddrs[i].second; > + const dr_with_seg_len& dr_a = comp_alias_ddrs[i].first; > + const dr_with_seg_len& dr_b = comp_alias_ddrs[i].second; > tree segment_length_a = dr_a.seg_len; > tree segment_length_b = dr_b.seg_len; > > tree addr_base_a > - = fold_build_pointer_plus (dr_a.basic_addr, dr_a.offset); > + = fold_build_pointer_plus (DR_BASE_ADDRESS (dr_a.dr), dr_a.offset); > tree addr_base_b > - = fold_build_pointer_plus (dr_b.basic_addr, dr_b.offset); > + = fold_build_pointer_plus (DR_BASE_ADDRESS (dr_b.dr), dr_b.offset); > > if (dump_enabled_p ()) > { > diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h > index bbd50e1..0ce78d9 100644 > --- a/gcc/tree-vectorizer.h > +++ b/gcc/tree-vectorizer.h > @@ -176,32 +176,33 @@ typedef struct _slp_oprnd_info > > > /* This struct is used to store the information of a data reference, > - including the data ref itself, its basic address, the access offset > - and the segment length for aliasing checks. This is used to generate > - alias checks. */ > + including the data ref itself, the access offset (calculated by summing > its > + offset and init) and the segment length for aliasing checks. > + This is used to merge alias checks. */ > > -struct dr_addr_with_seg_len > +struct dr_with_seg_len > { > - dr_addr_with_seg_len (data_reference* d, tree addr, tree off, tree len) > - : dr (d), basic_addr (addr), offset (off), seg_len (len) {} > + dr_with_seg_len (data_reference_p d, tree len) > + : dr (d), > + offset (size_binop (PLUS_EXPR, DR_OFFSET (d), DR_INIT (d))), > + seg_len (len) {} > > - data_reference *dr; > - tree basic_addr; > + data_reference_p dr; > tree offset; > tree seg_len; > }; > > -/* This struct contains two dr_addr_with_seg_len objects with aliasing data > +/* This struct contains two dr_with_seg_len objects with aliasing data > refs. Two comparisons are generated from them. */ > > -struct dr_addr_with_seg_len_pair_t > +struct dr_with_seg_len_pair_t > { > - dr_addr_with_seg_len_pair_t (const dr_addr_with_seg_len& d1, > - const dr_addr_with_seg_len& d2) > + dr_with_seg_len_pair_t (const dr_with_seg_len& d1, > + const dr_with_seg_len& d2) > : first (d1), second (d2) {} > > - dr_addr_with_seg_len first; > - dr_addr_with_seg_len second; > + dr_with_seg_len first; > + dr_with_seg_len second; > }; > > > @@ -306,7 +307,7 @@ typedef struct _loop_vec_info { > > /* Data Dependence Relations defining address ranges together with segment > lengths from which the run-time aliasing check is built. */ > - vec<dr_addr_with_seg_len_pair_t> comp_alias_ddrs; > + vec<dr_with_seg_len_pair_t> comp_alias_ddrs; > > /* Statements in the loop that have data references that are candidates > for a > runtime (loop versioning) misalignment check. */ >