2010-04-15 Richard Guenther <rguenther@suse.de>
+ * tree-ssa-structalias.c (struct variable_info): Add
+ is_fn_info flag.
+ (new_var_info): Initialize it.
+ (dump_constraints): Support printing last added constraints.
+ (debug_constraints): Adjust.
+ (dump_constraint_graph): Likewise.
+ (make_heapvar_for): Check for NULL cfun.
+ (get_function_part_constraint): New function.
+ (get_fi_for_callee): Likewise.
+ (find_func_aliases): Properly implement IPA PTA constraints.
+ (process_ipa_clobber): New function.
+ (find_func_clobbers): Likewise.
+ (insert_into_field_list_sorted): Remove.
+ (create_function_info_for): Properly allocate vars for IPA mode.
+ Do not use insert_into_field_list_sorted.
+ (create_variable_info_for): Properly generate constraints for
+ global vars in IPA mode.
+ (dump_solution_for_var): Always dump the solution.
+ (set_uids_in_ptset): Initialize DECL_PT_UID if in ipa-mode.
+ (find_what_var_points_to): Adjust.
+ (pt_solution_set): Change.
+ (pt_solution_ior_into): New function.
+ (pt_solution_empty_p): Export.
+ (pt_solution_includes_global): Adjust.
+ (pt_solution_includes_1): Likewise.
+ (pt_solutions_intersect_1): Likewise.
+ (dump_sa_points_to_info): Check some invariants.
+ (solve_constraints): Move constraint dumping ...
+ (compute_points_to_sets): ... here.
+ (ipa_pta_execute): ... and here.
+ (compute_may_aliases): Do not re-compute points-to info
+ locally if IPA info is available.
+ (ipa_escaped_pt): New global var.
+ (ipa_pta_execute): Properly implement IPA PTA.
+ * tree-into-ssa.c (dump_decl_set): Support dumping
+ decls not in referenced-vars.
+ * tree-flow.h (struct gimple_df): Add ipa_pta flag.
+ * tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Adjust.
+ (dump_points_to_solution): Likewise.
+ * tree-dfa.c (dump_variable): Also dump DECL_PT_UID.
+ * tree-inline.c (remap_ssa_name): Copy IPA points-to solution.
+ (remap_gimple_stmt): Reset call clobber/use information if
+ necessary.
+ (copy_decl_to_var): Copy DECL_PT_UID.
+ (copy_result_decl_to_var): Likewise.
+ * tree.c (make_node_stat): Initialize DECL_PT_UID.
+ (copy_node_stat): Copy it.
+ * tree.h (DECL_PT_UID): New macro.
+ (SET_DECL_PT_UID): Likewise.
+ (DECL_PT_UID_SET_P): Likewise.
+ (struct tree_decl_minimal): Add pt_uid member.
+ * tree-ssa-alias.h (struct pt_solution): Add ipa_escaped flag.
+ (pt_solution_empty_p): Declare.
+ (pt_solution_set): Adjust.
+ (ipa_escaped_pt): Declare.
+ * cfgexpand.c (update_alias_info_with_stack_vars): Adjust.
+ * gimple-pretty-print.c (pp_points_to_solution): New function.
+ (dump_gimple_call): Dump call clobber/use information.
+ * tree-dump.c (dump_option_value_in): Add TDF_ALIAS entry.
+ * tree-pass.h (TDF_ALIAS): New dump option.
+ * tree-pretty-print.c (dump_decl_name): Dump DECL_PT_UID if asked to.
+ * doc/invoke.texi (-fipa-pta): Update documentation.
+
+2010-04-15 Richard Guenther <rguenther@suse.de>
+
* Makefile.in (OBJS-common): Add gimple-fold.o.
(gimple-fold.o): New rule.
* tree.h (maybe_fold_offset_to_reference,
else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
{
varinfo_t ai = first_vi_for_offset (fi, part);
- if (ai)
- c.var = ai->id;
- else
- c.var = anything_id;
+ c.var = ai ? ai->id : anything_id;
c.offset = 0;
c.type = SCALAR;
}
/* If we are returning a value, assign it to the result. */
lhsop = gimple_call_lhs (t);
if (lhsop
- && type_could_have_pointers (TREE_TYPE (lhsop)))
+ && could_have_pointers (lhsop))
{
struct constraint_expr rhs;
struct constraint_expr *lhsp;
OFFSET. If there is no such varinfo the varinfo directly preceding
OFFSET is returned. */
-static varinfo_t
-first_or_preceding_vi_for_offset (varinfo_t start,
- unsigned HOST_WIDE_INT offset)
+static void
+process_ipa_clobber (varinfo_t fi, tree ptr)
{
- /* If we cannot reach offset from start, lookup the first field
- and start from there. */
- if (start->offset > offset)
- start = lookup_vi_for_tree (start->decl);
+ VEC(ce_s, heap) *ptrc = NULL;
+ struct constraint_expr *c, lhs;
+ unsigned i;
+ get_constraint_for (ptr, &ptrc);
+ lhs = get_function_part_constraint (fi, fi_clobbers);
+ for (i = 0; VEC_iterate (ce_s, ptrc, i, c); i++)
+ process_constraint (new_constraint (lhs, *c));
+ VEC_free (ce_s, heap, ptrc);
+}
- /* We may not find a variable in the field list with the actual
- offset when when we have glommed a structure to a variable.
- In that case, however, offset should still be within the size
- of the variable.
- If we got beyond the offset we look for return the field
- directly preceding offset which may be the last field. */
- while (start->next
- && offset >= start->offset
- && !((offset - start->offset) < start->size))
- start = start->next;
+/* Walk statement T setting up clobber and use constraints according to the
+ references found in T. This function is a main part of the
+ IPA constraint builder. */
- return start;
-}
+static void
+find_func_clobbers (gimple origt)
+{
+ gimple t = origt;
+ VEC(ce_s, heap) *lhsc = NULL;
+ VEC(ce_s, heap) *rhsc = NULL;
+ varinfo_t fi;
+ /* Add constraints for clobbered/used in IPA mode.
+ We are not interested in what automatic variables are clobbered
+ or used as we only use the information in the caller to which
+ they do not escape. */
+ gcc_assert (in_ipa_mode);
/* This structure is used during pushing fields onto the fieldstack
to track the offset of the field, since bitpos_of_field gives it
gcc_assert (prev_vi->offset < clobbervi->offset);
prev_vi->next = clobbervi;
prev_vi = clobbervi;
+ stats.total_vars++;
asprintf (&tempname, "%s.use", name);
newname = ggc_strdup (tempname);
gcc_assert (prev_vi->offset < usevi->offset);
prev_vi->next = usevi;
prev_vi = usevi;
+ stats.total_vars++;
}
/* And one for the static chain. */
gcc_assert (prev_vi->offset < chainvi->offset);
prev_vi->next = chainvi;
prev_vi = chainvi;
+ stats.total_vars++;
insert_vi_for_tree (fn->static_chain_decl, chainvi);
}
gcc_assert (prev_vi->offset < resultvi->offset);
prev_vi->next = resultvi;
prev_vi = resultvi;
+ stats.total_vars++;
if (DECL_RESULT (decl))
insert_vi_for_tree (DECL_RESULT (decl), resultvi);
}
gcc_assert (prev_vi->offset < argvi->offset);
prev_vi->next = argvi;
prev_vi = argvi;
+ stats.total_vars++;
if (arg)
{
insert_vi_for_tree (arg, argvi);
gcc_assert (prev_vi->offset < argvi->offset);
prev_vi->next = argvi;
prev_vi = argvi;
+ stats.total_vars++;
}
return vi;
vi = new_var_info (decl, name);
vi->offset = 0;
vi->size = ~0;
- vi->fullsize = ~0;
- vi->is_unknown_size_var = true;
- vi->is_full_var = true;
- vi->may_have_pointers = could_have_pointers (decl);
- return vi;
+ }
+ else
+ {
+ vi->fullsize = TREE_INT_CST_LOW (declsize);
+ vi->size = vi->fullsize;
+ }
+
+ insert_vi_for_tree (vi->decl, vi);
+
+ /* ??? The setting of vi->may_have_pointers is too conservative here
+ and may get refined below. Thus we have superfluous constraints
+ here sometimes which triggers the commented assert in
+ dump_sa_points_to_info. */
+ if (vi->is_global_var
+ && vi->may_have_pointers)
+ {
+ /* Mark global restrict qualified pointers. */
+ if (POINTER_TYPE_P (TREE_TYPE (decl))
+ && TYPE_RESTRICT (TREE_TYPE (decl)))
+ make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+
+ /* For escaped variables initialize them from nonlocal. */
+ if (!in_ipa_mode
+ || DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
+ make_copy_constraint (vi, nonlocal_id);
+
+ /* If this is a global variable with an initializer and we are in
+ IPA mode generate constraints for it. In non-IPA mode
+ the initializer from nonlocal is all we need. */
+ if (in_ipa_mode
+ && DECL_INITIAL (vi->decl))
+ {
+ VEC (ce_s, heap) *rhsc = NULL;
+ struct constraint_expr lhs, *rhsp;
+ unsigned i;
+ get_constraint_for (DECL_INITIAL (vi->decl), &rhsc);
+ lhs.var = vi->id;
+ lhs.offset = 0;
+ lhs.type = SCALAR;
+ for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
+ process_constraint (new_constraint (lhs, *rhsp));
+ /* If this is a variable that escapes from the unit
+ the initializer escapes as well. */
+ if (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
+ {
+ lhs.var = escaped_id;
+ lhs.offset = 0;
+ lhs.type = SCALAR;
+ for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
+ process_constraint (new_constraint (lhs, *rhsp));
+ }
+ VEC_free (ce_s, heap, rhsc);
+ /* ??? Force us to not use subfields. Else we'd have to parse
+ arbitrary initializers. */
+ VEC_free (fieldoff_s, heap, fieldstack);
+ }
}
/* Collect field information. */
const char *newname = "NULL";
char *tempname;
- if (dump_file)
+ vi->offset = fo->offset;
+ vi->may_have_pointers = fo->may_have_pointers;
+ if (vi->is_global_var
+ && vi->may_have_pointers)
{
asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
"+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
if (vi->id == nothing_id)
pt->null = 1;
else if (vi->id == escaped_id)
- pt->escaped = 1;
+ {
+ if (in_ipa_mode)
+ pt->ipa_escaped = 1;
+ else
+ pt->escaped = 1;
+ }
else if (vi->id == nonlocal_id)
pt->nonlocal = 1;
else if (vi->is_heap_var)
{
varinfo_t vi = get_varinfo (i);
if (!vi->may_have_pointers)
- continue;
+ {
+ gcc_assert (find (i) == i
+ || !(vi = get_varinfo (find (i)))->may_have_pointers);
+ /* ??? See create_variable_info_for.
+ gcc_assert (bitmap_empty_p (vi->solution)); */
+ continue;
+ }
dump_solution_for_var (outfile, i);
}
}
|| node->clone_of)
continue;
- vi = create_function_info_for (node->decl,
- alias_get_name (node->decl));
-
- /* Associate the varinfo node with all aliases. */
- for (alias = node->same_body; alias; alias = alias->next)
- insert_vi_for_tree (alias->decl, vi);
+ create_function_info_for (node->decl,
+ cgraph_node_name (node));
}
/* Create constraints for global variables and their initializers. */
for (var = varpool_nodes; var; var = var->next)
- {
- struct varpool_node *alias;
- varinfo_t vi;
-
- vi = get_vi_for_tree (var->decl);
-
- /* Associate the varinfo node with all aliases. */
- for (alias = var->extra_name; alias; alias = alias->next)
- insert_vi_for_tree (alias->decl, vi);
- }
+ get_vi_for_tree (var->decl);
if (dump_file)
{