diff options
author | congh <congh@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-11-07 19:29:45 +0000 |
---|---|---|
committer | congh <congh@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-11-07 19:29:45 +0000 |
commit | 8a7b0f48b2599df0bed20d9488b7106561310c1b (patch) | |
tree | ce9a066296eee210133c1bff32f548ab6ed8aa4a | |
parent | ec513397c38a49f9167751fe63ced6b0f1cd90ff (diff) | |
download | gcc-8a7b0f48b2599df0bed20d9488b7106561310c1b.tar.gz |
2013-11-07 Cong Hou <congh@google.com>
PR tree-optimization/56764
* tree-vect-loop-manip.c (vect_create_cond_for_alias_checks):
Combine alias checks if it is possible to amortize the runtime
overhead. Return the number of alias checks after merging.
* tree-vect-data-refs.c (vect_prune_runtime_alias_test_list):
Use the function vect_create_cond_for_alias_checks () to check
the number of alias checks.
2013-11-07 Cong Hou <congh@google.com>
* gcc.dg/vect/vect-alias-check.c: New.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204538 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/vect/vect-alias-check.c | 18 | ||||
-rw-r--r-- | gcc/tree-vect-data-refs.c | 364 | ||||
-rw-r--r-- | gcc/tree-vect-loop-manip.c | 131 | ||||
-rw-r--r-- | gcc/tree-vectorizer.h | 35 |
6 files changed, 386 insertions, 176 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 243175c2e79..5808ee5ce96 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2013-11-07 Cong Hou <congh@google.com> + + PR tree-optimization/56764 + * tree-vect-loop-manip.c (vect_create_cond_for_alias_checks): + Combine alias checks if it is possible to amortize the runtime + overhead. Return the number of alias checks after merging. + * tree-vect-data-refs.c (vect_prune_runtime_alias_test_list): + Use the function vect_create_cond_for_alias_checks () to check + the number of alias checks. + 2013-11-07 Jeff Law <law@redhat.com> * varpool.c (ctor_for_folding): Fix typo in comment. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e28fce632c6..6cb4b9822ef 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2013-11-07 Cong Hou <congh@google.com> + + * gcc.dg/vect/vect-alias-check.c: New. + 2013-11-07 Jakub Jelinek <jakub@redhat.com> * gcc.dg/tree-ssa/loop-39.c: New test. diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check.c b/gcc/testsuite/gcc.dg/vect/vect-alias-check.c new file mode 100644 index 00000000000..64a4e0ce05c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check.c @@ -0,0 +1,18 @@ +/* { 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" } */ + +/* 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. */ + +void foo (int *a, int *b) +{ + int i; + for (i = 0; i < 1000; ++i) + a[i] = b[i] + b[i+7] + b[i+14]; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ +/* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index fb3fe94240b..b2a31b1de4a 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -135,41 +135,6 @@ vect_get_smallest_scalar_type (gimple stmt, HOST_WIDE_INT *lhs_size_unit, } -/* Check if data references pointed by DR_I and DR_J are same or - belong to same interleaving group. Return FALSE if drs are - different, otherwise return TRUE. */ - -static bool -vect_same_range_drs (data_reference_p dr_i, data_reference_p dr_j) -{ - gimple stmt_i = DR_STMT (dr_i); - gimple stmt_j = DR_STMT (dr_j); - - if (operand_equal_p (DR_REF (dr_i), DR_REF (dr_j), 0) - || (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_i)) - && GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_j)) - && (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_i)) - == GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_j))))) - return true; - else - return false; -} - -/* If address ranges represented by DDR_I and DDR_J are equal, - return TRUE, otherwise return FALSE. */ - -static bool -vect_vfa_range_equal (ddr_p ddr_i, ddr_p ddr_j) -{ - if ((vect_same_range_drs (DDR_A (ddr_i), DDR_A (ddr_j)) - && vect_same_range_drs (DDR_B (ddr_i), DDR_B (ddr_j))) - || (vect_same_range_drs (DDR_A (ddr_i), DDR_B (ddr_j)) - && vect_same_range_drs (DDR_B (ddr_i), DDR_A (ddr_j)))) - return true; - else - return false; -} - /* Insert DDR into LOOP_VINFO list of ddrs that may alias and need to be tested at run-time. Return TRUE if DDR was successfully inserted. Return false if versioning is not supported. */ @@ -2654,69 +2619,320 @@ vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo) return true; } + +/* Operator == between two dr_addr_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 + aliasing checks of those two pairs of data dependent data + refs. */ + +static bool +operator == (const dr_addr_with_seg_len& d1, + const dr_addr_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; +} + +/* Function comp_dr_addr_with_seg_len_pair. + + Comparison function for sorting objects of dr_addr_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_) +{ + 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) + return comp_res; + + comp_res = compare_tree (p12.basic_addr, p22.basic_addr); + if (comp_res != 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; + } + if (tree_int_cst_compare (p11.offset, p21.offset) < 0) + return -1; + 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; + } + if (tree_int_cst_compare (p12.offset, p22.offset) < 0) + return -1; + if (tree_int_cst_compare (p12.offset, p22.offset) > 0) + return 1; + + return 0; +} + +template <class T> static void +swap (T& a, T& b) +{ + T c (a); + a = b; + b = c; +} + +/* Function vect_vfa_segment_size. + + Create an expression that computes the size of segment + that will be accessed for a data reference. The functions takes into + account that realignment loads may access one more vector. + + Input: + DR: The data reference. + LENGTH_FACTOR: segment length to consider. + + Return an expression whose value is the size of segment which will be + accessed by DR. */ + +static tree +vect_vfa_segment_size (struct data_reference *dr, tree length_factor) +{ + tree segment_length; + + if (integer_zerop (DR_STEP (dr))) + 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)); + + if (vect_supportable_dr_alignment (dr, false) + == dr_explicit_realign_optimized) + { + tree vector_size = TYPE_SIZE_UNIT + (STMT_VINFO_VECTYPE (vinfo_for_stmt (DR_STMT (dr)))); + + segment_length = size_binop (PLUS_EXPR, segment_length, vector_size); + } + return segment_length; +} + /* Function vect_prune_runtime_alias_test_list. Prune a list of ddrs to be tested at run-time by versioning for alias. + Merge several alias checks into one if possible. Return FALSE if resulting list of ddrs is longer then allowed by PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE. */ bool vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo) { - vec<ddr_p> ddrs = + vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo); - unsigned i, j; + vec<dr_addr_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); + + ddr_p ddr; + unsigned int i; + tree length_factor; if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "=== vect_prune_runtime_alias_test_list ===\n"); - for (i = 0; i < ddrs.length (); ) + if (may_alias_ddrs.is_empty ()) + return true; + + /* Basically, for each pair of dependent data refs store_ptr_0 + and load_ptr_0, we create an expression: + + ((store_ptr_0 + store_segment_length_0) <= load_ptr_0) + || (load_ptr_0 + load_segment_length_0) <= store_ptr_0)) + + for aliasing checks. However, in some cases we can decrease + the number of checks by combining two checks into one. For + example, suppose we have another pair of data refs store_ptr_0 + and load_ptr_1, and if the following condition is satisfied: + + load_ptr_0 < load_ptr_1 && + load_ptr_1 - load_ptr_0 - load_segment_length_0 < store_segment_length_0 + + (this condition means, in each iteration of vectorized loop, + the accessed memory of store_ptr_0 cannot be between the memory + of load_ptr_0 and load_ptr_1.) + + we then can use only the following expression to finish the + alising checks between store_ptr_0 & load_ptr_0 and + store_ptr_0 & load_ptr_1: + + ((store_ptr_0 + store_segment_length_0) <= load_ptr_0) + || (load_ptr_1 + load_segment_length_1 <= store_ptr_0)) + + Note that we only consider that load_ptr_0 and load_ptr_1 have the + same basic address. */ + + comp_alias_ddrs.create (may_alias_ddrs.length ()); + + /* First, we collect all data ref pairs for aliasing checks. */ + FOR_EACH_VEC_ELT (may_alias_ddrs, i, ddr) { - bool found; - ddr_p ddr_i; + struct data_reference *dr_a, *dr_b; + gimple dr_group_first_a, dr_group_first_b; + tree segment_length_a, segment_length_b; + gimple stmt_a, stmt_b; + + dr_a = DDR_A (ddr); + stmt_a = DR_STMT (DDR_A (ddr)); + dr_group_first_a = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_a)); + if (dr_group_first_a) + { + stmt_a = dr_group_first_a; + dr_a = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt_a)); + } - ddr_i = ddrs[i]; - found = false; + dr_b = DDR_B (ddr); + stmt_b = DR_STMT (DDR_B (ddr)); + dr_group_first_b = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_b)); + if (dr_group_first_b) + { + stmt_b = dr_group_first_b; + dr_b = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt_b)); + } - for (j = 0; j < i; j++) - { - ddr_p ddr_j = ddrs[j]; + if (!operand_equal_p (DR_STEP (dr_a), DR_STEP (dr_b), 0)) + length_factor = scalar_loop_iters; + else + length_factor = size_int (vect_factor); + 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) + swap (dr_with_seg_len_pair.first, dr_with_seg_len_pair.second); + + comp_alias_ddrs.safe_push (dr_with_seg_len_pair); + } - if (vect_vfa_range_equal (ddr_i, ddr_j)) + /* 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); + + /* 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; + + /* Remove duplicate data ref pairs. */ + if (*dr_a1 == *dr_a2 && *dr_b1 == *dr_b2) + { + if (dump_enabled_p ()) { - if (dump_enabled_p ()) - { - dump_printf_loc (MSG_NOTE, vect_location, - "found equal ranges "); - dump_generic_expr (MSG_NOTE, TDF_SLIM, - DR_REF (DDR_A (ddr_i))); - dump_printf (MSG_NOTE, ", "); - dump_generic_expr (MSG_NOTE, TDF_SLIM, - DR_REF (DDR_B (ddr_i))); - dump_printf (MSG_NOTE, " and "); - dump_generic_expr (MSG_NOTE, TDF_SLIM, - DR_REF (DDR_A (ddr_j))); - dump_printf (MSG_NOTE, ", "); - dump_generic_expr (MSG_NOTE, TDF_SLIM, - DR_REF (DDR_B (ddr_j))); - dump_printf (MSG_NOTE, "\n"); - } - found = true; - break; + dump_printf_loc (MSG_NOTE, vect_location, + "found equal ranges "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, + DR_REF (dr_a1->dr)); + dump_printf (MSG_NOTE, ", "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, + DR_REF (dr_b1->dr)); + dump_printf (MSG_NOTE, " and "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, + DR_REF (dr_a2->dr)); + dump_printf (MSG_NOTE, ", "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, + DR_REF (dr_b2->dr)); + dump_printf (MSG_NOTE, "\n"); } + + comp_alias_ddrs.ordered_remove (i--); + continue; } - if (found) - { - ddrs.ordered_remove (i); - continue; - } - i++; + if (*dr_a1 == *dr_a2 || *dr_b1 == *dr_b2) + { + /* We consider the case that DR_B1 and DR_B2 are same memrefs, + and DR_A1 and DR_A2 are two consecutive memrefs. */ + if (*dr_a1 == *dr_a2) + { + swap (dr_a1, dr_b1); + swap (dr_a2, dr_b2); + } + + if (!operand_equal_p (dr_a1->basic_addr, dr_a2->basic_addr, 0) + || !host_integerp (dr_a1->offset, 0) + || !host_integerp (dr_a2->offset, 0)) + continue; + + HOST_WIDE_INT diff = TREE_INT_CST_LOW (dr_a2->offset) - + TREE_INT_CST_LOW (dr_a1->offset); + + + /* Now we check if the following condition is satisfied: + + DIFF - SEGMENT_LENGTH_A < SEGMENT_LENGTH_B + + where DIFF = DR_A2->OFFSET - DR_A1->OFFSET. However, + SEGMENT_LENGTH_A or SEGMENT_LENGTH_B may not be constant so we + have to make a best estimation. We can get the minimum value + of SEGMENT_LENGTH_B as a constant, represented by MIN_SEG_LEN_B, + then either of the following two conditions can guarantee the + one above: + + 1: DIFF <= MIN_SEG_LEN_B + 2: DIFF - SEGMENT_LENGTH_A < MIN_SEG_LEN_B + + */ + + 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; + + if (diff <= min_seg_len_b + || (TREE_CODE (dr_a1->seg_len) == INTEGER_CST + && diff - (HOST_WIDE_INT) TREE_INT_CST_LOW (dr_a1->seg_len) < + min_seg_len_b)) + { + dr_a1->seg_len = size_binop (PLUS_EXPR, + dr_a2->seg_len, size_int (diff)); + comp_alias_ddrs.ordered_remove (i--); + } + } } - if (ddrs.length () > - (unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS)) + if ((int) comp_alias_ddrs.length () > + PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS)) { if (dump_enabled_p ()) { @@ -2725,8 +2941,6 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo) "generated checks exceeded.\n"); } - LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).truncate (0); - return false; } diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c index 00a3661385e..fb34664960e 100644 --- a/gcc/tree-vect-loop-manip.c +++ b/gcc/tree-vect-loop-manip.c @@ -2219,44 +2219,6 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo, *cond_expr = part_cond_expr; } - -/* Function vect_vfa_segment_size. - - Create an expression that computes the size of segment - that will be accessed for a data reference. The functions takes into - account that realignment loads may access one more vector. - - Input: - DR: The data reference. - LENGTH_FACTOR: segment length to consider. - - Return an expression whose value is the size of segment which will be - accessed by DR. */ - -static tree -vect_vfa_segment_size (struct data_reference *dr, tree length_factor) -{ - tree segment_length; - - if (integer_zerop (DR_STEP (dr))) - 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)); - - if (vect_supportable_dr_alignment (dr, false) - == dr_explicit_realign_optimized) - { - tree vector_size = TYPE_SIZE_UNIT - (STMT_VINFO_VECTYPE (vinfo_for_stmt (DR_STMT (dr)))); - - segment_length = size_binop (PLUS_EXPR, segment_length, vector_size); - } - return segment_length; -} - - /* Function vect_create_cond_for_alias_checks. Create a conditional expression that represents the run-time checks for @@ -2265,28 +2227,24 @@ vect_vfa_segment_size (struct data_reference *dr, tree length_factor) Input: COND_EXPR - input conditional expression. New conditions will be chained - with logical AND operation. + with logical AND operation. If it is NULL, then the function + is used to return the number of alias checks. LOOP_VINFO - field LOOP_VINFO_MAY_ALIAS_STMTS contains the list of ddrs to be checked. Output: COND_EXPR - conditional expression. - The returned value is the conditional expression to be used in the if + The returned COND_EXPR is the conditional expression to be used in the if statement that controls which version of the loop gets executed at runtime. */ -static void +void vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr) { - vec<ddr_p> may_alias_ddrs = - LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo); - int vect_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo); - tree scalar_loop_iters = LOOP_VINFO_NITERS (loop_vinfo); - - ddr_p ddr; - unsigned int i; - tree part_cond_expr, length_factor; + vec<dr_addr_with_seg_len_pair_t> comp_alias_ddrs = + LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo); + tree part_cond_expr; /* Create expression ((store_ptr_0 + store_segment_length_0) <= load_ptr_0) @@ -2297,70 +2255,39 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr) ((store_ptr_n + store_segment_length_n) <= load_ptr_n) || (load_ptr_n + load_segment_length_n) <= store_ptr_n)) */ - if (may_alias_ddrs.is_empty ()) + if (comp_alias_ddrs.is_empty ()) return; - FOR_EACH_VEC_ELT (may_alias_ddrs, i, ddr) + for (size_t i = 0, s = comp_alias_ddrs.length (); i < s; ++i) { - struct data_reference *dr_a, *dr_b; - gimple dr_group_first_a, dr_group_first_b; - tree addr_base_a, addr_base_b; - tree segment_length_a, segment_length_b; - gimple stmt_a, stmt_b; - tree seg_a_min, seg_a_max, seg_b_min, seg_b_max; - - dr_a = DDR_A (ddr); - stmt_a = DR_STMT (DDR_A (ddr)); - dr_group_first_a = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_a)); - if (dr_group_first_a) - { - stmt_a = dr_group_first_a; - dr_a = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt_a)); - } - - dr_b = DDR_B (ddr); - stmt_b = DR_STMT (DDR_B (ddr)); - dr_group_first_b = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_b)); - if (dr_group_first_b) - { - stmt_b = dr_group_first_b; - dr_b = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt_b)); - } + 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; + tree segment_length_a = dr_a.seg_len; + tree segment_length_b = dr_b.seg_len; - addr_base_a - = fold_build_pointer_plus (DR_BASE_ADDRESS (dr_a), - size_binop (PLUS_EXPR, DR_OFFSET (dr_a), - DR_INIT (dr_a))); - addr_base_b - = fold_build_pointer_plus (DR_BASE_ADDRESS (dr_b), - size_binop (PLUS_EXPR, DR_OFFSET (dr_b), - DR_INIT (dr_b))); - - if (!operand_equal_p (DR_STEP (dr_a), DR_STEP (dr_b), 0)) - length_factor = scalar_loop_iters; - else - length_factor = size_int (vect_factor); - segment_length_a = vect_vfa_segment_size (dr_a, length_factor); - segment_length_b = vect_vfa_segment_size (dr_b, length_factor); + tree addr_base_a + = fold_build_pointer_plus (dr_a.basic_addr, dr_a.offset); + tree addr_base_b + = fold_build_pointer_plus (dr_b.basic_addr, dr_b.offset); if (dump_enabled_p ()) { dump_printf_loc (MSG_NOTE, vect_location, - "create runtime check for data references "); - dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_a)); + "create runtime check for data references "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_a.dr)); dump_printf (MSG_NOTE, " and "); - dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_b)); - dump_printf (MSG_NOTE, "\n"); + dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_b.dr)); + dump_printf (MSG_NOTE, "\n"); } - seg_a_min = addr_base_a; - seg_a_max = fold_build_pointer_plus (addr_base_a, segment_length_a); - if (tree_int_cst_compare (DR_STEP (dr_a), size_zero_node) < 0) + tree seg_a_min = addr_base_a; + tree seg_a_max = fold_build_pointer_plus (addr_base_a, segment_length_a); + if (tree_int_cst_compare (DR_STEP (dr_a.dr), size_zero_node) < 0) seg_a_min = seg_a_max, seg_a_max = addr_base_a; - seg_b_min = addr_base_b; - seg_b_max = fold_build_pointer_plus (addr_base_b, segment_length_b); - if (tree_int_cst_compare (DR_STEP (dr_b), size_zero_node) < 0) + tree seg_b_min = addr_base_b; + tree seg_b_max = fold_build_pointer_plus (addr_base_b, segment_length_b); + if (tree_int_cst_compare (DR_STEP (dr_b.dr), size_zero_node) < 0) seg_b_min = seg_b_max, seg_b_max = addr_base_b; part_cond_expr = @@ -2378,7 +2305,9 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr) if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "created %u versioning for alias checks.\n", - may_alias_ddrs.length ()); + comp_alias_ddrs.length ()); + + comp_alias_ddrs.release (); } diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index a2f482ddad5..bbd50e1d993 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -175,6 +175,36 @@ 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. */ + +struct dr_addr_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) {} + + data_reference *dr; + tree basic_addr; + tree offset; + tree seg_len; +}; + +/* This struct contains two dr_addr_with_seg_len objects with aliasing data + refs. Two comparisons are generated from them. */ + +struct dr_addr_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) + : first (d1), second (d2) {} + + dr_addr_with_seg_len first; + dr_addr_with_seg_len second; +}; + + typedef struct _vect_peel_info { int npeel; @@ -274,6 +304,10 @@ typedef struct _loop_vec_info { for a run-time aliasing check. */ vec<ddr_p> may_alias_ddrs; + /* 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; + /* Statements in the loop that have data references that are candidates for a runtime (loop versioning) misalignment check. */ vec<gimple> may_misalign_stmts; @@ -336,6 +370,7 @@ typedef struct _loop_vec_info { #define LOOP_VINFO_MAY_MISALIGN_STMTS(L) (L)->may_misalign_stmts #define LOOP_VINFO_LOC(L) (L)->loop_line_number #define LOOP_VINFO_MAY_ALIAS_DDRS(L) (L)->may_alias_ddrs +#define LOOP_VINFO_COMP_ALIAS_DDRS(L) (L)->comp_alias_ddrs #define LOOP_VINFO_GROUPED_STORES(L) (L)->grouped_stores #define LOOP_VINFO_SLP_INSTANCES(L) (L)->slp_instances #define LOOP_VINFO_SLP_UNROLLING_FACTOR(L) (L)->slp_unrolling_factor |