On Wed, Feb 27, 2013 at 4:49 PM, Richard Biener <rguent...@suse.de> wrote: > > This splits data reference group analysis away from data dependence > checking and splits the latter into loop and a BB vectorization > functions. This allows us to perform the now no longer quadratic > but O(n * log (n)) data reference group analysis right after > data reference gathering, pushing the quadratic data dependence > testing down the vectorization analysis pipeline. > > Bootstrap and regtest running on x86_64-unknown-linux-gnu, queued for 4.9.
Committed as r196775. Richard. > Richard. > > 2013-02-27 Richard Biener <rguent...@suse.de> > > * tree-vect-data-refs.c (vect_update_interleaving_chain): Remove. > (vect_insert_into_interleaving_chain): Likewise. > (vect_drs_dependent_in_basic_block): Inline ... > (vect_slp_analyze_data_ref_dependence): ... here. New function, > split out from ... > (vect_analyze_data_ref_dependence): ... here. Simplify. > (vect_check_interleaving): Simplify. > (vect_analyze_data_ref_dependences): Likewise. Split out ... > (vect_slp_analyze_data_ref_dependences): ... this new function. > (dr_group_sort_cmp): New function. > (vect_analyze_data_ref_accesses): Compute data-reference groups > here instead of in vect_analyze_data_ref_dependence. Use > a more efficient algorithm. > * tree-vect-slp.c (vect_slp_analyze_bb_1): Use > vect_slp_analyze_data_ref_dependences. Call > vect_analyze_data_ref_accesses earlier. > * tree-vect-loop.c (vect_analyze_loop_2): Likewise. > * tree-vectorizer.h (vect_analyze_data_ref_dependences): Adjust. > (vect_slp_analyze_data_ref_dependences): New prototype. > > Index: trunk/gcc/tree-vect-data-refs.c > =================================================================== > *** trunk.orig/gcc/tree-vect-data-refs.c 2013-02-27 14:53:36.000000000 > +0100 > --- trunk/gcc/tree-vect-data-refs.c 2013-02-27 16:45:58.969861004 +0100 > *************** vect_get_place_in_interleaving_chain (gi > *** 154,394 **** > } > > > - /* Function vect_insert_into_interleaving_chain. > - > - Insert DRA into the interleaving chain of DRB according to DRA's INIT. > */ > - > - static void > - vect_insert_into_interleaving_chain (struct data_reference *dra, > - struct data_reference *drb) > - { > - gimple prev, next; > - tree next_init; > - stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra)); > - stmt_vec_info stmtinfo_b = vinfo_for_stmt (DR_STMT (drb)); > - > - prev = GROUP_FIRST_ELEMENT (stmtinfo_b); > - next = GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)); > - while (next) > - { > - next_init = DR_INIT (STMT_VINFO_DATA_REF (vinfo_for_stmt (next))); > - if (tree_int_cst_compare (next_init, DR_INIT (dra)) > 0) > - { > - /* Insert here. */ > - GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)) = DR_STMT (dra); > - GROUP_NEXT_ELEMENT (stmtinfo_a) = next; > - return; > - } > - prev = next; > - next = GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)); > - } > - > - /* We got to the end of the list. Insert here. */ > - GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)) = DR_STMT (dra); > - GROUP_NEXT_ELEMENT (stmtinfo_a) = NULL; > - } > - > - > - /* Function vect_update_interleaving_chain. > - > - For two data-refs DRA and DRB that are a part of a chain interleaved data > - accesses, update the interleaving chain. DRB's INIT is smaller than > DRA's. > - > - There are four possible cases: > - 1. New stmts - both DRA and DRB are not a part of any chain: > - FIRST_DR = DRB > - NEXT_DR (DRB) = DRA > - 2. DRB is a part of a chain and DRA is not: > - no need to update FIRST_DR > - no need to insert DRB > - insert DRA according to init > - 3. DRA is a part of a chain and DRB is not: > - if (init of FIRST_DR > init of DRB) > - FIRST_DR = DRB > - NEXT(FIRST_DR) = previous FIRST_DR > - else > - insert DRB according to its init > - 4. both DRA and DRB are in some interleaving chains: > - choose the chain with the smallest init of FIRST_DR > - insert the nodes of the second chain into the first one. */ > - > - static void > - vect_update_interleaving_chain (struct data_reference *drb, > - struct data_reference *dra) > - { > - stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra)); > - stmt_vec_info stmtinfo_b = vinfo_for_stmt (DR_STMT (drb)); > - tree next_init, init_dra_chain, init_drb_chain; > - gimple first_a, first_b; > - tree node_init; > - gimple node, prev, next, first_stmt; > - > - /* 1. New stmts - both DRA and DRB are not a part of any chain. */ > - if (!GROUP_FIRST_ELEMENT (stmtinfo_a) && !GROUP_FIRST_ELEMENT > (stmtinfo_b)) > - { > - GROUP_FIRST_ELEMENT (stmtinfo_a) = DR_STMT (drb); > - GROUP_FIRST_ELEMENT (stmtinfo_b) = DR_STMT (drb); > - GROUP_NEXT_ELEMENT (stmtinfo_b) = DR_STMT (dra); > - return; > - } > - > - /* 2. DRB is a part of a chain and DRA is not. */ > - if (!GROUP_FIRST_ELEMENT (stmtinfo_a) && GROUP_FIRST_ELEMENT (stmtinfo_b)) > - { > - GROUP_FIRST_ELEMENT (stmtinfo_a) = GROUP_FIRST_ELEMENT (stmtinfo_b); > - /* Insert DRA into the chain of DRB. */ > - vect_insert_into_interleaving_chain (dra, drb); > - return; > - } > - > - /* 3. DRA is a part of a chain and DRB is not. */ > - if (GROUP_FIRST_ELEMENT (stmtinfo_a) && !GROUP_FIRST_ELEMENT (stmtinfo_b)) > - { > - gimple old_first_stmt = GROUP_FIRST_ELEMENT (stmtinfo_a); > - tree init_old = DR_INIT (STMT_VINFO_DATA_REF (vinfo_for_stmt ( > - > old_first_stmt))); > - gimple tmp; > - > - if (tree_int_cst_compare (init_old, DR_INIT (drb)) > 0) > - { > - /* DRB's init is smaller than the init of the stmt previously marked > - as the first stmt of the interleaving chain of DRA. Therefore, > we > - update FIRST_STMT and put DRB in the head of the list. */ > - GROUP_FIRST_ELEMENT (stmtinfo_b) = DR_STMT (drb); > - GROUP_NEXT_ELEMENT (stmtinfo_b) = old_first_stmt; > - > - /* Update all the stmts in the list to point to the new FIRST_STMT. > */ > - tmp = old_first_stmt; > - while (tmp) > - { > - GROUP_FIRST_ELEMENT (vinfo_for_stmt (tmp)) = DR_STMT (drb); > - tmp = GROUP_NEXT_ELEMENT (vinfo_for_stmt (tmp)); > - } > - } > - else > - { > - /* Insert DRB in the list of DRA. */ > - vect_insert_into_interleaving_chain (drb, dra); > - GROUP_FIRST_ELEMENT (stmtinfo_b) = GROUP_FIRST_ELEMENT (stmtinfo_a); > - } > - return; > - } > - > - /* 4. both DRA and DRB are in some interleaving chains. */ > - first_a = GROUP_FIRST_ELEMENT (stmtinfo_a); > - first_b = GROUP_FIRST_ELEMENT (stmtinfo_b); > - if (first_a == first_b) > - return; > - init_dra_chain = DR_INIT (STMT_VINFO_DATA_REF (vinfo_for_stmt (first_a))); > - init_drb_chain = DR_INIT (STMT_VINFO_DATA_REF (vinfo_for_stmt (first_b))); > - > - if (tree_int_cst_compare (init_dra_chain, init_drb_chain) > 0) > - { > - /* Insert the nodes of DRA chain into the DRB chain. > - After inserting a node, continue from this node of the DRB chain > (don't > - start from the beginning. */ > - node = GROUP_FIRST_ELEMENT (stmtinfo_a); > - prev = GROUP_FIRST_ELEMENT (stmtinfo_b); > - first_stmt = first_b; > - } > - else > - { > - /* Insert the nodes of DRB chain into the DRA chain. > - After inserting a node, continue from this node of the DRA chain > (don't > - start from the beginning. */ > - node = GROUP_FIRST_ELEMENT (stmtinfo_b); > - prev = GROUP_FIRST_ELEMENT (stmtinfo_a); > - first_stmt = first_a; > - } > - > - while (node) > - { > - node_init = DR_INIT (STMT_VINFO_DATA_REF (vinfo_for_stmt (node))); > - next = GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)); > - while (next) > - { > - next_init = DR_INIT (STMT_VINFO_DATA_REF (vinfo_for_stmt (next))); > - if (tree_int_cst_compare (next_init, node_init) > 0) > - { > - /* Insert here. */ > - GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)) = node; > - GROUP_NEXT_ELEMENT (vinfo_for_stmt (node)) = next; > - prev = node; > - break; > - } > - prev = next; > - next = GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)); > - } > - if (!next) > - { > - /* We got to the end of the list. Insert here. */ > - GROUP_NEXT_ELEMENT (vinfo_for_stmt (prev)) = node; > - GROUP_NEXT_ELEMENT (vinfo_for_stmt (node)) = NULL; > - prev = node; > - } > - GROUP_FIRST_ELEMENT (vinfo_for_stmt (node)) = first_stmt; > - node = GROUP_NEXT_ELEMENT (vinfo_for_stmt (node)); > - } > - } > - > - /* Check dependence between DRA and DRB for basic block vectorization. > - If the accesses share same bases and offsets, we can compare their > initial > - constant offsets to decide whether they differ or not. In case of a > read- > - write dependence we check that the load is before the store to ensure > that > - vectorization will not change the order of the accesses. */ > - > - static bool > - vect_drs_dependent_in_basic_block (struct data_reference *dra, > - struct data_reference *drb) > - { > - HOST_WIDE_INT type_size_a, type_size_b, init_a, init_b; > - gimple earlier_stmt; > - > - /* We only call this function for pairs of loads and stores, but we verify > - it here. */ > - if (DR_IS_READ (dra) == DR_IS_READ (drb)) > - { > - if (DR_IS_READ (dra)) > - return false; > - else > - return true; > - } > - > - /* Check that the data-refs have same bases and offsets. If not, we can't > - determine if they are dependent. */ > - if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0) > - || !dr_equal_offsets_p (dra, drb)) > - return true; > - > - /* Check the types. */ > - type_size_a = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (dra)))); > - type_size_b = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (drb)))); > - > - if (type_size_a != type_size_b > - || !types_compatible_p (TREE_TYPE (DR_REF (dra)), > - TREE_TYPE (DR_REF (drb)))) > - return true; > - > - init_a = TREE_INT_CST_LOW (DR_INIT (dra)); > - init_b = TREE_INT_CST_LOW (DR_INIT (drb)); > - > - /* Two different locations - no dependence. */ > - if (init_a != init_b) > - return false; > - > - /* We have a read-write dependence. Check that the load is before the > store. > - When we vectorize basic blocks, vector load can be only before > - corresponding scalar load, and vector store can be only after its > - corresponding scalar store. So the order of the acceses is preserved > in > - case the load is before the store. */ > - earlier_stmt = get_earlier_stmt (DR_STMT (dra), DR_STMT (drb)); > - if (DR_IS_READ (STMT_VINFO_DATA_REF (vinfo_for_stmt (earlier_stmt)))) > - return false; > - > - return true; > - } > - > - > /* Function vect_check_interleaving. > > Check if DRA and DRB are a part of interleaving. In case they are, > insert > --- 154,159 ---- > *************** static bool > *** 398,479 **** > vect_check_interleaving (struct data_reference *dra, > struct data_reference *drb) > { > ! HOST_WIDE_INT type_size_a, type_size_b, diff_mod_size, step, init_a, > init_b; > > ! /* Check that the data-refs have same first location (except init) and > they > ! are both either store or load (not load and store). */ > if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0) > || !dr_equal_offsets_p (dra, drb) > - || !tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb)) > || DR_IS_READ (dra) != DR_IS_READ (drb)) > ! return false; > > ! /* Check: > ! 1. data-refs are of the same type > ! 2. their steps are equal > ! 3. the step (if greater than zero) is greater than the difference > between > ! data-refs' inits. */ > type_size_a = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (dra)))); > type_size_b = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (drb)))); > - > if (type_size_a != type_size_b > ! || tree_int_cst_compare (DR_STEP (dra), DR_STEP (drb)) > ! || !types_compatible_p (TREE_TYPE (DR_REF (dra)), > ! TREE_TYPE (DR_REF (drb)))) > return false; > > init_a = TREE_INT_CST_LOW (DR_INIT (dra)); > init_b = TREE_INT_CST_LOW (DR_INIT (drb)); > step = TREE_INT_CST_LOW (DR_STEP (dra)); > > ! if (init_a > init_b) > ! { > ! /* If init_a == init_b + the size of the type * k, we have an > interleaving, > ! and DRB is accessed before DRA. */ > ! diff_mod_size = (init_a - init_b) % type_size_a; > ! > ! if (step && (init_a - init_b) > step) > ! return false; > > ! if (diff_mod_size == 0) > ! { > ! vect_update_interleaving_chain (drb, dra); > ! if (dump_enabled_p ()) > ! { > ! dump_printf_loc (MSG_NOTE, vect_location, > ! "Detected interleaving "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dra)); > ! dump_printf (MSG_NOTE, " and "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (drb)); > ! } > ! return true; > ! } > ! } > ! else > ! { > ! /* If init_b == init_a + the size of the type * k, we have an > ! interleaving, and DRA is accessed before DRB. */ > ! diff_mod_size = (init_b - init_a) % type_size_a; > > ! if (step && (init_b - init_a) > step) > ! return false; > > ! if (diff_mod_size == 0) > ! { > ! vect_update_interleaving_chain (dra, drb); > ! if (dump_enabled_p ()) > ! { > ! dump_printf_loc (MSG_NOTE, vect_location, > ! "Detected interleaving "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dra)); > ! dump_printf (MSG_NOTE, " and "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (drb)); > ! } > ! return true; > ! } > } > > ! return false; > } > > /* Check if data references pointed by DR_I and DR_J are same or > --- 163,220 ---- > vect_check_interleaving (struct data_reference *dra, > struct data_reference *drb) > { > ! HOST_WIDE_INT type_size_a, type_size_b, step, init_a, init_b; > > ! /* The caller has ensured that the data-refs have same first location > ! (except init) and they are both either store or load. */ > if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0) > || !dr_equal_offsets_p (dra, drb) > || DR_IS_READ (dra) != DR_IS_READ (drb)) > ! gcc_unreachable (); > > ! /* The caller has ensured type sizes and steps are equal. */ > type_size_a = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (dra)))); > type_size_b = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (drb)))); > if (type_size_a != type_size_b > ! || tree_int_cst_compare (DR_STEP (dra), DR_STEP (drb)) != 0) > ! gcc_unreachable (); > ! > ! /* Do not place the same access in the interleaving chain twice. */ > ! if (tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb)) == 0) > ! return false; > ! > ! /* Check the types are compatible. */ > ! if (!types_compatible_p (TREE_TYPE (DR_REF (dra)), > ! TREE_TYPE (DR_REF (drb)))) > return false; > > init_a = TREE_INT_CST_LOW (DR_INIT (dra)); > init_b = TREE_INT_CST_LOW (DR_INIT (drb)); > step = TREE_INT_CST_LOW (DR_STEP (dra)); > > ! /* The caller has ensured that DR_INIT (dra) <= DR_INIT (drb). */ > ! gcc_assert (init_a < init_b); > > ! /* If init_b == init_a + the size of the type * k, we have an > ! interleaving, and DRA is accessed before DRB. */ > ! if ((init_b - init_a) % type_size_a != 0) > ! return false; > > ! /* The step (if not zero) is greater than the difference between > ! data-refs' inits. This splits groups into suitable sizes. */ > ! if (step != 0 && step <= (init_b - init_a)) > ! return false; > > ! if (dump_enabled_p ()) > ! { > ! dump_printf_loc (MSG_NOTE, vect_location, > ! "Detected interleaving "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dra)); > ! dump_printf (MSG_NOTE, " and "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (drb)); > } > > ! return true; > } > > /* Check if data references pointed by DR_I and DR_J are same or > *************** vect_analyze_data_ref_dependence (struct > *** 578,584 **** > loop_vec_info loop_vinfo, int *max_vf) > { > unsigned int i; > ! struct loop *loop = NULL; > struct data_reference *dra = DDR_A (ddr); > struct data_reference *drb = DDR_B (ddr); > stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra)); > --- 319,325 ---- > loop_vec_info loop_vinfo, int *max_vf) > { > unsigned int i; > ! struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); > struct data_reference *dra = DDR_A (ddr); > struct data_reference *drb = DDR_B (ddr); > stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra)); > *************** vect_analyze_data_ref_dependence (struct > *** 586,688 **** > lambda_vector dist_v; > unsigned int loop_depth; > > ! /* Don't bother to analyze statements marked as unvectorizable. */ > if (!STMT_VINFO_VECTORIZABLE (stmtinfo_a) > || !STMT_VINFO_VECTORIZABLE (stmtinfo_b)) > ! return false; > > if (DDR_ARE_DEPENDENT (ddr) == chrec_known) > ! { > ! /* Independent data accesses. */ > ! vect_check_interleaving (dra, drb); > ! return false; > ! } > ! > ! if (loop_vinfo) > ! loop = LOOP_VINFO_LOOP (loop_vinfo); > > ! if ((DR_IS_READ (dra) && DR_IS_READ (drb) && loop_vinfo) || dra == drb) > return false; > > if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) > { > - gimple earlier_stmt; > - > - if (loop_vinfo) > - { > - if (dump_enabled_p ()) > - { > - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > - "versioning for alias required: " > - "can't determine dependence between "); > - dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, > - DR_REF (dra)); > - dump_printf (MSG_MISSED_OPTIMIZATION, " and "); > - dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, > - DR_REF (drb)); > - } > - > - /* Add to list of ddrs that need to be tested at run-time. */ > - return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo); > - } > - > - /* When vectorizing a basic block unknown depnedence can still mean > - grouped access. */ > - if (vect_check_interleaving (dra, drb)) > - return false; > - > - /* Read-read is OK (we need this check here, after checking for > - interleaving). */ > - if (DR_IS_READ (dra) && DR_IS_READ (drb)) > - return false; > - > - if (dump_enabled_p ()) > - { > - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > - "can't determine dependence between "); > - dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, DR_REF > (dra)); > - dump_printf (MSG_MISSED_OPTIMIZATION, " and "); > - dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, DR_REF > (drb)); > - } > - > - /* We do not vectorize basic blocks with write-write dependencies. */ > - if (DR_IS_WRITE (dra) && DR_IS_WRITE (drb)) > - return true; > - > - /* Check that it's not a load-after-store dependence. */ > - earlier_stmt = get_earlier_stmt (DR_STMT (dra), DR_STMT (drb)); > - if (DR_IS_WRITE (STMT_VINFO_DATA_REF (vinfo_for_stmt (earlier_stmt)))) > - return true; > - > - return false; > - } > - > - /* Versioning for alias is not yet supported for basic block SLP, and > - dependence distance is unapplicable, hence, in case of known data > - dependence, basic block vectorization is impossible for now. */ > - if (!loop_vinfo) > - { > - if (dra != drb && vect_check_interleaving (dra, drb)) > - return false; > - > if (dump_enabled_p ()) > ! { > ! dump_printf_loc (MSG_NOTE, vect_location, > ! "determined dependence between "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dra)); > ! dump_printf (MSG_NOTE, " and "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (drb)); > ! } > ! > ! /* Do not vectorize basic blcoks with write-write dependences. */ > ! if (DR_IS_WRITE (dra) && DR_IS_WRITE (drb)) > ! return true; > > ! /* Check if this dependence is allowed in basic block vectorization. > */ > ! return vect_drs_dependent_in_basic_block (dra, drb); > } > > ! /* Loop-based vectorization and known data dependence. */ > if (DDR_NUM_DIST_VECTS (ddr) == 0) > { > if (dump_enabled_p ()) > --- 327,365 ---- > lambda_vector dist_v; > unsigned int loop_depth; > > ! /* In loop analysis all data references should be vectorizable. */ > if (!STMT_VINFO_VECTORIZABLE (stmtinfo_a) > || !STMT_VINFO_VECTORIZABLE (stmtinfo_b)) > ! gcc_unreachable (); > > + /* Independent data accesses. */ > if (DDR_ARE_DEPENDENT (ddr) == chrec_known) > ! return false; > > ! if (dra == drb > ! || (DR_IS_READ (dra) && DR_IS_READ (drb))) > return false; > > + /* Unknown data dependence. */ > if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) > { > if (dump_enabled_p ()) > ! { > ! dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > ! "versioning for alias required: " > ! "can't determine dependence between "); > ! dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, > ! DR_REF (dra)); > ! dump_printf (MSG_MISSED_OPTIMIZATION, " and "); > ! dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, > ! DR_REF (drb)); > ! } > > ! /* Add to list of ddrs that need to be tested at run-time. */ > ! return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo); > } > > ! /* Known data dependence. */ > if (DDR_NUM_DIST_VECTS (ddr) == 0) > { > if (dump_enabled_p ()) > *************** vect_analyze_data_ref_dependence (struct > *** 719,725 **** > } > > /* For interleaving, mark that there is a read-write dependency if > ! necessary. We check before that one of the data-refs is store. > */ > if (DR_IS_READ (dra)) > GROUP_READ_WRITE_DEPENDENCE (stmtinfo_a) = true; > else > --- 396,402 ---- > } > > /* For interleaving, mark that there is a read-write dependency if > ! necessary. We check before that one of the data-refs is > store. */ > if (DR_IS_READ (dra)) > GROUP_READ_WRITE_DEPENDENCE (stmtinfo_a) = true; > else > *************** vect_analyze_data_ref_dependence (struct > *** 787,821 **** > the maximum vectorization factor the data dependences allow. */ > > bool > ! vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo, > ! bb_vec_info bb_vinfo, int *max_vf) > { > unsigned int i; > - vec<ddr_p> ddrs = vNULL; > struct data_dependence_relation *ddr; > > if (dump_enabled_p ()) > dump_printf_loc (MSG_NOTE, vect_location, > ! "=== vect_analyze_dependences ==="); > ! if (loop_vinfo) > { > ! if (!compute_all_dependences (LOOP_VINFO_DATAREFS (loop_vinfo), > ! &LOOP_VINFO_DDRS (loop_vinfo), > ! LOOP_VINFO_LOOP_NEST (loop_vinfo), true)) > ! return false; > ! ddrs = LOOP_VINFO_DDRS (loop_vinfo); > } > ! else > { > ! if (!compute_all_dependences (BB_VINFO_DATAREFS (bb_vinfo), > ! &BB_VINFO_DDRS (bb_vinfo), > ! vNULL, true)) > ! return false; > ! ddrs = BB_VINFO_DDRS (bb_vinfo); > } > > ! FOR_EACH_VEC_ELT (ddrs, i, ddr) > ! if (vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf)) > return false; > > return true; > --- 464,624 ---- > the maximum vectorization factor the data dependences allow. */ > > bool > ! vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo, int *max_vf) > { > unsigned int i; > struct data_dependence_relation *ddr; > > if (dump_enabled_p ()) > dump_printf_loc (MSG_NOTE, vect_location, > ! "=== vect_analyze_data_ref_dependences ==="); > ! > ! if (!compute_all_dependences (LOOP_VINFO_DATAREFS (loop_vinfo), > ! &LOOP_VINFO_DDRS (loop_vinfo), > ! LOOP_VINFO_LOOP_NEST (loop_vinfo), true)) > ! return false; > ! > ! FOR_EACH_VEC_ELT (LOOP_VINFO_DDRS (loop_vinfo), i, ddr) > ! if (vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf)) > ! return false; > ! > ! return true; > ! } > ! > ! > ! /* Function vect_slp_analyze_data_ref_dependence. > ! > ! Return TRUE if there (might) exist a dependence between a > memory-reference > ! DRA and a memory-reference DRB. When versioning for alias may check a > ! dependence at run-time, return FALSE. Adjust *MAX_VF according to > ! the data dependence. */ > ! > ! static bool > ! vect_slp_analyze_data_ref_dependence (struct data_dependence_relation *ddr) > ! { > ! struct data_reference *dra = DDR_A (ddr); > ! struct data_reference *drb = DDR_B (ddr); > ! > ! /* We need to check dependences of statements marked as unvectorizable > ! as well, they still can prohibit vectorization. */ > ! > ! /* Independent data accesses. */ > ! if (DDR_ARE_DEPENDENT (ddr) == chrec_known) > ! return false; > ! > ! if (dra == drb) > ! return false; > ! > ! /* Read-read is OK. */ > ! if (DR_IS_READ (dra) && DR_IS_READ (drb)) > ! return false; > ! > ! /* Unknown data dependence. */ > ! if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) > { > ! gimple earlier_stmt; > ! > ! if (dump_enabled_p ()) > ! { > ! dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > ! "can't determine dependence between "); > ! dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, DR_REF > (dra)); > ! dump_printf (MSG_MISSED_OPTIMIZATION, " and "); > ! dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, DR_REF > (drb)); > ! } > ! > ! /* We do not vectorize basic blocks with write-write dependencies. */ > ! if (DR_IS_WRITE (dra) && DR_IS_WRITE (drb)) > ! return true; > ! > ! /* Check that it's not a load-after-store dependence. */ > ! earlier_stmt = get_earlier_stmt (DR_STMT (dra), DR_STMT (drb)); > ! if (DR_IS_WRITE (STMT_VINFO_DATA_REF (vinfo_for_stmt (earlier_stmt)))) > ! return true; > ! > ! return false; > } > ! > ! if (dump_enabled_p ()) > { > ! dump_printf_loc (MSG_NOTE, vect_location, > ! "determined dependence between "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dra)); > ! dump_printf (MSG_NOTE, " and "); > ! dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (drb)); > } > > ! /* Do not vectorize basic blocks with write-write dependences. */ > ! if (DR_IS_WRITE (dra) && DR_IS_WRITE (drb)) > ! return true; > ! > ! /* Check dependence between DRA and DRB for basic block vectorization. > ! If the accesses share same bases and offsets, we can compare their > initial > ! constant offsets to decide whether they differ or not. In case of a > read- > ! write dependence we check that the load is before the store to ensure > that > ! vectorization will not change the order of the accesses. */ > ! > ! HOST_WIDE_INT type_size_a, type_size_b, init_a, init_b; > ! gimple earlier_stmt; > ! > ! /* Check that the data-refs have same bases and offsets. If not, we can't > ! determine if they are dependent. */ > ! if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0) > ! || !dr_equal_offsets_p (dra, drb)) > ! return true; > ! > ! /* Check the types. */ > ! type_size_a = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (dra)))); > ! type_size_b = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (drb)))); > ! > ! if (type_size_a != type_size_b > ! || !types_compatible_p (TREE_TYPE (DR_REF (dra)), > ! TREE_TYPE (DR_REF (drb)))) > ! return true; > ! > ! init_a = TREE_INT_CST_LOW (DR_INIT (dra)); > ! init_b = TREE_INT_CST_LOW (DR_INIT (drb)); > ! > ! /* Two different locations - no dependence. */ > ! if (init_a != init_b) > ! return false; > ! > ! /* We have a read-write dependence. Check that the load is before the > store. > ! When we vectorize basic blocks, vector load can be only before > ! corresponding scalar load, and vector store can be only after its > ! corresponding scalar store. So the order of the acceses is preserved > in > ! case the load is before the store. */ > ! earlier_stmt = get_earlier_stmt (DR_STMT (dra), DR_STMT (drb)); > ! if (DR_IS_READ (STMT_VINFO_DATA_REF (vinfo_for_stmt (earlier_stmt)))) > ! return false; > ! > ! return true; > ! } > ! > ! > ! /* Function vect_analyze_data_ref_dependences. > ! > ! Examine all the data references in the basic-block, and make sure there > ! do not exist any data dependences between them. Set *MAX_VF according to > ! the maximum vectorization factor the data dependences allow. */ > ! > ! bool > ! vect_slp_analyze_data_ref_dependences (bb_vec_info bb_vinfo) > ! { > ! struct data_dependence_relation *ddr; > ! unsigned int i; > ! > ! if (dump_enabled_p ()) > ! dump_printf_loc (MSG_NOTE, vect_location, > ! "=== vect_slp_analyze_data_ref_dependences ==="); > ! > ! if (!compute_all_dependences (BB_VINFO_DATAREFS (bb_vinfo), > ! &BB_VINFO_DDRS (bb_vinfo), > ! vNULL, true)) > ! return false; > ! > ! FOR_EACH_VEC_ELT (BB_VINFO_DDRS (bb_vinfo), i, ddr) > ! if (vect_slp_analyze_data_ref_dependence (ddr)) > return false; > > return true; > *************** vect_analyze_data_ref_access (struct dat > *** 2567,2572 **** > --- 2370,2425 ---- > return vect_analyze_group_access (dr); > } > > + /* 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_); > + int cmp; > + > + /* Stabilize sort. */ > + if (dra == drb) > + return 0; > + > + /* Ordering of DRs with unequal base or offset according to a hash. */ > + if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0) > + || !dr_equal_offsets_p (dra, drb)) > + { > + hashval_t h1 > + = iterative_hash_expr (DR_BASE_ADDRESS (dra), > + iterative_hash_expr (DR_OFFSET (dra), 0)); > + hashval_t h2 > + = iterative_hash_expr (DR_BASE_ADDRESS (drb), > + iterative_hash_expr (DR_OFFSET (drb), 0)); > + if (h1 == h2) > + gcc_unreachable (); > + return h1 < h2 ? -1 : 1; > + } > + > + /* Else put reads first. */ > + if (DR_IS_READ (dra) != DR_IS_READ (drb)) > + return DR_IS_READ (dra) ? -1 : 1; > + > + /* Then sort after access size. */ > + cmp = tree_int_cst_compare (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dra))), > + TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drb)))); > + if (cmp != 0) > + return cmp; > + > + /* And after step. */ > + cmp = tree_int_cst_compare (DR_STEP (dra), DR_STEP (drb)); > + if (cmp != 0) > + return cmp; > + > + /* Then sort after DR_INIT. In case of identical DRs sort after stmt > UID. */ > + cmp = tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb)); > + if (cmp == 0) > + return gimple_uid (DR_STMT (dra)) < gimple_uid (DR_STMT (drb)) ? -1 : 1; > + return cmp; > + } > > /* Function vect_analyze_data_ref_accesses. > > *************** vect_analyze_data_ref_accesses (loop_vec > *** 2593,2598 **** > --- 2446,2497 ---- > else > datarefs = BB_VINFO_DATAREFS (bb_vinfo); > > + if (datarefs.is_empty ()) > + return true; > + > + /* Sort the array of datarefs to make building the interleaving chains > + linear. */ > + qsort (datarefs.address(), datarefs.length (), > + sizeof (data_reference_p), dr_group_sort_cmp); > + > + /* Build the interleaving chains. */ > + for (i = 0; i < datarefs.length () - 1;) > + { > + data_reference_p dra = datarefs[i]; > + stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra)); > + stmt_vec_info lastinfo = NULL; > + for (i = i + 1; i < datarefs.length (); ++i) > + { > + data_reference_p drb = datarefs[i]; > + stmt_vec_info stmtinfo_b = vinfo_for_stmt (DR_STMT (drb)); > + /* Check that the data-refs have same first location (except init) > + and they are both either store or load (not load and store). > + Check that the data-refs have the same size and step. */ > + if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), > 0) > + || !dr_equal_offsets_p (dra, drb) > + || DR_IS_READ (dra) != DR_IS_READ (drb) > + || tree_int_cst_compare (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (dra))), > + TYPE_SIZE_UNIT (TREE_TYPE (DR_REF > (drb)))) > + || tree_int_cst_compare (DR_STEP (dra), DR_STEP (drb))) > + break; > + /* ??? Imperfect sorting (non-compatible types, non-modulo > + accesses, same accesses) can lead to a group to be artificially > + split here as we don't just skip over those. If it really > + matters we can push those to a worklist and re-iterate > + over them. The we can just skip ahead to the next DR here. */ > + if (!vect_check_interleaving (dra, drb)) > + break; > + if (!GROUP_FIRST_ELEMENT (stmtinfo_a)) > + { > + GROUP_FIRST_ELEMENT (stmtinfo_a) = DR_STMT (dra); > + lastinfo = stmtinfo_a; > + } > + GROUP_FIRST_ELEMENT (stmtinfo_b) = DR_STMT (dra); > + GROUP_NEXT_ELEMENT (lastinfo) = DR_STMT (drb); > + lastinfo = stmtinfo_b; > + } > + } > + > FOR_EACH_VEC_ELT (datarefs, i, dr) > if (STMT_VINFO_VECTORIZABLE (vinfo_for_stmt (DR_STMT (dr))) > && !vect_analyze_data_ref_access (dr)) > Index: trunk/gcc/tree-vect-slp.c > =================================================================== > *** trunk.orig/gcc/tree-vect-slp.c 2013-02-27 14:53:36.000000000 +0100 > --- trunk/gcc/tree-vect-slp.c 2013-02-27 14:57:30.977783197 +0100 > *************** vect_slp_analyze_bb_1 (basic_block bb) > *** 2089,2095 **** > slp_instance instance; > int i; > int min_vf = 2; > - int max_vf = MAX_VECTORIZATION_FACTOR; > > bb_vinfo = new_bb_vec_info (bb); > if (!bb_vinfo) > --- 2089,2094 ---- > *************** vect_slp_analyze_bb_1 (basic_block bb) > *** 2117,2126 **** > return NULL; > } > > vect_pattern_recog (NULL, bb_vinfo); > > ! if (!vect_analyze_data_ref_dependences (NULL, bb_vinfo, &max_vf) > ! || min_vf > max_vf) > { > if (dump_enabled_p ()) > dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > --- 2116,2135 ---- > return NULL; > } > > + if (!vect_analyze_data_ref_accesses (NULL, bb_vinfo)) > + { > + if (dump_enabled_p ()) > + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > + "not vectorized: unhandled data access in " > + "basic block.\n"); > + > + destroy_bb_vec_info (bb_vinfo); > + return NULL; > + } > + > vect_pattern_recog (NULL, bb_vinfo); > > ! if (!vect_slp_analyze_data_ref_dependences (bb_vinfo)) > { > if (dump_enabled_p ()) > dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > *************** vect_slp_analyze_bb_1 (basic_block bb) > *** 2140,2156 **** > > destroy_bb_vec_info (bb_vinfo); > return NULL; > - } > - > - if (!vect_analyze_data_ref_accesses (NULL, bb_vinfo)) > - { > - if (dump_enabled_p ()) > - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > - "not vectorized: unhandled data access in " > - "basic block.\n"); > - > - destroy_bb_vec_info (bb_vinfo); > - return NULL; > } > > /* Check the SLP opportunities in the basic block, analyze and build SLP > --- 2149,2154 ---- > Index: trunk/gcc/tree-vect-loop.c > =================================================================== > *** trunk.orig/gcc/tree-vect-loop.c 2013-02-27 14:53:36.000000000 +0100 > --- trunk/gcc/tree-vect-loop.c 2013-02-27 14:57:30.978783208 +0100 > *************** vect_analyze_loop_2 (loop_vec_info loop_ > *** 1603,1608 **** > --- 1603,1620 ---- > return false; > } > > + /* 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, NULL); > + if (!ok) > + { > + if (dump_enabled_p ()) > + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > + "bad data access."); > + return false; > + } > + > /* Classify all cross-iteration scalar data-flow cycles. > Cross-iteration cycles caused by virtual phis are analyzed separately. > */ > > *************** vect_analyze_loop_2 (loop_vec_info loop_ > *** 1626,1632 **** > the dependences. > FORNOW: fail at the first data dependence that we encounter. */ > > ! ok = vect_analyze_data_ref_dependences (loop_vinfo, NULL, &max_vf); > if (!ok > || max_vf < min_vf) > { > --- 1638,1644 ---- > the dependences. > FORNOW: fail at the first data dependence that we encounter. */ > > ! ok = vect_analyze_data_ref_dependences (loop_vinfo, &max_vf); > if (!ok > || max_vf < min_vf) > { > *************** vect_analyze_loop_2 (loop_vec_info loop_ > *** 1664,1681 **** > return false; > } > > - /* 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, NULL); > - if (!ok) > - { > - if (dump_enabled_p ()) > - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, > - "bad data access."); > - return false; > - } > - > /* Prune the list of ddrs to be tested at run-time by versioning for > alias. > It is important to call pruning after vect_analyze_data_ref_accesses, > since we use grouping information gathered by interleaving analysis. > */ > --- 1676,1681 ---- > Index: trunk/gcc/tree-vectorizer.h > =================================================================== > *** trunk.orig/gcc/tree-vectorizer.h 2013-02-27 14:53:36.000000000 +0100 > --- trunk/gcc/tree-vectorizer.h 2013-02-27 14:57:30.978783208 +0100 > *************** extern enum dr_alignment_support vect_su > *** 914,921 **** > (struct data_reference *, bool); > extern tree vect_get_smallest_scalar_type (gimple, HOST_WIDE_INT *, > HOST_WIDE_INT *); > ! extern bool vect_analyze_data_ref_dependences (loop_vec_info, bb_vec_info, > ! int *); > extern bool vect_enhance_data_refs_alignment (loop_vec_info); > extern bool vect_analyze_data_refs_alignment (loop_vec_info, bb_vec_info); > extern bool vect_verify_datarefs_alignment (loop_vec_info, bb_vec_info); > --- 914,921 ---- > (struct data_reference *, bool); > extern tree vect_get_smallest_scalar_type (gimple, HOST_WIDE_INT *, > HOST_WIDE_INT *); > ! extern bool vect_analyze_data_ref_dependences (loop_vec_info, int *); > ! extern bool vect_slp_analyze_data_ref_dependences (bb_vec_info); > extern bool vect_enhance_data_refs_alignment (loop_vec_info); > extern bool vect_analyze_data_refs_alignment (loop_vec_info, bb_vec_info); > extern bool vect_verify_datarefs_alignment (loop_vec_info, bb_vec_info);