diff options
author | irar <irar@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-07-25 12:05:07 +0000 |
---|---|---|
committer | irar <irar@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-07-25 12:05:07 +0000 |
commit | 516849c7cdbe9be15bb886db53588d1cc868e795 (patch) | |
tree | 2c7091212ab12d18c54b6a9e333f0b9450742dab /gcc/tree-vect-analyze.c | |
parent | e8089f751c03c2f2d0709b475a22b42e0cc402a2 (diff) | |
download | gcc-516849c7cdbe9be15bb886db53588d1cc868e795.tar.gz |
* expr.c (highest_pow2_factor): Make extern.
* tree-data-ref.c (ptr_decl_may_alias_p): New function.
(ptr_ptr_may_alias_p, may_alias_p, record_ptr_differ_p,
record_array_differ_p, array_ptr_differ_p): Likewise.
(base_object_differ_p): Rename (from array_base_name_differ_p). Support
additional cases. Call the above functions.
(base_addr_differ_p): Moved from tree-vect-analyze.c. Call
base_object_differ_p when there are two base objects. Otherwise, compare
base address and offset. Call may_alias_p.
(dump_data_reference): Use a correct field name.
(analyze_array): Make static. Initialize new data-ref fields.
(analyze_indirect_ref): New function.
(init_data_ref): Initialize new data-ref fields.
(strip_conversion): Moved from tree-vect-analyze.c.
(analyze_offset_expr, get_ptr_offset, address_analysis, object_analysis):
Likewise.
(analyze_offset): New function.
(create_data_ref): Likewise.
(initialize_data_dependence_relation): Call base_addr_differ_p. Compare
dimensions for ARRAY_REFs only.
(build_classic_dist_vector): Make static.
(access_functions_are_affine_or_constant_p): Call macro to get the
address of access functions.
(compute_all_dependences): Add new parameter
compute_self_and_read_read_dependences. Compute self and read-read
dependences if it is true.
(find_data_references_in_loop): Call create_data_ref. Initialize new
data-ref fields.
(compute_data_dependences_for_loop): Add new parameter
compute_self_and_read_read_dependences. Remove parameter nb_loops,
compute nb_loops. Call compute_all_dependences, build_classic_dist_vector
and build_classic_dir_vector with correct parameters.
(analyze_all_data_dependences): Call compute_data_dependences_for_loop with
correct parameters. Compare dimensions for ARRAY_REFs only.
(free_data_refs): Call macro to free access functions.
* tree-data-ref.h (struct first_location_in_loop): New structure. Move
fields from stmt_vinfo.
(struct base_object_info): New structure.
(struct data_reference): Move fields to base_object_info. Add fields
first_location and object_info for above structures. Move fields from
stmt_info: memtag, ptr_info, subvars, misalignment. Add new field aligned_to.
Add macros to access the new fields.
Update functions declarations.
* tree-flow.h (is_aliased_with): Declare.
* tree-loop-linear.c (linear_transform_loops): Call
compute_data_dependences_for_loop with correct parameters.
* tree-ssa-alias.c (is_aliased_with): New function.
* tree-vect-analyze.c (vect_get_ptr_offset): Remove.
(vect_analyze_offset_expr, vect_base_addr_differ_p): Likewise.
(vect_analyze_data_ref_dependence): Get ddr. Remove call to
vect_base_addr_differ_p, compute_subscript_distance and
build_classic_dist_vector. Add printings. Check absolute value of
distance.
(vect_analyze_data_ref_dependences): Go through ddrs instead of data-refs.
(vect_compute_data_ref_alignment): Get the fields of data-ref instead of
stmt. Check aligned_to. Check if the base is aligned. Remove conversion
to bytes. Add printing.
(vect_compute_data_refs_alignment): Go through loads and stores in one loop.
(vect_enhance_data_refs_alignment, vect_analyze_data_refs_alignment,
vect_analyze_data_ref_access): Likewise.
(vect_analyze_pointer_ref_access): Remove.
(vect_address_analysis, vect_object_analysis): Likewise.
(vect_analyze_data_refs): Call compute_data_dependences_for_loop to find
and analyze data-refs in the loop.
* tree-vect-transform.c (vect_create_addr_base_for_vector_ref): Get the
fields of data-ref instead of stmt. Add init to the offset from the base.
(vect_create_data_ref_ptr): Get the fields of data-ref instead of stmt.
(vect_update_init_of_dr): Likewise.
(vect_update_inits_of_drs): Go through loads and stores in one loop.
* tree-vectorizer.c (new_stmt_vec_info): Remove initialization of removed
fields.
(new_loop_vec_info): Initialize new fields.
(destroy_loop_vec_info): Free new fields.
(vect_strip_conversion): Remove.
* tree-vectorizer.h (enum verbosity_levels): Add new verbosity level.
(struct _loop_vec_info): Unify data_ref_writes and data_ref_reads into
datarefs. Add new field ddrs.
Add macros for the new fields access.
(struct _stmt_vec_info): Remove: base_address, initial_offset, step,
base_aligned_p, misalignment, memtag, ptr_info and subvars.
Remove their macros.
* tree.h (highest_pow2_factor): Declare.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@102356 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-vect-analyze.c')
-rw-r--r-- | gcc/tree-vect-analyze.c | 1259 |
1 files changed, 192 insertions, 1067 deletions
diff --git a/gcc/tree-vect-analyze.c b/gcc/tree-vect-analyze.c index 267a6ffdde5..45deb5c0952 100644 --- a/gcc/tree-vect-analyze.c +++ b/gcc/tree-vect-analyze.c @@ -57,234 +57,10 @@ static void vect_mark_relevant (VEC(tree,heap) **, tree, bool, bool); static bool vect_stmt_relevant_p (tree, loop_vec_info, bool *, bool *); static tree vect_get_loop_niters (struct loop *, tree *); static bool vect_analyze_data_ref_dependence - (struct data_reference *, struct data_reference *, loop_vec_info); -static bool vect_compute_data_ref_alignment (struct data_reference *); + (struct data_dependence_relation *, loop_vec_info); +static bool vect_compute_data_ref_alignment (struct data_reference *); static bool vect_analyze_data_ref_access (struct data_reference *); -static struct data_reference * vect_analyze_pointer_ref_access - (tree, tree, bool, tree, tree *, tree *); static bool vect_can_advance_ivs_p (loop_vec_info); -static tree vect_get_ptr_offset (tree, tree, tree *); -static bool vect_analyze_offset_expr (tree, struct loop *, tree, tree *, - tree *, tree *); -static bool vect_base_addr_differ_p (struct data_reference *, - struct data_reference *drb, bool *); -static tree vect_object_analysis (tree, tree, bool, tree, - struct data_reference **, tree *, 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_get_ptr_offset - - Compute the OFFSET modulo vector-type alignment of pointer REF in bits. */ - -static tree -vect_get_ptr_offset (tree ref ATTRIBUTE_UNUSED, - tree vectype ATTRIBUTE_UNUSED, - tree *offset ATTRIBUTE_UNUSED) -{ - /* TODO: Use alignment information. */ - return NULL_TREE; -} - - -/* Function vect_analyze_offset_expr - - Given an offset expression EXPR received from get_inner_reference, analyze - it and create an expression for INITIAL_OFFSET by substituting the variables - of EXPR with initial_condition of the corresponding access_fn in the loop. - E.g., - for i - for (j = 3; j < N; j++) - a[j].b[i][j] = 0; - - For a[j].b[i][j], EXPR will be 'i * C_i + j * C_j + C'. 'i' cannot be - substituted, since its access_fn in the inner loop is i. 'j' will be - substituted with 3. An INITIAL_OFFSET will be 'i * C_i + C`', where - C` = 3 * C_j + C. - - Compute MISALIGN (the misalignment of the data reference initial access from - its base) if possible. Misalignment can be calculated only if all the - variables can be substituted with constants, or if a variable is multiplied - by a multiple of VECTYPE_ALIGNMENT. In the above example, since 'i' cannot - be substituted, MISALIGN will be NULL_TREE in case that C_i is not a multiple - of VECTYPE_ALIGNMENT, and C` otherwise. (We perform MISALIGN modulo - VECTYPE_ALIGNMENT computation in the caller of this function). - - STEP is an evolution of the data reference in this loop in bytes. - In the above example, STEP is C_j. - - Return FALSE, if the analysis fails, e.g., there is no access_fn for a - variable. In this case, all the outputs (INITIAL_OFFSET, MISALIGN and STEP) - are NULL_TREEs. Otherwise, return TRUE. - -*/ - -static bool -vect_analyze_offset_expr (tree expr, - struct loop *loop, - tree vectype_alignment, - tree *initial_offset, - tree *misalign, - tree *step) -{ - tree oprnd0; - tree oprnd1; - tree left_offset = ssize_int (0); - tree right_offset = ssize_int (0); - tree left_misalign = ssize_int (0); - tree right_misalign = ssize_int (0); - tree left_step = ssize_int (0); - tree right_step = ssize_int (0); - enum tree_code code; - tree init, evolution; - - *step = NULL_TREE; - *misalign = NULL_TREE; - *initial_offset = NULL_TREE; - - /* Strip conversions that don't narrow the mode. */ - expr = vect_strip_conversion (expr); - if (!expr) - return false; - - /* Stop conditions: - 1. Constant. */ - if (TREE_CODE (expr) == INTEGER_CST) - { - *initial_offset = fold_convert (ssizetype, expr); - *misalign = fold_convert (ssizetype, expr); - *step = ssize_int (0); - return true; - } - - /* 2. Variable. Try to substitute with initial_condition of the corresponding - access_fn in the current loop. */ - if (SSA_VAR_P (expr)) - { - tree access_fn = analyze_scalar_evolution (loop, expr); - - if (access_fn == chrec_dont_know) - /* No access_fn. */ - return false; - - init = initial_condition_in_loop_num (access_fn, loop->num); - if (init == expr && !expr_invariant_in_loop_p (loop, init)) - /* Not enough information: may be not loop invariant. - E.g., for a[b[i]], we get a[D], where D=b[i]. EXPR is D, its - initial_condition is D, but it depends on i - loop's induction - variable. */ - return false; - - evolution = evolution_part_in_loop_num (access_fn, loop->num); - if (evolution && TREE_CODE (evolution) != INTEGER_CST) - /* Evolution is not constant. */ - return false; - - if (TREE_CODE (init) == INTEGER_CST) - *misalign = fold_convert (ssizetype, init); - else - /* Not constant, misalignment cannot be calculated. */ - *misalign = NULL_TREE; - - *initial_offset = fold_convert (ssizetype, init); - - *step = evolution ? fold_convert (ssizetype, evolution) : ssize_int (0); - return true; - } - - /* Recursive computation. */ - if (!BINARY_CLASS_P (expr)) - { - /* We expect to get binary expressions (PLUS/MINUS and MULT). */ - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "Not binary expression "); - print_generic_expr (vect_dump, expr, TDF_SLIM); - } - return false; - } - oprnd0 = TREE_OPERAND (expr, 0); - oprnd1 = TREE_OPERAND (expr, 1); - - if (!vect_analyze_offset_expr (oprnd0, loop, vectype_alignment, &left_offset, - &left_misalign, &left_step) - || !vect_analyze_offset_expr (oprnd1, loop, vectype_alignment, - &right_offset, &right_misalign, &right_step)) - return false; - - /* The type of the operation: plus, minus or mult. */ - code = TREE_CODE (expr); - switch (code) - { - case MULT_EXPR: - if (TREE_CODE (right_offset) != INTEGER_CST) - /* RIGHT_OFFSET can be not constant. For example, for arrays of variable - sized types. - FORNOW: We don't support such cases. */ - return false; - - /* Strip conversions that don't narrow the mode. */ - left_offset = vect_strip_conversion (left_offset); - if (!left_offset) - return false; - /* Misalignment computation. */ - if (SSA_VAR_P (left_offset)) - { - /* If the left side contains variables that can't be substituted with - constants, we check if the right side is a multiple of ALIGNMENT. - */ - if (integer_zerop (size_binop (TRUNC_MOD_EXPR, right_offset, - fold_convert (ssizetype, vectype_alignment)))) - *misalign = ssize_int (0); - else - /* If the remainder is not zero or the right side isn't constant, - we can't compute misalignment. */ - *misalign = NULL_TREE; - } - else - { - /* The left operand was successfully substituted with constant. */ - if (left_misalign) - /* In case of EXPR '(i * C1 + j) * C2', LEFT_MISALIGN is - NULL_TREE. */ - *misalign = size_binop (code, left_misalign, right_misalign); - else - *misalign = NULL_TREE; - } - - /* Step calculation. */ - /* Multiply the step by the right operand. */ - *step = size_binop (MULT_EXPR, left_step, right_offset); - break; - - case PLUS_EXPR: - case MINUS_EXPR: - /* Combine the recursive calculations for step and misalignment. */ - *step = size_binop (code, left_step, right_step); - - if (left_misalign && right_misalign) - *misalign = size_binop (code, left_misalign, right_misalign); - else - *misalign = NULL_TREE; - - break; - - default: - gcc_unreachable (); - } - - /* Compute offset. */ - *initial_offset = fold_convert (ssizetype, - fold_build2 (code, TREE_TYPE (left_offset), - left_offset, - right_offset)); - return true; -} - /* Function vect_determine_vectorization_factor @@ -780,86 +556,34 @@ vect_analyze_scalar_cycles (loop_vec_info loop_vinfo) } -/* Function vect_base_addr_differ_p. - - This is the simplest data dependence test: determines whether the - data references A and B access the same array/region. Returns - false when the property is not computable at compile time. - Otherwise return true, and DIFFER_P will record the result. This - utility will not be necessary when alias_sets_conflict_p will be - less conservative. */ - -static bool -vect_base_addr_differ_p (struct data_reference *dra, - struct data_reference *drb, - bool *differ_p) -{ - tree stmt_a = DR_STMT (dra); - stmt_vec_info stmt_info_a = vinfo_for_stmt (stmt_a); - tree stmt_b = DR_STMT (drb); - stmt_vec_info stmt_info_b = vinfo_for_stmt (stmt_b); - tree addr_a = STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info_a); - tree addr_b = STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info_b); - tree type_a = TREE_TYPE (addr_a); - tree type_b = TREE_TYPE (addr_b); - HOST_WIDE_INT alias_set_a, alias_set_b; - - gcc_assert (POINTER_TYPE_P (type_a) && POINTER_TYPE_P (type_b)); - - /* Both references are ADDR_EXPR, i.e., we have the objects. */ - if (TREE_CODE (addr_a) == ADDR_EXPR && TREE_CODE (addr_b) == ADDR_EXPR) - return array_base_name_differ_p (dra, drb, differ_p); - - alias_set_a = (TREE_CODE (addr_a) == ADDR_EXPR) ? - get_alias_set (TREE_OPERAND (addr_a, 0)) : get_alias_set (addr_a); - alias_set_b = (TREE_CODE (addr_b) == ADDR_EXPR) ? - get_alias_set (TREE_OPERAND (addr_b, 0)) : get_alias_set (addr_b); - - if (!alias_sets_conflict_p (alias_set_a, alias_set_b)) - { - *differ_p = true; - return true; - } - - /* An instruction writing through a restricted pointer is "independent" of any - instruction reading or writing through a different pointer, in the same - block/scope. */ - else if ((TYPE_RESTRICT (type_a) && !DR_IS_READ (dra)) - || (TYPE_RESTRICT (type_b) && !DR_IS_READ (drb))) - { - *differ_p = true; - return true; - } - return false; -} - - /* Function vect_analyze_data_ref_dependence. Return TRUE if there (might) exist a dependence between a memory-reference DRA and a memory-reference DRB. */ - + static bool -vect_analyze_data_ref_dependence (struct data_reference *dra, - struct data_reference *drb, - loop_vec_info loop_vinfo) +vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, + loop_vec_info loop_vinfo) { - bool differ_p; - struct data_dependence_relation *ddr; struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo); int dist = 0; unsigned int loop_depth = 0; - struct loop *loop_nest = loop; - stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra)); + struct loop *loop_nest = loop; + 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)); stmt_vec_info stmtinfo_b = vinfo_for_stmt (DR_STMT (drb)); + + if (DDR_ARE_DEPENDENT (ddr) == chrec_known) + return false; - if (!vect_base_addr_differ_p (dra, drb, &differ_p)) + if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) { if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) { fprintf (vect_dump, - "not vectorized: can't determine dependence between: "); + "not vectorized: can't determine dependence between "); print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM); fprintf (vect_dump, " and "); print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM); @@ -867,57 +591,28 @@ vect_analyze_data_ref_dependence (struct data_reference *dra, return true; } - if (differ_p) - return false; - - ddr = initialize_data_dependence_relation (dra, drb); - compute_affine_dependence (ddr); - - if (DDR_ARE_DEPENDENT (ddr) == chrec_known) - return false; - - if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) + if (!DDR_DIST_VECT (ddr)) { if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) { - fprintf (vect_dump, - "not vectorized: can't determine dependence between "); + fprintf (vect_dump, "not vectorized: bad dist vector for "); print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM); fprintf (vect_dump, " and "); print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM); } return true; - } + } /* Find loop depth. */ - while (loop_nest) + while (loop_nest && loop_nest->outer && loop_nest->outer->outer) { - if (loop_nest->outer && loop_nest->outer->outer) - { - loop_nest = loop_nest->outer; - loop_depth++; - } - else - break; - } - - /* Compute distance vector. */ - compute_subscript_distance (ddr); - build_classic_dist_vector (ddr, vect_loops_num, loop_nest->depth); - - if (!DDR_DIST_VECT (ddr)) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - { - fprintf (vect_dump, "not vectorized: bad dist vector for "); - print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM); - fprintf (vect_dump, " and "); - print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM); - } - return true; + loop_nest = loop_nest->outer; + loop_depth++; } - + dist = DDR_DIST_VECT (ddr)[loop_depth]; + if (vect_print_dump_info (REPORT_DR_DETAILS)) + fprintf (vect_dump, "dependence distance = %d.",dist); /* Same loop iteration. */ if (dist % vectorization_factor == 0) @@ -926,76 +621,59 @@ vect_analyze_data_ref_dependence (struct data_reference *dra, VEC_safe_push (dr_p, heap, STMT_VINFO_SAME_ALIGN_REFS (stmtinfo_a), drb); VEC_safe_push (dr_p, heap, STMT_VINFO_SAME_ALIGN_REFS (stmtinfo_b), dra); if (vect_print_dump_info (REPORT_ALIGNMENT)) - fprintf (vect_dump, "accesses have the same alignment."); + fprintf (vect_dump, "accesses have the same alignment."); + if (vect_print_dump_info (REPORT_DR_DETAILS)) + { + fprintf (vect_dump, "dependence distance modulo vf == 0 between "); + print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM); + fprintf (vect_dump, " and "); + print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM); + } return false; - } + } - if (dist >= vectorization_factor) - /* Dependence distance does not create dependence, as far as vectorization - is concerned, in this case. */ - return false; - + if (abs (dist) >= vectorization_factor) + { + /* Dependence distance does not create dependence, as far as vectorization + is concerned, in this case. */ + if (vect_print_dump_info (REPORT_DR_DETAILS)) + fprintf (vect_dump, "dependence distance >= VF."); + return false; + } + if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) { fprintf (vect_dump, - "not vectorized: possible dependence between data-refs "); + "not vectorized: possible dependence between data-refs "); print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM); fprintf (vect_dump, " and "); print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM); } - + return true; } /* Function vect_analyze_data_ref_dependences. - + Examine all the data references in the loop, and make sure there do not exist any data dependences between them. */ - + static bool vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo) { - unsigned int i, j; - varray_type loop_write_refs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo); - varray_type loop_read_refs = LOOP_VINFO_DATAREF_READS (loop_vinfo); - - /* Examine store-store (output) dependences. */ + unsigned int i; + varray_type ddrs = LOOP_VINFO_DDRS (loop_vinfo); - if (vect_print_dump_info (REPORT_DETAILS)) + if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "=== vect_analyze_dependences ==="); - - if (vect_print_dump_info (REPORT_DETAILS)) - fprintf (vect_dump, "compare all store-store pairs."); - - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_refs); i++) - { - for (j = i + 1; j < VARRAY_ACTIVE_SIZE (loop_write_refs); j++) - { - struct data_reference *dra = - VARRAY_GENERIC_PTR (loop_write_refs, i); - struct data_reference *drb = - VARRAY_GENERIC_PTR (loop_write_refs, j); - if (vect_analyze_data_ref_dependence (dra, drb, loop_vinfo)) - return false; - } - } - - /* Examine load-store (true/anti) dependences. */ - - if (vect_print_dump_info (REPORT_DETAILS)) - fprintf (vect_dump, "compare all load-store pairs."); - - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_refs); i++) + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ddrs); i++) { - for (j = 0; j < VARRAY_ACTIVE_SIZE (loop_write_refs); j++) - { - struct data_reference *dra = VARRAY_GENERIC_PTR (loop_read_refs, i); - struct data_reference *drb = - VARRAY_GENERIC_PTR (loop_write_refs, j); - if (vect_analyze_data_ref_dependence (dra, drb, loop_vinfo)) - return false; - } + struct data_dependence_relation *ddr = VARRAY_GENERIC_PTR (ddrs, i); + + if (vect_analyze_data_ref_dependence (ddr, loop_vinfo)) + return false; } return true; @@ -1021,9 +699,10 @@ vect_compute_data_ref_alignment (struct data_reference *dr) stmt_vec_info stmt_info = vinfo_for_stmt (stmt); tree ref = DR_REF (dr); tree vectype; - tree base, alignment; - bool base_aligned_p; + tree base, base_addr; + bool base_aligned; tree misalign; + tree aligned_to, alignment; if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "vect_compute_data_ref_alignment:"); @@ -1031,12 +710,15 @@ vect_compute_data_ref_alignment (struct data_reference *dr) /* Initialize misalignment to unknown. */ DR_MISALIGNMENT (dr) = -1; - misalign = STMT_VINFO_VECT_MISALIGNMENT (stmt_info); - base_aligned_p = STMT_VINFO_VECT_BASE_ALIGNED_P (stmt_info); - base = build_fold_indirect_ref (STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info)); + misalign = DR_OFFSET_MISALIGNMENT (dr); + aligned_to = DR_ALIGNED_TO (dr); + base_addr = DR_BASE_ADDRESS (dr); + base = build_fold_indirect_ref (base_addr); vectype = STMT_VINFO_VECTYPE (stmt_info); + alignment = ssize_int (TYPE_ALIGN (vectype)/BITS_PER_UNIT); - if (!misalign) + if ((aligned_to && tree_int_cst_compare (aligned_to, alignment) < 0) + || !misalign) { if (vect_print_dump_info (REPORT_DETAILS)) { @@ -1046,7 +728,18 @@ vect_compute_data_ref_alignment (struct data_reference *dr) return true; } - if (!base_aligned_p) + if ((DECL_P (base) + && tree_int_cst_compare (ssize_int (DECL_ALIGN_UNIT (base)), + alignment) >= 0) + || (TREE_CODE (base_addr) == SSA_NAME + && tree_int_cst_compare (ssize_int (TYPE_ALIGN_UNIT (TREE_TYPE ( + TREE_TYPE (base_addr)))), + alignment) >= 0)) + base_aligned = true; + else + base_aligned = false; + + if (!base_aligned) { if (!vect_can_force_dr_alignment_p (base, TYPE_ALIGN (vectype))) { @@ -1068,15 +761,13 @@ vect_compute_data_ref_alignment (struct data_reference *dr) } /* At this point we assume that the base is aligned. */ - gcc_assert (base_aligned_p + gcc_assert (base_aligned || (TREE_CODE (base) == VAR_DECL && DECL_ALIGN (base) >= TYPE_ALIGN (vectype))); - /* Alignment required, in bytes: */ - alignment = ssize_int (TYPE_ALIGN (vectype)/BITS_PER_UNIT); - /* Modulo alignment. */ misalign = size_binop (TRUNC_MOD_EXPR, misalign, alignment); + if (tree_int_cst_sgn (misalign) < 0) { /* Negative misalignment value. */ @@ -1088,7 +779,10 @@ vect_compute_data_ref_alignment (struct data_reference *dr) DR_MISALIGNMENT (dr) = tree_low_cst (misalign, 1); if (vect_print_dump_info (REPORT_DETAILS)) - fprintf (vect_dump, "misalign = %d bytes", DR_MISALIGNMENT (dr)); + { + fprintf (vect_dump, "misalign = %d bytes of ref ", DR_MISALIGNMENT (dr)); + print_generic_expr (vect_dump, ref, TDF_SLIM); + } return true; } @@ -1106,20 +800,12 @@ vect_compute_data_ref_alignment (struct data_reference *dr) static bool vect_compute_data_refs_alignment (loop_vec_info loop_vinfo) { - varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo); - varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo); + varray_type datarefs = LOOP_VINFO_DATAREFS (loop_vinfo); unsigned int i; - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++) - { - struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i); - if (!vect_compute_data_ref_alignment (dr)) - return false; - } - - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++) + for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++) { - struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i); + struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i); if (!vect_compute_data_ref_alignment (dr)) return false; } @@ -1141,13 +827,13 @@ vect_compute_data_refs_alignment (loop_vec_info loop_vinfo) static void vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) { - varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo); - varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo); + varray_type loop_datarefs = LOOP_VINFO_DATAREFS (loop_vinfo); varray_type datarefs; VEC(dr_p,heap) *same_align_drs; struct data_reference *dr0 = NULL; struct data_reference *dr; unsigned int i, j; + bool check_loads; /* This pass will require a cost model to guide it whether to apply peeling @@ -1248,10 +934,10 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) TODO: Use a better cost model. */ - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++) + for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_datarefs); i++) { - dr0 = VARRAY_GENERIC_PTR (loop_write_datarefs, i); - if (!aligned_access_p (dr0)) + dr0 = VARRAY_GENERIC_PTR (loop_datarefs, i); + if (!DR_IS_READ (dr0) && !aligned_access_p (dr0)) { LOOP_VINFO_UNALIGNED_DR (loop_vinfo) = dr0; LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo) = DR_MISALIGNMENT (dr0); @@ -1285,14 +971,15 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) npeel = LOOP_VINFO_VECT_FACTOR (loop_vinfo) - mis; } - datarefs = loop_write_datarefs; + datarefs = loop_datarefs; + check_loads = false; for (j = 0; j < 2; j++) { for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++) { struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i); - if (dr == dr0) + if (dr == dr0 || (!check_loads && DR_IS_READ (dr))) continue; if (known_alignment_for_access_p (dr) && DR_MISALIGNMENT (dr) == DR_MISALIGNMENT (dr0)) @@ -1309,7 +996,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) else DR_MISALIGNMENT (dr) = -1; } - datarefs = loop_read_datarefs; + check_loads = true; } same_align_drs = @@ -1334,8 +1021,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) static bool vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo) { - varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo); - varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo); + varray_type datarefs = LOOP_VINFO_DATAREFS (loop_vinfo); enum dr_alignment_support supportable_dr_alignment; unsigned int i; @@ -1364,29 +1050,19 @@ vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo) /* Finally, check that all the data references in the loop can be handled with respect to their alignment. */ - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++) - { - struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i); - supportable_dr_alignment = vect_supportable_dr_alignment (dr); - if (!supportable_dr_alignment) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: unsupported unaligned load."); - return false; - } - if (supportable_dr_alignment != dr_aligned - && (vect_print_dump_info (REPORT_ALIGNMENT))) - fprintf (vect_dump, "Vectorizing an unaligned access."); - } - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++) + for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++) { - struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i); + struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i); supportable_dr_alignment = vect_supportable_dr_alignment (dr); if (!supportable_dr_alignment) { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: unsupported unaligned store."); - return false; + if (DR_IS_READ (dr)) + fprintf (vect_dump, + "not vectorized: unsupported unaligned load."); + else + fprintf (vect_dump, + "not vectorized: unsupported unaligned store."); + return false; } if (supportable_dr_alignment != dr_aligned && (vect_print_dump_info (REPORT_ALIGNMENT))) @@ -1395,7 +1071,6 @@ vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo) if (LOOP_VINFO_UNALIGNED_DR (loop_vinfo) && vect_print_dump_info (REPORT_ALIGNMENT)) fprintf (vect_dump, "Alignment of access forced using peeling."); - return true; } @@ -1408,9 +1083,7 @@ vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo) static bool vect_analyze_data_ref_access (struct data_reference *dr) { - tree stmt = DR_STMT (dr); - stmt_vec_info stmt_info = vinfo_for_stmt (stmt); - tree step = STMT_VINFO_VECT_STEP (stmt_info); + tree step = DR_STEP (dr); tree scalar_type = TREE_TYPE (DR_REF (dr)); if (!step || tree_int_cst_compare (step, TYPE_SIZE_UNIT (scalar_type))) @@ -1436,29 +1109,15 @@ static bool vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo) { unsigned int i; - varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo); - varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo); + varray_type datarefs = LOOP_VINFO_DATAREFS (loop_vinfo); if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "=== vect_analyze_data_ref_accesses ==="); - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++) + for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++) { - struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i); - bool ok = vect_analyze_data_ref_access (dr); - if (!ok) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: complicated access pattern."); - return false; - } - } - - for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++) - { - struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i); - bool ok = vect_analyze_data_ref_access (dr); - if (!ok) + struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i); + if (!vect_analyze_data_ref_access (dr)) { if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) fprintf (vect_dump, "not vectorized: complicated access pattern."); @@ -1470,640 +1129,106 @@ vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo) } -/* Function vect_analyze_pointer_ref_access. - - Input: - STMT - a stmt that contains a data-ref. - MEMREF - a data-ref in STMT, which is an INDIRECT_REF. - ACCESS_FN - the access function of MEMREF. - - Output: - If the data-ref access is vectorizable, return a data_reference structure - that represents it (DR). Otherwise - return NULL. - STEP - the stride of MEMREF in the loop. - INIT - the initial condition of MEMREF in the loop. -*/ - -static struct data_reference * -vect_analyze_pointer_ref_access (tree memref, tree stmt, bool is_read, - tree access_fn, tree *ptr_init, tree *ptr_step) -{ - stmt_vec_info stmt_info = vinfo_for_stmt (stmt); - loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); - struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); - tree step, init; - tree reftype, innertype; - tree indx_access_fn; - int loopnum = loop->num; - struct data_reference *dr; - - if (!vect_is_simple_iv_evolution (loopnum, access_fn, &init, &step)) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: pointer access is not simple."); - return NULL; - } - - STRIP_NOPS (init); - - if (!expr_invariant_in_loop_p (loop, init)) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, - "not vectorized: initial condition is not loop invariant."); - return NULL; - } - - if (TREE_CODE (step) != INTEGER_CST) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, - "not vectorized: non constant step for pointer access."); - return NULL; - } - - reftype = TREE_TYPE (TREE_OPERAND (memref, 0)); - if (!POINTER_TYPE_P (reftype)) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: unexpected pointer access form."); - return NULL; - } - - if (!POINTER_TYPE_P (TREE_TYPE (init))) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: unexpected pointer access form."); - return NULL; - } - - *ptr_step = fold_convert (ssizetype, step); - innertype = TREE_TYPE (reftype); - if (!COMPLETE_TYPE_P (innertype)) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - 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))))) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: non consecutive access."); - return NULL; - } - - indx_access_fn = - build_polynomial_chrec (loopnum, integer_zero_node, integer_one_node); - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "Access function of ptr indx: "); - print_generic_expr (vect_dump, indx_access_fn, TDF_SLIM); - } - dr = init_data_ref (stmt, memref, NULL_TREE, indx_access_fn, is_read); - *ptr_init = init; - return dr; -} - - -/* Function vect_address_analysis - - Return the BASE of the address expression EXPR. - Also compute the INITIAL_OFFSET from BASE, MISALIGN and STEP. - - Input: - EXPR - the address expression that is being analyzed - STMT - the statement that contains EXPR or its original memory reference - IS_READ - TRUE if STMT reads from EXPR, FALSE if writes to EXPR - VECTYPE - the type that defines the alignment (i.e, we compute - alignment relative to TYPE_ALIGN(VECTYPE)) - DR - data_reference struct for the original memory reference - - Output: - BASE (returned value) - the base of the data reference EXPR. - INITIAL_OFFSET - initial offset of EXPR from BASE (an expression) - MISALIGN - offset of EXPR from BASE in bytes (a constant) or NULL_TREE if the - computation is impossible - STEP - evolution of EXPR in the loop - BASE_ALIGNED - indicates if BASE is aligned - - If something unexpected is encountered (an unsupported form of data-ref), - then NULL_TREE is returned. - */ - -static tree -vect_address_analysis (tree expr, tree stmt, bool is_read, tree vectype, - struct data_reference *dr, tree *offset, tree *misalign, - tree *step, bool *base_aligned) -{ - 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)) - { - case PLUS_EXPR: - case MINUS_EXPR: - /* EXPR is of form {base +/- offset} (or {offset +/- base}). */ - oprnd0 = TREE_OPERAND (expr, 0); - oprnd1 = TREE_OPERAND (expr, 1); - - STRIP_NOPS (oprnd0); - STRIP_NOPS (oprnd1); - - /* Recursively try to find the base of the address contained in EXPR. - For offset, the returned base will be NULL. */ - base_addr0 = vect_address_analysis (oprnd0, stmt, is_read, vectype, dr, - &address_offset, &address_misalign, step, - base_aligned); - - base_addr1 = vect_address_analysis (oprnd1, stmt, is_read, vectype, dr, - &address_offset, &address_misalign, step, - base_aligned); - - /* We support cases where only one of the operands contains an - address. */ - if ((base_addr0 && base_addr1) || (!base_addr0 && !base_addr1)) - return NULL_TREE; - - /* To revert STRIP_NOPS. */ - oprnd0 = TREE_OPERAND (expr, 0); - oprnd1 = TREE_OPERAND (expr, 1); - - offset_expr = base_addr0 ? - fold_convert (ssizetype, oprnd1) : fold_convert (ssizetype, oprnd0); - - /* EXPR is of form {base +/- offset} (or {offset +/- base}). If offset is - a number, we can add it to the misalignment value calculated for base, - otherwise, misalignment is NULL. */ - if (TREE_CODE (offset_expr) == INTEGER_CST && address_misalign) - *misalign = size_binop (TREE_CODE (expr), address_misalign, - offset_expr); - else - *misalign = NULL_TREE; - - /* Combine offset (from EXPR {base + offset}) with the offset calculated - for base. */ - *offset = size_binop (TREE_CODE (expr), address_offset, offset_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, &dummy1, &dummy2); - return base_address; - - case SSA_NAME: - if (!POINTER_TYPE_P (TREE_TYPE (expr))) - return NULL_TREE; - - if (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (expr))) < TYPE_ALIGN (vectype)) - { - if (vect_get_ptr_offset (expr, vectype, misalign)) - *base_aligned = true; - else - *base_aligned = false; - } - else - { - *base_aligned = true; - *misalign = ssize_int (0); - } - *offset = ssize_int (0); - *step = ssize_int (0); - return expr; - - default: - return NULL_TREE; - } -} - - -/* Function vect_object_analysis - - Return the BASE of the data reference MEMREF. - Also compute the INITIAL_OFFSET from BASE, MISALIGN and STEP. - E.g., for EXPR a.b[i] + 4B, BASE is a, and OFFSET is the overall offset - 'a.b[i] + 4B' from a (can be an expression), MISALIGN is an OFFSET - instantiated with initial_conditions of access_functions of variables, - modulo alignment, and STEP is the evolution of the DR_REF in this loop. - - Function get_inner_reference is used for the above in case of ARRAY_REF and - COMPONENT_REF. - - The structure of the function is as follows: - Part 1: - Case 1. For handled_component_p refs - 1.1 call get_inner_reference - 1.1.1 analyze offset expr received from get_inner_reference - 1.2. build data-reference structure for MEMREF - (fall through with BASE) - Case 2. For declarations - 2.1 check alignment - 2.2 update DR_BASE_NAME if necessary for alias - Case 3. For INDIRECT_REFs - 3.1 get the access function - 3.2 analyze evolution of MEMREF - 3.3 set data-reference structure for MEMREF - 3.4 call vect_address_analysis to analyze INIT of the access function - - Part 2: - Combine the results of object and address analysis to calculate - INITIAL_OFFSET, STEP and misalignment info. - - Input: - MEMREF - the memory reference that is being analyzed - STMT - the statement that contains MEMREF - IS_READ - TRUE if STMT reads from MEMREF, FALSE if writes to MEMREF - VECTYPE - the type that defines the alignment (i.e, we compute - alignment relative to TYPE_ALIGN(VECTYPE)) - - Output: - BASE_ADDRESS (returned value) - the base address of the data reference MEMREF - E.g, if MEMREF is a.b[k].c[i][j] the returned - base is &a. - DR - data_reference struct for MEMREF - INITIAL_OFFSET - initial offset of MEMREF from BASE (an expression) - MISALIGN - offset of MEMREF from BASE in bytes (a constant) or NULL_TREE if - the computation is impossible - 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. */ - -static tree -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, - 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); - tree object_step = ssize_int (0), address_step = ssize_int (0); - bool object_base_aligned = true, address_base_aligned = true; - tree address_offset = ssize_int (0), address_misalign = ssize_int (0); - HOST_WIDE_INT pbitsize, pbitpos; - tree poffset, bit_pos_in_bytes; - enum machine_mode pmode; - int punsignedp, pvolatilep; - tree ptr_step = ssize_int (0), ptr_init = NULL_TREE; - stmt_vec_info stmt_info = vinfo_for_stmt (stmt); - loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); - 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. */ - if (handled_component_p (memref)) - { - /* 1.1 call get_inner_reference. */ - /* Find the base and the offset from it. */ - base = get_inner_reference (memref, &pbitsize, &pbitpos, &poffset, - &pmode, &punsignedp, &pvolatilep, false); - if (!base) - return NULL_TREE; - - /* 1.1.1 analyze offset expr received from get_inner_reference. */ - if (poffset - && !vect_analyze_offset_expr (poffset, loop, TYPE_SIZE_UNIT (vectype), - &object_offset, &object_misalign, &object_step)) - { - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "failed to compute offset or step for "); - print_generic_expr (vect_dump, memref, TDF_SLIM); - } - return NULL_TREE; - } - - /* Add bit position to OFFSET and MISALIGN. */ - - bit_pos_in_bytes = ssize_int (pbitpos/BITS_PER_UNIT); - /* Check that there is no remainder in bits. */ - if (pbitpos%BITS_PER_UNIT) - { - if (vect_print_dump_info (REPORT_DETAILS)) - fprintf (vect_dump, "bit offset alignment."); - return NULL_TREE; - } - object_offset = size_binop (PLUS_EXPR, bit_pos_in_bytes, object_offset); - if (object_misalign) - object_misalign = size_binop (PLUS_EXPR, object_misalign, - bit_pos_in_bytes); - - /* Create data-reference for MEMREF. TODO: handle COMPONENT_REFs. */ - if (!(*dr)) - { - if (TREE_CODE (memref) == ARRAY_REF) - *dr = analyze_array (stmt, memref, is_read); - else - /* FORNOW. */ - return NULL_TREE; - } - memref = base; /* To continue analysis of BASE. */ - /* fall through */ - } - - /* Part 1: Case 2. Declarations. */ - if (DECL_P (memref)) - { - /* We expect to get a decl only if we already have a DR. */ - if (!(*dr)) - { - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "unhandled decl "); - print_generic_expr (vect_dump, memref, TDF_SLIM); - } - return NULL_TREE; - } - - /* 2.1 check the alignment. */ - if (DECL_ALIGN (memref) >= TYPE_ALIGN (vectype)) - object_base_aligned = true; - else - object_base_aligned = false; - - /* 2.2 update DR_BASE_NAME if necessary. */ - if (!DR_BASE_NAME ((*dr))) - /* For alias analysis. In case the analysis of INDIRECT_REF brought - 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, ptr_ref); - if (!access_fn) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - fprintf (vect_dump, "not vectorized: complicated pointer access."); - return NULL_TREE; - } - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "Access function of ptr: "); - print_generic_expr (vect_dump, access_fn, TDF_SLIM); - } - - /* 3.2 analyze evolution of MEMREF. */ - evolution_part = evolution_part_in_loop_num (access_fn, loop->num); - if (evolution_part) - { - ptr_dr = vect_analyze_pointer_ref_access (memref, stmt, is_read, - access_fn, &ptr_init, &ptr_step); - if (!(ptr_dr)) - return NULL_TREE; - - object_step = size_binop (PLUS_EXPR, object_step, ptr_step); - address_to_analyze = ptr_init; - } - else - { - if (!(*dr)) - { - 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 init of - the access function, which not necessary has evolution in the - loop. */ - address_to_analyze = initial_condition_in_loop_num (access_fn, - loop->num); - } - - /* 3.3 set data-reference structure for MEMREF. */ - *dr = (*dr) ? *dr : ptr_dr; - - /* 3.4 call vect_address_analysis to analyze INIT of the access - function. */ - base_address = vect_address_analysis (address_to_analyze, stmt, is_read, - vectype, *dr, &address_offset, &address_misalign, - &address_step, &address_base_aligned); - if (!base_address) - return NULL_TREE; - - switch (TREE_CODE (base_address)) - { - case SSA_NAME: - *memtag = get_var_ann (SSA_NAME_VAR (base_address))->type_mem_tag; - if (!(*memtag) && TREE_CODE (TREE_OPERAND (memref, 0)) == SSA_NAME) - *memtag = get_var_ann ( - SSA_NAME_VAR (TREE_OPERAND (memref, 0)))->type_mem_tag; - break; - case ADDR_EXPR: - *memtag = TREE_OPERAND (base_address, 0); - break; - default: - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - { - fprintf (vect_dump, "not vectorized: no memtag ref: "); - print_generic_expr (vect_dump, memref, TDF_SLIM); - } - return NULL_TREE; - } - } - - if (!base_address) - /* 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. */ - *offset = size_binop (PLUS_EXPR, object_offset, address_offset); - if (object_misalign && address_misalign) - *misalign = size_binop (PLUS_EXPR, object_misalign, address_misalign); - else - *misalign = NULL_TREE; - *step = size_binop (PLUS_EXPR, object_step, address_step); - *base_aligned = object_base_aligned && address_base_aligned; - - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "Results of object analysis for: "); - print_generic_expr (vect_dump, memref, TDF_SLIM); - fprintf (vect_dump, "\n\tbase_address: "); - print_generic_expr (vect_dump, base_address, TDF_SLIM); - fprintf (vect_dump, "\n\toffset: "); - print_generic_expr (vect_dump, *offset, TDF_SLIM); - fprintf (vect_dump, "\n\tstep: "); - print_generic_expr (vect_dump, *step, TDF_SLIM); - fprintf (vect_dump, "\n\tbase aligned %d\n\tmisalign: ", *base_aligned); - print_generic_expr (vect_dump, *misalign, TDF_SLIM); - } - return base_address; -} - - /* Function vect_analyze_data_refs. - Find all the data references in the loop. + Find all the data references in the loop. - The general structure of the analysis of data refs in the vectorizer is as + The general structure of the analysis of data refs in the vectorizer is as follows: - 1- vect_analyze_data_refs(loop): - Find and analyze all data-refs in the loop: - foreach ref - base_address = vect_object_analysis(ref) - 1.1- vect_object_analysis(ref): - Analyze ref, and build a DR (data_reference struct) for it; - compute base, initial_offset, step and alignment. - 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, ref_stmt.ptr_info and ref_stmt.step accordingly. - 2- vect_analyze_dependences(): apply dependence testing using ref_stmt.DR + 1- vect_analyze_data_refs(loop): call compute_data_dependences_for_loop to + find and analyze all data-refs in the loop and their dependences. + 2- vect_analyze_dependences(): apply dependence testing using ddrs. 3- vect_analyze_drs_alignment(): check that ref_stmt.alignment is ok. 4- vect_analyze_drs_access(): check that ref_stmt.step is ok. - FORNOW: Handle aligned INDIRECT_REFs and ARRAY_REFs - which base is really an array (not a pointer) and which alignment - can be forced. This restriction will be relaxed. */ +*/ static bool -vect_analyze_data_refs (loop_vec_info loop_vinfo) +vect_analyze_data_refs (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; - int j; - struct data_reference *dr; + unsigned int i; + varray_type datarefs; + tree scalar_type; if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "=== vect_analyze_data_refs ==="); - for (j = 0; j < nbbs; j++) - { - basic_block bb = bbs[j]; - for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) - { - bool is_read = false; - tree stmt = bsi_stmt (si); - stmt_vec_info stmt_info = vinfo_for_stmt (stmt); - varray_type *datarefs = NULL; - 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; - bool no_vuse, no_vmaymust; - - /* Assumption: there exists a data-ref in stmt, if and only if - it has vuses/vdefs. */ - - no_vuse = ZERO_SSA_OPERANDS (stmt, SSA_OP_VUSE); - no_vmaymust = ZERO_SSA_OPERANDS (stmt, - SSA_OP_VMAYDEF | SSA_OP_VMUSTDEF); - if (no_vuse && no_vmaymust) - continue; + compute_data_dependences_for_loop (loop, false, + &(LOOP_VINFO_DATAREFS (loop_vinfo)), + &(LOOP_VINFO_DDRS (loop_vinfo))); - if (!no_vuse && !no_vmaymust) - { - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "unexpected vdefs and vuses in stmt: "); - print_generic_expr (vect_dump, stmt, TDF_SLIM); - } - return false; - } - - if (TREE_CODE (stmt) != MODIFY_EXPR) - { - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "unexpected vops in stmt: "); - print_generic_expr (vect_dump, stmt, TDF_SLIM); - } - return false; - } - - if (!no_vuse) - { - memref = TREE_OPERAND (stmt, 1); - datarefs = &(LOOP_VINFO_DATAREF_READS (loop_vinfo)); - is_read = true; - } - else /* vdefs */ - { - memref = TREE_OPERAND (stmt, 0); - datarefs = &(LOOP_VINFO_DATAREF_WRITES (loop_vinfo)); - is_read = false; - } - - scalar_type = TREE_TYPE (memref); - vectype = get_vectype_for_scalar_type (scalar_type); - if (!vectype) - { - if (vect_print_dump_info (REPORT_DETAILS)) - { - fprintf (vect_dump, "no vectype for stmt: "); - print_generic_expr (vect_dump, stmt, TDF_SLIM); - fprintf (vect_dump, " scalar_type: "); - print_generic_expr (vect_dump, scalar_type, TDF_DETAILS); - } - /* It is not possible to vectorize this data reference. */ - return false; - } - /* Analyze MEMREF. If it is of a supported form, build data_reference - struct for it (DR). */ - dr = NULL; - base = vect_object_analysis (memref, stmt, is_read, vectype, &dr, - &offset, &misalign, &step, - &base_aligned, &tag, &ptr_info, - &subvars); - if (!base) - { - if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) - { - fprintf (vect_dump, "not vectorized: unhandled data ref: "); - print_generic_expr (vect_dump, stmt, TDF_SLIM); - } - return false; - } - STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info) = base; - STMT_VINFO_VECT_INIT_OFFSET (stmt_info) = offset; - STMT_VINFO_VECT_STEP (stmt_info) = step; - 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; - } + /* Go through the data-refs, check that the analysis succeeded. Update pointer + from stmt_vec_info struct to DR and vectype. */ + datarefs = LOOP_VINFO_DATAREFS (loop_vinfo); + for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++) + { + struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i); + tree stmt; + stmt_vec_info stmt_info; + + if (!dr || !DR_REF (dr)) + { + if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) + fprintf (vect_dump, "not vectorized: unhandled data-ref "); + return false; + } + + /* Update DR field in stmt_vec_info struct. */ + stmt = DR_STMT (dr); + stmt_info = vinfo_for_stmt (stmt); + + if (STMT_VINFO_DATA_REF (stmt_info)) + { + if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) + { + fprintf (vect_dump, + "not vectorized: more than one data ref in stmt: "); + print_generic_expr (vect_dump, stmt, TDF_SLIM); + } + return false; + } + STMT_VINFO_DATA_REF (stmt_info) = dr; + + /* Check that analysis of the data-ref succeeded. */ + if (!DR_BASE_ADDRESS (dr) || !DR_OFFSET (dr) || !DR_INIT (dr) + || !DR_STEP (dr)) + { + if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) + { + fprintf (vect_dump, "not vectorized: data ref analysis failed "); + print_generic_expr (vect_dump, stmt, TDF_SLIM); + } + return false; + } + if (!DR_MEMTAG (dr)) + { + if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) + { + fprintf (vect_dump, "not vectorized: no memory tag for "); + print_generic_expr (vect_dump, DR_REF (dr), TDF_SLIM); + } + return false; + } + + /* Set vectype for STMT. */ + scalar_type = TREE_TYPE (DR_REF (dr)); + STMT_VINFO_VECTYPE (stmt_info) = + get_vectype_for_scalar_type (scalar_type); + if (!STMT_VINFO_VECTYPE (stmt_info)) + { + if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) + { + fprintf (vect_dump, + "not vectorized: no vectype for stmt: "); + print_generic_expr (vect_dump, stmt, TDF_SLIM); + fprintf (vect_dump, " scalar_type: "); + print_generic_expr (vect_dump, scalar_type, TDF_DETAILS); + } + return false; + } } - + return true; } |