re PR tree-optimization/55334 (mgrid regression (ipa-cp disables vectorization))
2014-11-24 Richard Biener <rguenther@suse.de> 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
This commit is contained in:
parent
f3dccf5091
commit
aa09816577
|
@ -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 ();
|
||||
|
|
Loading…
Reference in New Issue