From aa098165777d11e3c8bb39936339e9a54d7d6f12 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 24 Nov 2014 09:24:50 +0000 Subject: [PATCH] re PR tree-optimization/55334 (mgrid regression (ipa-cp disables vectorization)) 2014-11-24 Richard Biener PR tree-optimization/55334 * function.h (struct function): Add last_clique member. * tree-inline.c (remap_dependence_clique): New function. (remap_gimple_op_r): Remap dependence cliques in MEM_REFs. (copy_tree_body_r): Likewise. (copy_cfg_body): Free dependence map. (copy_gimple_seq_and_replace_locals): Likewise. * tree-pretty-print.c (dump_generic_node): Dump dependence info. * tree-ssa-alias.c (refs_may_alias_p_1): Use dependence info to answer alias query. * tree-ssa-structalias.c: Include tree-phinodes.h, ssa-iterators.h, tree-pretty-print.h and gimple-walk.h. (struct variable_info): Add is_restrict_var flag and ruid member. (new_var_info): Initialize is_restrict_var. (make_constraint_from_restrict): Likewise. (create_variable_info_for): Exclude restricts from global vars from new handling. (intra_create_variable_infos): But not those from parameters. (visit_loadstore): New function. (maybe_set_dependence_info): Likewise. (compute_dependence_clique): Likewise. (compute_may_aliases): Call compute_dependence_clique. * tree-data-ref.c (dr_analyze_indices): Copy dependence info to fake MEM_REF. (dr_may_alias_p): Use recorded dependence info to answer alias query. * tree-core.h (struct tree_base): Add clique, base struct in union. * tree.h (MR_DEPENDENCE_CLIQUE): New macro. (MR_DEPENDENCE_BASE): Likewise. * tree-inline.h (dependence_hasher): New hash-map kind. (struct copy_body_data): Add dependence_map pointer. * gimple-fold.c (maybe_canonicalize_mem_ref_addr): Avoid throwing away dependence info. * tree-streamer-in.c (unpack_value_fields): Stream dependence info. * tree-streamer-out.c (streamer_pack_tree_bitfields): Likewise. * gcc.dg/tree-ssa/restrict-5.c: New testcase. From-SVN: r218005 --- gcc/tree-ssa-structalias.c | 203 ++++++++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index e065f1a1b4c..69cf60b0895 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -64,6 +64,10 @@ #include "splay-tree.h" #include "params.h" #include "alias.h" +#include "tree-phinodes.h" +#include "ssa-iterators.h" +#include "tree-pretty-print.h" +#include "gimple-walk.h" /* The idea behind this analyzer is to generate set constraints from the program, then solve the resulting constraints in order to generate the @@ -284,12 +288,19 @@ struct variable_info /* True if this field has only restrict qualified pointers. */ unsigned int only_restrict_pointers : 1; + /* True if this represents a heap var created for a restrict qualified + pointer. */ + unsigned int is_restrict_var : 1; + /* True if this represents a global variable. */ unsigned int is_global_var : 1; /* True if this represents a IPA function info. */ unsigned int is_fn_info : 1; + /* ??? Store somewhere better. */ + unsigned short ruid; + /* The ID of the variable for the next field in this structure or zero for the last field in this structure. */ unsigned next; @@ -381,6 +392,7 @@ new_var_info (tree t, const char *name) ret->is_heap_var = false; ret->may_have_pointers = true; ret->only_restrict_pointers = false; + ret->is_restrict_var = false; ret->is_global_var = (t == NULL_TREE); ret->is_fn_info = false; if (t && DECL_P (t)) @@ -3785,6 +3797,7 @@ static varinfo_t make_constraint_from_restrict (varinfo_t lhs, const char *name) { varinfo_t vi = make_heapvar (name); + vi->is_restrict_var = 1; vi->is_global_var = 1; vi->may_have_pointers = 1; make_constraint_from (lhs, vi->id); @@ -5749,7 +5762,11 @@ create_variable_info_for (tree decl, const char *name) && TYPE_RESTRICT (TREE_TYPE (decl))) || vi->only_restrict_pointers) { - make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT"); + varinfo_t rvi + = make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT"); + /* ??? For now exclude reads from globals as restrict sources + if those are not (indirectly) from incoming parameters. */ + rvi->is_restrict_var = false; continue; } @@ -5859,6 +5876,7 @@ intra_create_variable_infos (struct function *fn) tree heapvar = build_fake_var_decl (TREE_TYPE (TREE_TYPE (t))); DECL_EXTERNAL (heapvar) = 1; vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS"); + vi->is_restrict_var = 1; insert_vi_for_tree (heapvar, vi); lhsc.var = p->id; lhsc.type = SCALAR; @@ -6933,6 +6951,186 @@ delete_points_to_sets (void) obstack_free (&final_solutions_obstack, NULL); } +/* Mark "other" loads and stores as belonging to CLIQUE and with + base zero. */ + +static bool +visit_loadstore (gimple, tree base, tree ref, void *clique_) +{ + unsigned short clique = (uintptr_t)clique_; + if (TREE_CODE (base) == MEM_REF + || TREE_CODE (base) == TARGET_MEM_REF) + { + tree ptr = TREE_OPERAND (base, 0); + if (TREE_CODE (ptr) == SSA_NAME) + { + /* ??? We need to make sure 'ptr' doesn't include any of + the restrict tags in its points-to set. */ + return false; + } + + /* For now let decls through. */ + + /* Do not overwrite existing cliques (that includes clique, base + pairs we just set). */ + if (MR_DEPENDENCE_CLIQUE (base) == 0) + { + MR_DEPENDENCE_CLIQUE (base) = clique; + MR_DEPENDENCE_BASE (base) = 0; + } + } + + /* For plain decl accesses see whether they are accesses to globals + and rewrite them to MEM_REFs with { clique, 0 }. */ + if (TREE_CODE (base) == VAR_DECL + && is_global_var (base) + /* ??? We can't rewrite a plain decl with the walk_stmt_load_store + ops callback. */ + && base != ref) + { + tree *basep = &ref; + while (handled_component_p (*basep)) + basep = &TREE_OPERAND (*basep, 0); + gcc_assert (TREE_CODE (*basep) == VAR_DECL); + tree ptr = build_fold_addr_expr (*basep); + tree zero = build_int_cst (TREE_TYPE (ptr), 0); + *basep = build2 (MEM_REF, TREE_TYPE (*basep), ptr, zero); + MR_DEPENDENCE_CLIQUE (*basep) = clique; + MR_DEPENDENCE_BASE (*basep) = 0; + } + + return false; +} + +/* If REF is a MEM_REF then assign a clique, base pair to it, updating + CLIQUE, *RESTRICT_VAR and LAST_RUID. Return whether dependence info + was assigned to REF. */ + +static bool +maybe_set_dependence_info (tree ref, tree ptr, + unsigned short &clique, varinfo_t restrict_var, + unsigned short &last_ruid) +{ + while (handled_component_p (ref)) + ref = TREE_OPERAND (ref, 0); + if ((TREE_CODE (ref) == MEM_REF + || TREE_CODE (ref) == TARGET_MEM_REF) + && TREE_OPERAND (ref, 0) == ptr) + { + /* Do not overwrite existing cliques. This avoids overwriting dependence + info inlined from a function with restrict parameters inlined + into a function with restrict parameters. This usually means we + prefer to be precise in innermost loops. */ + if (MR_DEPENDENCE_CLIQUE (ref) == 0) + { + if (clique == 0) + clique = ++cfun->last_clique; + if (restrict_var->ruid == 0) + restrict_var->ruid = ++last_ruid; + MR_DEPENDENCE_CLIQUE (ref) = clique; + MR_DEPENDENCE_BASE (ref) = restrict_var->ruid; + return true; + } + } + return false; +} + +/* Compute the set of independend memory references based on restrict + tags and their conservative propagation to the points-to sets. */ + +static void +compute_dependence_clique (void) +{ + unsigned short clique = 0; + unsigned short last_ruid = 0; + for (unsigned i = 0; i < num_ssa_names; ++i) + { + tree ptr = ssa_name (i); + if (!ptr || !POINTER_TYPE_P (TREE_TYPE (ptr))) + continue; + + /* Avoid all this when ptr is not dereferenced? */ + tree p = ptr; + if (SSA_NAME_IS_DEFAULT_DEF (ptr) + && (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL + || TREE_CODE (SSA_NAME_VAR (ptr)) == RESULT_DECL)) + p = SSA_NAME_VAR (ptr); + varinfo_t vi = lookup_vi_for_tree (p); + if (!vi) + continue; + vi = get_varinfo (find (vi->id)); + bitmap_iterator bi; + unsigned j; + varinfo_t restrict_var = NULL; + EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, j, bi) + { + varinfo_t oi = get_varinfo (j); + if (oi->is_restrict_var) + { + if (restrict_var) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "found restrict pointed-to " + "for "); + print_generic_expr (dump_file, ptr, 0); + fprintf (dump_file, " but not exclusively\n"); + } + restrict_var = NULL; + break; + } + restrict_var = oi; + } + /* NULL is the only other valid points-to entry. */ + else if (oi->id != nothing_id) + { + restrict_var = NULL; + break; + } + } + /* Ok, found that ptr must(!) point to a single(!) restrict + variable. */ + /* ??? PTA isn't really a proper propagation engine to compute + this property. + ??? We could handle merging of two restricts by unifying them. */ + if (restrict_var) + { + /* Now look at possible dereferences of ptr. */ + imm_use_iterator ui; + gimple use_stmt; + FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr) + { + /* ??? Calls and asms. */ + if (!gimple_assign_single_p (use_stmt)) + continue; + maybe_set_dependence_info (gimple_assign_lhs (use_stmt), ptr, + clique, restrict_var, last_ruid); + maybe_set_dependence_info (gimple_assign_rhs1 (use_stmt), ptr, + clique, restrict_var, last_ruid); + } + } + } + + if (clique == 0) + return; + + /* Assign the BASE id zero to all accesses not based on a restrict + pointer. That way they get disabiguated against restrict + accesses but not against each other. */ + /* ??? For restricts derived from globals (thus not incoming + parameters) we can't restrict scoping properly thus the following + is too aggressive there. For now we have excluded those globals from + getting into the MR_DEPENDENCE machinery. */ + basic_block bb; + FOR_EACH_BB_FN (bb, cfun) + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); + !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + walk_stmt_load_store_ops (stmt, (void *)(uintptr_t)clique, + visit_loadstore, visit_loadstore); + } +} /* Compute points-to information for every SSA_NAME pointer in the current function and compute the transitive closure of escaped @@ -6964,6 +7162,9 @@ compute_may_aliases (void) if (dump_file) dump_alias_info (dump_file); + /* Compute restrict-based memory disambiguations. */ + compute_dependence_clique (); + /* Deallocate memory used by aliasing data structures and the internal points-to solution. */ delete_points_to_sets (); -- 2.30.2