aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-vectorizer.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2013-08-27 20:38:00 +0200
committerAldy Hernandez <aldyh@gcc.gnu.org>2013-08-27 18:38:00 +0000
commit74bf76ed78a14069969e94233f05e7840806aed8 (patch)
treec96afad81f1d970413ba047262aa9f9765da99e4 /gcc/tree-vectorizer.c
parentd0cf4e841d8ab907811943e04102d9765660c003 (diff)
downloadgcc-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.c267
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.