#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
/* 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;
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))
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);
&& 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;
}
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;
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
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 ();