process_constraint (new_constraint (lhs, rhs));
}
-/* Create a new artificial heap variable with NAME.
- Return the created variable. */
+/* Create a new artificial heap variable with NAME and make a
+ constraint from it to LHS. Return the created variable. */
static varinfo_t
make_heapvar_for (varinfo_t lhs, const char *name)
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);
basic_block bb;
unsigned i;
varinfo_t vi;
- struct pt_solution callused;
timevar_push (TV_TREE_PTA);
/* Compute the points-to set for ESCAPED used for call-clobber analysis. */
find_what_var_points_to (get_varinfo (escaped_id),
&cfun->gimple_df->escaped);
- find_what_var_points_to (get_varinfo (callused_id), &callused);
/* Make sure the ESCAPED solution (which is used as placeholder in
other solutions) does not reference itself. This simplifies
pt = gimple_call_use_set (stmt);
if (gimple_call_flags (stmt) & ECF_CONST)
memset (pt, 0, sizeof (struct pt_solution));
- else if (gimple_call_flags (stmt) & ECF_PURE)
+ else if ((vi = lookup_call_use_vi (stmt)) != NULL)
{
- /* For const calls we should now be able to compute the
- call-used set per function. */
- *pt = callused;
+ find_what_var_points_to (vi, pt);
+ /* Escaped (and thus nonlocal) variables are always
+ implicitly used by calls. */
/* ??? ESCAPED can be empty even though NONLOCAL
always escaped. */
pt->nonlocal = 1;
}
else
{
+ /* If there is nothing special about this call then
+ we have made everything that is used also escape. */
*pt = cfun->gimple_df->escaped;
pt->nonlocal = 1;
}
|| 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)
{