diff options
author | Jakub Jelinek <jakub@redhat.com> | 2013-08-27 20:38:00 +0200 |
---|---|---|
committer | Aldy Hernandez <aldyh@gcc.gnu.org> | 2013-08-27 18:38:00 +0000 |
commit | 74bf76ed78a14069969e94233f05e7840806aed8 (patch) | |
tree | c96afad81f1d970413ba047262aa9f9765da99e4 /gcc/tree-vectorizer.c | |
parent | d0cf4e841d8ab907811943e04102d9765660c003 (diff) | |
download | gcc-74bf76ed78a14069969e94233f05e7840806aed8.zip gcc-74bf76ed78a14069969e94233f05e7840806aed8.tar.gz gcc-74bf76ed78a14069969e94233f05e7840806aed8.tar.bz2 |
Makefile.in (omp-low.o): Depend on $(TARGET_H).
* Makefile.in (omp-low.o): Depend on $(TARGET_H).
* cfgloop.h (struct loop): Add safelen, force_vect, simduid.
* function.h (struct function): Add has_force_vect_loops and
has_simduid_loops.
* gimple-pretty-print.c (dump_gimple_omp_for): Handle
GF_OMP_FOR_KIND*.
* gimple.c (gimple_build_omp_critical): Add KIND argument and
handle it.
* gimple.def: Update CLAUSES comments.
* gimple.h (enum gf_mask): Add GF_OMP_FOR_KIND_{FOR,SIMD}.
(gimple_build_omp_for): Add argument to prototype.
(gimple_omp_for_kind): New.
(gimple_omp_for_set_kind): New.
* gimplify.c (enum gimplify_omp_var_data): Add GOVD_LINEAR to
GOVD_DATA_SHARE_CLASS.
(enum omp_region_type): Add ORT_SIMD.
(gimple_add_tmp_var): Handle ORT_SIMD.
(gimplify_var_or_parm_decl): Same.
(is_gimple_stmt): Same.
(omp_firstprivatize_variable): Same.
(omp_add_variable): Only use splay_tree_insert if lookup failed.
(omp_notice_variable): Handle ORT_SIMD.
(omp_is_private): Add SIMD argument and handle it as well as
ORT_SIMD.
(omp_check_private): Handle ORT_SIMD.
(gimplify_scan_omp_clauses): Handle OMP_CLAUSE_LINEAR and
OMP_CLAUSE_SAFELEN.
(gimplify_adjust_omp_clauses_1): Handle GOVD_LINEAR.
Handle OMP_CLAUSE_LASTPRIVATE.
(gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_LINEAR and
OMP_CLAUSE_SAFELEN.
(gimplify_omp_for): Handle OMP_SIMD and OMP_CLAUSE_LINEAR.
(gimplify_expr): Handle OMP_SIMD.
* internal-fn.c (expand_GOMP_SIMD_LANE): New.
(expand_GOMP_SIMD_VF): New.
(expand_GOMP_SIMD_LAST_LANE): New.
* internal-fn.def (GOMP_SIMD_LANE): New.
(GOMP_SIMD_VF): New.
(GOMP_SIMD_LAST_LANE): New.
* omp-low.c: Include target.h.
(extract_omp_for_data): Handle OMP_SIMD, OMP_CLAUSE_LINEAR,
OMP_CLAUSE_SAFELEN.
(check_omp_nesting_restrictions): Same.
(omp_max_vf): New.
(lower_rec_simd_input_clauses): New.
(lower_rec_input_clauses): Handle OMP_SIMD, GF_OMP_FOR_KIND_SIMD,
OMP_CLAUSE_LINEAR.
(lower_lastprivate_clauses): Handle OMP_CLAUSE_LINEAR,
GF_OMP_FOR_KIND_SIMD, OMP_SIMD.
(expand_omp_build_assign): New.
(expand_omp_for_init_counts): New.
(expand_omp_for_init_vars): New.
(extract_omp_for_update_vars): New.
(expand_omp_for_generic): Use expand_omp_for_{init,update}_vars
and rewrite accordingly.
(expand_omp_simd): New.
(expand_omp_for): Use expand_omp_simd.
(lower_omp_for_lastprivate): Unshare vinit when appropriate.
(lower_omp_for): Do not lower the body.
* tree-data-ref (get_references_in_stmt): Allow IFN_GOMP_SIMD_LANE
in their own loops.
* tree-flow.h (find_omp_clause): Remove prototype.
* tree-if-conv.c (main_tree_if_conversion): Run if doing if
conversion, forcing vectorization of the loop, or if
flag_tree_vectorize.
(gate_tree_if_conversion): Similarly.
* tree-inline.c (remap_gimple_stmt): Pass for kind argument to
gimple_build_omp_for.
(copy_cfg_body): set has_force_vect_loops and has_simduid_loops.
* tree-parloops (create_parallel_loop): Pass kind argument to
gimple_build_omp_for.
* tree-pretty-print.c (dump_omp_clause): Add cases for
OMP_CLAUSE_UNIFORM, OMP_CLAUSE_LINEAR, OMP_CLAUSE_SAFELEN,
OMP_CLAUSE__SIMDUID_.
(dump_generic_node): Handle OMP_SIMD.
* tree-ssa-ccp.c (likely_value): Handle IFN_GOMP_SIMD*.
* tree-ssa-loop-ivcanon.c (tree_unroll_loops_completely_1): Do not
unroll OMP_SIMD loops here.
* tree-ssa-loop.c (gate_tree_vectorize): Run if
has_force_vect_loops.
* tree-vect-data-refs.c (vect_analyze_data_ref_dependence): Handle
loop->safelen
(vect_analyze_data_refs): Handle simd loops.
* tree-vect-loop.c (vectorizable_live_operation): Handle
IFN_GOMP_SIMD*.
* tree-vect-stmts.c (vectorizable_call): Handle
IFN_GOMP_SIMD_LANE.
(vectorizable_store): Handle STMT_VINFO_SIMD_LANE_ACCESS_P.
(vectorizable_load): Same.
* tree-vectorizer.c: Include hash-table.h and
tree-ssa-propagate.h.
(struct simduid_to_vf): New.
(simduid_to_vf::hash): New.
(simduid_to-vf::equal): New.
(struct simd_array_to_simduid): New.
(simd_array_to_simduid::hash): New.
(simd_array_to_simduid::equal): New.
(adjust_simduid_builtins): New.
(struct note_simd_array_uses_struct): New.
(note_simd_array_uses_cb): New.
(note_simd_array_uses): New.
(vectorize_loops): Handle simd hints and adjust simd builtins
accordingly.
* tree-vectorizer.h (struct _stmt_vec_info): Add
simd_lane_access_p field.
(STMT_VINFO_SIMD_LANE_ACCESS_P): New macro.
* tree.c (omp_clause_num_ops): Add entries for OMP_CLAUSE_LINEAR,
OMP_CLAUSE_SAFELEN, OMP_CLAUSE__SIMDUID_, OMP_CLAUSE_UNIFORM.
(omp_clause_code_name): Same.
(walk_tree_1): Handle OMP_CLAUSE_UNIFORM, OMP_CLAUSE_SAFELEN,
OMP_CLAUSE__SIMDUID_, OMP_CLAUSE_LINEAR.
* tree.def (OMP_SIMD): New entry.
* tree.h (enum omp_clause_code): Add entries for
OMP_CLAUSE_LINEAR, OMP_CLAUSE_UNIFORM, OMP_CLAUSE_SAFELEN,
OMP_CLAUSE__SIMDUID_.
(OMP_CLAUSE_DECL): Adjust range for new clauses.
(OMP_CLAUSE_LINEAR_NO_COPYIN): New.
(OMP_CLAUSE_LINEAR_NO_COPYOUT): New.
(OMP_CLAUSE_LINEAR_STEP): New.
(OMP_CLAUSE_SAFELEN_EXPR): New.
(OMP_CLAUSE__SIMDUID__DECL): New.
(find_omp_clause): New prototype.
cp/
* cp-tree.h (CP_OMP_CLAUSE_INFO): Adjust range for new clauses.
Co-Authored-By: Aldy Hernandez <aldyh@redhat.com>
From-SVN: r202029
Diffstat (limited to 'gcc/tree-vectorizer.c')
-rw-r--r-- | gcc/tree-vectorizer.c | 267 |
1 files changed, 265 insertions, 2 deletions
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index cfcc95d..5501479 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -66,13 +66,218 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "tree-vectorizer.h" #include "tree-pass.h" +#include "hash-table.h" +#include "tree-ssa-propagate.h" /* Loop or bb location. */ LOC vect_location; /* Vector mapping GIMPLE stmt to stmt_vec_info. */ vec<vec_void_p> stmt_vec_info_vec; + +/* For mapping simduid to vectorization factor. */ + +struct simduid_to_vf : typed_free_remove<simduid_to_vf> +{ + unsigned int simduid; + int vf; + + /* hash_table support. */ + typedef simduid_to_vf value_type; + typedef simduid_to_vf compare_type; + static inline hashval_t hash (const value_type *); + static inline int equal (const value_type *, const compare_type *); +}; + +inline hashval_t +simduid_to_vf::hash (const value_type *p) +{ + return p->simduid; +} + +inline int +simduid_to_vf::equal (const value_type *p1, const value_type *p2) +{ + return p1->simduid == p2->simduid; +} + +/* This hash maps the OMP simd array to the corresponding simduid used + to index into it. Like thus, + + _7 = GOMP_SIMD_LANE (simduid.0) + ... + ... + D.1737[_7] = stuff; + + + This hash maps from the simduid.0 to OMP simd array (D.1737[]). */ + +struct simd_array_to_simduid : typed_free_remove<simd_array_to_simduid> +{ + tree decl; + unsigned int simduid; + + /* hash_table support. */ + typedef simd_array_to_simduid value_type; + typedef simd_array_to_simduid compare_type; + static inline hashval_t hash (const value_type *); + static inline int equal (const value_type *, const compare_type *); +}; + +inline hashval_t +simd_array_to_simduid::hash (const value_type *p) +{ + return DECL_UID (p->decl); +} + +inline int +simd_array_to_simduid::equal (const value_type *p1, const value_type *p2) +{ + return p1->decl == p2->decl; +} + +/* Fold IFN_GOMP_SIMD_LANE, IFN_GOMP_SIMD_VF and IFN_GOMP_SIMD_LAST_LANE + into their corresponding constants. */ + +static void +adjust_simduid_builtins (hash_table <simduid_to_vf> &htab) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + gimple_stmt_iterator i; + + for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + { + unsigned int vf = 1; + enum internal_fn ifn; + gimple stmt = gsi_stmt (i); + tree t; + if (!is_gimple_call (stmt) + || !gimple_call_internal_p (stmt)) + continue; + ifn = gimple_call_internal_fn (stmt); + switch (ifn) + { + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + break; + default: + continue; + } + tree arg = gimple_call_arg (stmt, 0); + gcc_assert (arg != NULL_TREE); + gcc_assert (TREE_CODE (arg) == SSA_NAME); + simduid_to_vf *p = NULL, data; + data.simduid = DECL_UID (SSA_NAME_VAR (arg)); + if (htab.is_created ()) + p = htab.find (&data); + if (p) + vf = p->vf; + switch (ifn) + { + case IFN_GOMP_SIMD_VF: + t = build_int_cst (unsigned_type_node, vf); + break; + case IFN_GOMP_SIMD_LANE: + t = build_int_cst (unsigned_type_node, 0); + break; + case IFN_GOMP_SIMD_LAST_LANE: + t = gimple_call_arg (stmt, 1); + break; + default: + gcc_unreachable (); + } + update_call_from_tree (&i, t); + } + } +} + +/* Helper structure for note_simd_array_uses. */ + +struct note_simd_array_uses_struct +{ + hash_table <simd_array_to_simduid> *htab; + unsigned int simduid; +}; + +/* Callback for note_simd_array_uses, called through walk_gimple_op. */ + +static tree +note_simd_array_uses_cb (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = (struct walk_stmt_info *) data; + struct note_simd_array_uses_struct *ns + = (struct note_simd_array_uses_struct *) wi->info; + + if (TYPE_P (*tp)) + *walk_subtrees = 0; + else if (VAR_P (*tp) + && lookup_attribute ("omp simd array", DECL_ATTRIBUTES (*tp)) + && DECL_CONTEXT (*tp) == current_function_decl) + { + simd_array_to_simduid data; + if (!ns->htab->is_created ()) + ns->htab->create (15); + data.decl = *tp; + data.simduid = ns->simduid; + simd_array_to_simduid **slot = ns->htab->find_slot (&data, INSERT); + if (*slot == NULL) + { + simd_array_to_simduid *p = XNEW (simd_array_to_simduid); + *p = data; + *slot = p; + } + else if ((*slot)->simduid != ns->simduid) + (*slot)->simduid = -1U; + *walk_subtrees = 0; + } + return NULL_TREE; +} + +/* Find "omp simd array" temporaries and map them to corresponding + simduid. */ + +static void +note_simd_array_uses (hash_table <simd_array_to_simduid> *htab) +{ + basic_block bb; + gimple_stmt_iterator gsi; + struct walk_stmt_info wi; + struct note_simd_array_uses_struct ns; + + memset (&wi, 0, sizeof (wi)); + wi.info = &ns; + ns.htab = htab; + FOR_EACH_BB (bb) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) + continue; + switch (gimple_call_internal_fn (stmt)) + { + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + break; + default: + continue; + } + tree lhs = gimple_call_lhs (stmt); + if (lhs == NULL_TREE) + continue; + imm_use_iterator use_iter; + gimple use_stmt; + ns.simduid = DECL_UID (SSA_NAME_VAR (gimple_call_arg (stmt, 0))); + FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, lhs) + if (!is_gimple_debug (use_stmt)) + walk_gimple_op (use_stmt, note_simd_array_uses_cb, &wi); + } +} /* Function vectorize_loops. @@ -86,12 +291,21 @@ vectorize_loops (void) unsigned int vect_loops_num; loop_iterator li; struct loop *loop; + hash_table <simduid_to_vf> simduid_to_vf_htab; + hash_table <simd_array_to_simduid> simd_array_to_simduid_htab; vect_loops_num = number_of_loops (cfun); /* Bail out if there are no loops. */ if (vect_loops_num <= 1) - return 0; + { + if (cfun->has_simduid_loops) + adjust_simduid_builtins (simduid_to_vf_htab); + return 0; + } + + if (cfun->has_simduid_loops) + note_simd_array_uses (&simd_array_to_simduid_htab); init_stmt_vec_info_vec (); @@ -101,7 +315,8 @@ vectorize_loops (void) than all previously defined loops. This fact allows us to run only over initial loops skipping newly generated ones. */ FOR_EACH_LOOP (li, loop, 0) - if (optimize_loop_nest_for_speed_p (loop)) + if ((flag_tree_vectorize && optimize_loop_nest_for_speed_p (loop)) + || loop->force_vect) { loop_vec_info loop_vinfo; vect_location = find_loop_location (loop); @@ -122,6 +337,20 @@ vectorize_loops (void) "Vectorized loop\n"); vect_transform_loop (loop_vinfo); num_vectorized_loops++; + /* Now that the loop has been vectorized, allow it to be unrolled + etc. */ + loop->force_vect = false; + + if (loop->simduid) + { + simduid_to_vf *simduid_to_vf_data = XNEW (simduid_to_vf); + if (!simduid_to_vf_htab.is_created ()) + simduid_to_vf_htab.create (15); + simduid_to_vf_data->simduid = DECL_UID (loop->simduid); + simduid_to_vf_data->vf = loop_vinfo->vectorization_factor; + *simduid_to_vf_htab.find_slot (simduid_to_vf_data, INSERT) + = simduid_to_vf_data; + } } vect_location = UNKNOWN_LOC; @@ -149,6 +378,40 @@ vectorize_loops (void) free_stmt_vec_info_vec (); + /* Fold IFN_GOMP_SIMD_{VF,LANE,LAST_LANE} builtins. */ + if (cfun->has_simduid_loops) + adjust_simduid_builtins (simduid_to_vf_htab); + + /* Shrink any "omp array simd" temporary arrays to the + actual vectorization factors. */ + if (simd_array_to_simduid_htab.is_created ()) + { + for (hash_table <simd_array_to_simduid>::iterator iter + = simd_array_to_simduid_htab.begin (); + iter != simd_array_to_simduid_htab.end (); ++iter) + if ((*iter).simduid != -1U) + { + tree decl = (*iter).decl; + int vf = 1; + if (simduid_to_vf_htab.is_created ()) + { + simduid_to_vf *p = NULL, data; + data.simduid = (*iter).simduid; + p = simduid_to_vf_htab.find (&data); + if (p) + vf = p->vf; + } + tree atype + = build_array_type_nelts (TREE_TYPE (TREE_TYPE (decl)), vf); + TREE_TYPE (decl) = atype; + relayout_decl (decl); + } + + simd_array_to_simduid_htab.dispose (); + } + if (simduid_to_vf_htab.is_created ()) + simduid_to_vf_htab.dispose (); + if (num_vectorized_loops > 0) { /* If we vectorized any loop only virtual SSA form needs to be updated. |