/* True if this is a variable created by the constraint analysis, such as
heap variables and constraints we had to break up. */
- unsigned int is_artificial_var:1;
+ unsigned int is_artificial_var : 1;
/* True if this is a special variable whose solution set should not be
changed. */
- unsigned int is_special_var:1;
+ unsigned int is_special_var : 1;
/* True for variables whose size is not known or variable. */
- unsigned int is_unknown_size_var:1;
+ unsigned int is_unknown_size_var : 1;
/* True for (sub-)fields that represent a whole variable. */
unsigned int is_full_var : 1;
/* True if this is a heap variable. */
- unsigned int is_heap_var:1;
+ unsigned int is_heap_var : 1;
+
+ /* True if this is a variable tracking a restrict pointer source. */
+ unsigned int is_restrict_var : 1;
/* True if this field may contain pointers. */
unsigned int may_have_pointers : 1;
+ /* True if this represents a global variable. */
+ unsigned int is_global_var : 1;
+
/* A link to the variable for the next field in this structure. */
struct variable_info *next;
escaped_id = 3, nonlocal_id = 4, callused_id = 5,
storedanything_id = 6, integer_id = 7 };
-/* Variable that represents the unknown pointer. */
-static varinfo_t var_anything;
-static tree anything_tree;
-
-/* Variable that represents the NULL pointer. */
-static varinfo_t var_nothing;
-static tree nothing_tree;
-
-/* Variable that represents read only memory. */
-static varinfo_t var_readonly;
-static tree readonly_tree;
-
-/* Variable that represents escaped memory. */
-static varinfo_t var_escaped;
-static tree escaped_tree;
-
-/* Variable that represents nonlocal memory. */
-static varinfo_t var_nonlocal;
-static tree nonlocal_tree;
-
-/* Variable that represents call-used memory. */
-static varinfo_t var_callused;
-static tree callused_tree;
+struct GTY(()) heapvar_map {
+ struct tree_map map;
+ unsigned HOST_WIDE_INT offset;
+};
-/* Variable that represents variables that are stored to anything. */
-static varinfo_t var_storedanything;
-static tree storedanything_tree;
+static int
+heapvar_map_eq (const void *p1, const void *p2)
+{
+ const struct heapvar_map *h1 = (const struct heapvar_map *)p1;
+ const struct heapvar_map *h2 = (const struct heapvar_map *)p2;
+ return (h1->map.base.from == h2->map.base.from
+ && h1->offset == h2->offset);
+}
-/* Variable that represents integers. This is used for when people do things
- like &0->a.b. */
-static varinfo_t var_integer;
-static tree integer_tree;
+static unsigned int
+heapvar_map_hash (struct heapvar_map *h)
+{
+ return iterative_hash_host_wide_int (h->offset,
+ htab_hash_pointer (h->map.base.from));
+}
/* Lookup a heap var for FROM, and return it if we find one. */
static tree
-heapvar_lookup (tree from)
+heapvar_lookup (tree from, unsigned HOST_WIDE_INT offset)
{
- struct tree_map *h, in;
- in.base.from = from;
-
- h = (struct tree_map *) htab_find_with_hash (heapvar_for_stmt, &in,
- htab_hash_pointer (from));
+ struct heapvar_map *h, in;
+ in.map.base.from = from;
+ in.offset = offset;
+ h = (struct heapvar_map *) htab_find_with_hash (heapvar_for_stmt, &in,
+ heapvar_map_hash (&in));
if (h)
- return h->to;
+ return h->map.to;
return NULL_TREE;
}
hashtable. */
static void
-heapvar_insert (tree from, tree to)
+heapvar_insert (tree from, unsigned HOST_WIDE_INT offset, tree to)
{
- struct tree_map *h;
+ struct heapvar_map *h;
void **loc;
- h = GGC_NEW (struct tree_map);
- h->hash = htab_hash_pointer (from);
- h->base.from = from;
- h->to = to;
- loc = htab_find_slot_with_hash (heapvar_for_stmt, h, h->hash, INSERT);
- *(struct tree_map **) loc = h;
+ h = GGC_NEW (struct heapvar_map);
+ h->map.base.from = from;
+ h->offset = offset;
+ h->map.hash = heapvar_map_hash (h);
+ h->map.to = to;
+ loc = htab_find_slot_with_hash (heapvar_for_stmt, h, h->map.hash, INSERT);
+ gcc_assert (*loc == NULL);
+ *(struct heapvar_map **) loc = h;
}
/* Return a new variable info structure consisting for a variable
- named NAME, and using constraint graph node NODE. */
+ named NAME, and using constraint graph node NODE. Append it
+ to the vector of variable info structures. */
static varinfo_t
-new_var_info (tree t, unsigned int id, const char *name)
+new_var_info (tree t, const char *name)
{
+ unsigned index = VEC_length (varinfo_t, varmap);
varinfo_t ret = (varinfo_t) pool_alloc (variable_info_pool);
- ret->id = id;
+ ret->id = index;
ret->name = name;
ret->decl = t;
- ret->is_artificial_var = false;
- ret->is_heap_var = false;
+ /* Vars without decl are artificial and do not have sub-variables. */
+ ret->is_artificial_var = (t == NULL_TREE);
ret->is_special_var = false;
ret->is_unknown_size_var = false;
- ret->is_full_var = false;
+ ret->is_full_var = (t == NULL_TREE);
+ ret->is_heap_var = false;
+ ret->is_restrict_var = false;
ret->may_have_pointers = true;
+ ret->is_global_var = (t == NULL_TREE);
+ if (t && DECL_P (t))
+ ret->is_global_var = is_global_var (t);
ret->solution = BITMAP_ALLOC (&pta_obstack);
ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
ret->next = NULL;
+
+ VEC_safe_push (varinfo_t, heap, varmap, ret);
+
return ret;
}
unsigned int t;
HOST_WIDE_INT fieldoffset = v->offset + loff;
- /* If v is a NONLOCAL then this is an escape point. */
- if (j == nonlocal_id)
+ /* If v is a global variable then this is an escape point. */
+ if (v->is_global_var)
{
t = find (escaped_id);
if (add_graph_edge (graph, t, rhs)
changed_count++;
}
}
- /* If v is a global variable then this is an escape point. */
- if (is_global_var (v->decl))
- {
- t = find (escaped_id);
- if (add_graph_edge (graph, t, rhs)
- && bitmap_ior_into (get_varinfo (t)->solution, sol)
- && !TEST_BIT (changed, t))
- {
- SET_BIT (changed, t);
- changed_count++;
- }
- }
/* If the variable is not exactly at the requested offset
we have to include the next one. */
new_scalar_tmp_constraint_exp (const char *name)
{
struct constraint_expr tmp;
- unsigned index = VEC_length (varinfo_t, varmap);
varinfo_t vi;
- vi = new_var_info (NULL_TREE, index, name);
+ vi = new_var_info (NULL_TREE, name);
vi->offset = 0;
vi->size = -1;
vi->fullsize = -1;
vi->is_full_var = 1;
- VEC_safe_push (varinfo_t, heap, varmap, vi);
tmp.var = vi->id;
tmp.type = SCALAR;
VEC_free (ce_s, heap, rhsc);
}
+/* Create a constraint ID = &FROM. */
+
+static void
+make_constraint_from (varinfo_t vi, int from)
+{
+ struct constraint_expr lhs, rhs;
+
+ lhs.var = vi->id;
+ lhs.offset = 0;
+ lhs.type = SCALAR;
+
+ rhs.var = from;
+ rhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ process_constraint (new_constraint (lhs, rhs));
+}
+
+/* Create a constraint ID = FROM. */
+
+static void
+make_copy_constraint (varinfo_t vi, int from)
+{
+ struct constraint_expr lhs, rhs;
+
+ lhs.var = vi->id;
+ lhs.offset = 0;
+ lhs.type = SCALAR;
+
+ rhs.var = from;
+ rhs.offset = 0;
+ rhs.type = SCALAR;
+ process_constraint (new_constraint (lhs, rhs));
+}
+
/* Make constraints necessary to make OP escape. */
static void
make_constraint_to (escaped_id, op);
}
+/* Create a new artificial heap variable with NAME and make a
+ constraint from it to LHS. Return the created variable. */
+
+static varinfo_t
+make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+{
+ varinfo_t vi;
+ tree heapvar = heapvar_lookup (lhs->decl, lhs->offset);
+
+ if (heapvar == NULL_TREE)
+ {
+ var_ann_t ann;
+ heapvar = create_tmp_var_raw (ptr_type_node, name);
+ DECL_EXTERNAL (heapvar) = 1;
+
+ heapvar_insert (lhs->decl, lhs->offset, heapvar);
+
+ ann = get_var_ann (heapvar);
+ ann->is_heapvar = 1;
+ }
+
+ /* For global vars we need to add a heapvar to the list of referenced
+ vars of a different function than it was created for originally. */
+ if (gimple_referenced_vars (cfun))
+ add_referenced_var (heapvar);
+
+ vi = new_var_info (heapvar, name);
+ vi->is_artificial_var = true;
+ vi->is_heap_var = true;
+ vi->is_unknown_size_var = true;
+ vi->offset = 0;
+ vi->fullsize = ~0;
+ vi->size = ~0;
+ vi->is_full_var = true;
+ insert_vi_for_tree (heapvar, vi);
+
+ make_constraint_from (lhs, vi->id);
+
+ return vi;
+}
+
+/* Create a new artificial heap variable with NAME and make a
+ constraint from it to LHS. Set flags according to a tag used
+ for tracking restrict pointers. */
+
+static void
+make_constraint_from_restrict (varinfo_t lhs, const char *name)
+{
+ varinfo_t vi;
+ vi = make_constraint_from_heapvar (lhs, name);
+ vi->is_restrict_var = 1;
+ vi->is_global_var = 0;
+ vi->is_special_var = 1;
+ vi->may_have_pointers = 0;
+}
+
/* For non-IPA mode, generate constraints necessary for a call on the
RHS. */
handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc)
{
VEC(ce_s, heap) *lhsc = NULL;
- unsigned int j;
- struct constraint_expr *lhsp;
get_constraint_for (lhs, &lhsc);
if (flags & ECF_MALLOC)
{
- struct constraint_expr rhsc;
- tree heapvar = heapvar_lookup (lhs);
varinfo_t vi;
-
- if (heapvar == NULL)
- {
- heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
- DECL_EXTERNAL (heapvar) = 1;
- get_var_ann (heapvar)->is_heapvar = 1;
- if (gimple_referenced_vars (cfun))
- add_referenced_var (heapvar);
- heapvar_insert (lhs, heapvar);
- }
-
- rhsc.var = create_variable_info_for (heapvar,
- alias_get_name (heapvar));
- vi = get_varinfo (rhsc.var);
- vi->is_artificial_var = 1;
- vi->is_heap_var = 1;
- vi->is_unknown_size_var = true;
- vi->fullsize = ~0;
- vi->size = ~0;
- rhsc.type = ADDRESSOF;
- rhsc.offset = 0;
- for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
- process_constraint (new_constraint (*lhsp, rhsc));
+ vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
+ /* We delay marking allocated storage global until we know if
+ it escapes. */
+ DECL_EXTERNAL (vi->decl) = 0;
+ vi->is_global_var = 0;
}
else if (VEC_length (ce_s, rhsc) > 0)
{
&& DECL_P (lhsop)
&& is_global_var (lhsop))
make_escape_constraint (rhsop);
+ /* If this is a conversion of a non-restrict pointer to a
+ restrict pointer track it with a new heapvar. */
+ else if (gimple_assign_cast_p (t)
+ && POINTER_TYPE_P (TREE_TYPE (rhsop))
+ && POINTER_TYPE_P (TREE_TYPE (lhsop))
+ && !TYPE_RESTRICT (TREE_TYPE (rhsop))
+ && TYPE_RESTRICT (TREE_TYPE (lhsop)))
+ make_constraint_from_restrict (get_vi_for_tree (lhsop),
+ "CAST_RESTRICT");
}
/* For conversions of pointers to non-pointers the pointer escapes. */
else if (gimple_assign_cast_p (t)
{
make_escape_constraint (gimple_assign_rhs1 (t));
}
+ /* Handle escapes through return. */
+ else if (gimple_code (t) == GIMPLE_RETURN
+ && gimple_return_retval (t) != NULL_TREE
+ && could_have_pointers (gimple_return_retval (t)))
+ {
+ make_escape_constraint (gimple_return_retval (t));
+ }
/* Handle asms conservatively by adding escape constraints to everything. */
else if (gimple_code (t) == GIMPLE_ASM)
{
unsigned has_unknown_size : 1;
unsigned may_have_pointers : 1;
+
+ unsigned only_restrict_pointers : 1;
};
typedef struct fieldoff fieldoff_s;
else
pair->size = -1;
pair->may_have_pointers = could_have_pointers (field);
+ pair->only_restrict_pointers
+ = (!has_unknown_size
+ && POINTER_TYPE_P (TREE_TYPE (field))
+ && TYPE_RESTRICT (TREE_TYPE (field)));
count++;
}
}
return count;
}
-/* Create a constraint ID = &FROM. */
-
-static void
-make_constraint_from (varinfo_t vi, int from)
-{
- struct constraint_expr lhs, rhs;
-
- lhs.var = vi->id;
- lhs.offset = 0;
- lhs.type = SCALAR;
-
- rhs.var = from;
- rhs.offset = 0;
- rhs.type = ADDRESSOF;
- process_constraint (new_constraint (lhs, rhs));
-}
-
-/* Create a constraint ID = FROM. */
-
-static void
-make_copy_constraint (varinfo_t vi, int from)
-{
- struct constraint_expr lhs, rhs;
-
- lhs.var = vi->id;
- lhs.offset = 0;
- lhs.type = SCALAR;
-
- rhs.var = from;
- rhs.offset = 0;
- rhs.type = SCALAR;
- process_constraint (new_constraint (lhs, rhs));
-}
-
/* Count the number of arguments DECL has, and set IS_VARARGS to true
if it is a varargs function. */
static unsigned int
create_function_info_for (tree decl, const char *name)
{
- unsigned int index = VEC_length (varinfo_t, varmap);
varinfo_t vi;
tree arg;
unsigned int i;
/* Create the variable info. */
- vi = new_var_info (decl, index, name);
+ vi = new_var_info (decl, name);
vi->offset = 0;
vi->size = 1;
vi->fullsize = count_num_arguments (decl, &is_varargs) + 1;
insert_vi_for_tree (vi->decl, vi);
- VEC_safe_push (varinfo_t, heap, varmap, vi);
stats.total_vars++;
vi->fullsize = ~0;
vi->size = ~0;
vi->is_unknown_size_var = true;
- return index;
+ return vi->id;
}
-
arg = DECL_ARGUMENTS (decl);
/* Set up variables for each argument. */
varinfo_t argvi;
const char *newname;
char *tempname;
- unsigned int newindex;
tree argdecl = decl;
if (arg)
argdecl = arg;
- newindex = VEC_length (varinfo_t, varmap);
asprintf (&tempname, "%s.arg%d", name, i-1);
newname = ggc_strdup (tempname);
free (tempname);
- argvi = new_var_info (argdecl, newindex, newname);
- VEC_safe_push (varinfo_t, heap, varmap, argvi);
+ argvi = new_var_info (argdecl, newname);
argvi->offset = i;
argvi->size = 1;
argvi->is_full_var = true;
varinfo_t resultvi;
const char *newname;
char *tempname;
- unsigned int newindex;
tree resultdecl = decl;
vi->fullsize ++;
if (DECL_RESULT (decl))
resultdecl = DECL_RESULT (decl);
- newindex = VEC_length (varinfo_t, varmap);
asprintf (&tempname, "%s.result", name);
newname = ggc_strdup (tempname);
free (tempname);
- resultvi = new_var_info (resultdecl, newindex, newname);
- VEC_safe_push (varinfo_t, heap, varmap, resultvi);
+ resultvi = new_var_info (resultdecl, newname);
resultvi->offset = i;
resultvi->size = 1;
resultvi->fullsize = vi->fullsize;
if (DECL_RESULT (decl))
insert_vi_for_tree (DECL_RESULT (decl), resultvi);
}
- return index;
+
+ return vi->id;
}
static unsigned int
create_variable_info_for (tree decl, const char *name)
{
- unsigned int index = VEC_length (varinfo_t, varmap);
varinfo_t vi;
tree decl_type = TREE_TYPE (decl);
tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
- bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
VEC (fieldoff_s,heap) *fieldstack = NULL;
if (TREE_CODE (decl) == FUNCTION_DECL && in_ipa_mode)
return create_function_info_for (decl, name);
- if (var_can_have_subvars (decl) && use_field_sensitive
- && (!var_ann (decl)
- || var_ann (decl)->noalias_state == 0)
- && (!var_ann (decl)
- || !var_ann (decl)->is_heapvar))
+ if (var_can_have_subvars (decl) && use_field_sensitive)
push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
/* If the variable doesn't have subvars, we may end up needing to
sort the field list and create fake variables for all the
fields. */
- vi = new_var_info (decl, index, name);
+ vi = new_var_info (decl, name);
vi->offset = 0;
vi->may_have_pointers = could_have_pointers (decl);
if (!declsize
}
insert_vi_for_tree (vi->decl, vi);
- VEC_safe_push (varinfo_t, heap, varmap, vi);
- if (is_global && (!flag_whole_program || !in_ipa_mode)
+ if (vi->is_global_var
+ && (!flag_whole_program || !in_ipa_mode)
&& vi->may_have_pointers)
{
- if (var_ann (decl)
- && var_ann (decl)->noalias_state == NO_ALIAS_ANYTHING)
- make_constraint_from (vi, vi->id);
- else
- make_copy_constraint (vi, nonlocal_id);
+ if (POINTER_TYPE_P (TREE_TYPE (decl))
+ && TYPE_RESTRICT (TREE_TYPE (decl)))
+ make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+ make_copy_constraint (vi, nonlocal_id);
}
stats.total_vars++;
&& VEC_length (fieldoff_s, fieldstack) > 1
&& VEC_length (fieldoff_s, fieldstack) <= MAX_FIELDS_FOR_FIELD_SENSITIVE)
{
- unsigned int newindex = VEC_length (varinfo_t, varmap);
fieldoff_s *fo = NULL;
bool notokay = false;
unsigned int i;
vi->size = ~0;
vi->is_full_var = true;
VEC_free (fieldoff_s, heap, fieldstack);
- return index;
+ return vi->id;
}
vi->size = fo->size;
const char *newname = "NULL";
char *tempname;
- newindex = VEC_length (varinfo_t, varmap);
if (dump_file)
{
asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
newname = ggc_strdup (tempname);
free (tempname);
}
- newvi = new_var_info (decl, newindex, newname);
+ newvi = new_var_info (decl, newname);
newvi->offset = fo->offset;
newvi->size = fo->size;
newvi->fullsize = vi->fullsize;
newvi->may_have_pointers = fo->may_have_pointers;
insert_into_field_list (vi, newvi);
- VEC_safe_push (varinfo_t, heap, varmap, newvi);
- if (is_global && (!flag_whole_program || !in_ipa_mode)
+ if (newvi->is_global_var
+ && (!flag_whole_program || !in_ipa_mode)
&& newvi->may_have_pointers)
- make_copy_constraint (newvi, nonlocal_id);
+ {
+ if (fo->only_restrict_pointers)
+ make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
+ make_copy_constraint (newvi, nonlocal_id);
+ }
stats.total_vars++;
}
VEC_free (fieldoff_s, heap, fieldstack);
- return index;
+ return vi->id;
}
/* Print out the points-to solution for VAR to FILE. */
intra_create_variable_infos (void)
{
tree t;
- struct constraint_expr lhs, rhs;
/* For each incoming pointer argument arg, create the constraint ARG
= NONLOCAL or a dummy variable if flag_argument_noalias is set. */
if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0)
{
varinfo_t vi;
- tree heapvar = heapvar_lookup (t);
-
- lhs.offset = 0;
- lhs.type = SCALAR;
- lhs.var = get_vi_for_tree (t)->id;
+ var_ann_t ann;
- if (heapvar == NULL_TREE)
+ vi = make_constraint_from_heapvar (get_vi_for_tree (t),
+ "PARM_NOALIAS");
+ ann = get_var_ann (vi->decl);
+ if (flag_argument_noalias == 1)
{
- var_ann_t ann;
- heapvar = create_tmp_var_raw (ptr_type_node,
- "PARM_NOALIAS");
- DECL_EXTERNAL (heapvar) = 1;
- if (gimple_referenced_vars (cfun))
- add_referenced_var (heapvar);
-
- heapvar_insert (t, heapvar);
-
- ann = get_var_ann (heapvar);
- ann->is_heapvar = 1;
- if (flag_argument_noalias == 1)
- ann->noalias_state = NO_ALIAS;
- else if (flag_argument_noalias == 2)
- ann->noalias_state = NO_ALIAS_GLOBAL;
- else if (flag_argument_noalias == 3)
- ann->noalias_state = NO_ALIAS_ANYTHING;
- else
- gcc_unreachable ();
+ ann->noalias_state = NO_ALIAS;
+ make_copy_constraint (vi, nonlocal_id);
}
-
- vi = get_vi_for_tree (heapvar);
- vi->is_artificial_var = 1;
- vi->is_heap_var = 1;
- vi->is_unknown_size_var = true;
- vi->fullsize = ~0;
- vi->size = ~0;
- rhs.var = vi->id;
- rhs.type = ADDRESSOF;
- rhs.offset = 0;
- for (p = get_varinfo (lhs.var); p; p = p->next)
+ else if (flag_argument_noalias == 2)
+ {
+ ann->noalias_state = NO_ALIAS_GLOBAL;
+ make_constraint_from (vi, vi->id);
+ }
+ else if (flag_argument_noalias == 3)
{
- struct constraint_expr temp = lhs;
- temp.var = p->id;
- process_constraint (new_constraint (temp, rhs));
+ ann->noalias_state = NO_ALIAS_ANYTHING;
+ make_constraint_from (vi, vi->id);
}
+ else
+ gcc_unreachable ();
}
else
{
for (p = arg_vi; p; p = p->next)
make_constraint_from (p, nonlocal_id);
}
+ if (POINTER_TYPE_P (TREE_TYPE (t))
+ && TYPE_RESTRICT (TREE_TYPE (t)))
+ make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
}
/* Add a constraint for a result decl that is passed by reference. */
/* Add the decl to the points-to set. Note that the points-to
set contains global variables. */
bitmap_set_bit (into, DECL_UID (vi->decl));
- if (is_global_var (vi->decl))
+ if (vi->is_global_var)
pt->vars_contains_global = true;
}
}
bitmap_iterator bi;
bitmap finished_solution;
bitmap result;
- tree ptr = vi->decl;
memset (pt, 0, sizeof (struct pt_solution));
else if (vi->is_heap_var)
/* We represent heapvars in the points-to set properly. */
;
+ else if (vi->id == readonly_id)
+ /* Nobody cares. */
+ ;
else if (vi->id == anything_id
- || vi->id == readonly_id
|| vi->id == integer_id)
pt->anything = 1;
}
+ if (vi->is_restrict_var)
+ pt->vars_contains_restrict = true;
}
/* Instead of doing extra work, simply do not create
elaborate points-to information for pt_anything pointers. */
- if (pt->anything)
+ if (pt->anything
+ && (vi->is_artificial_var
+ || !pt->vars_contains_restrict))
return;
/* Share the final set of variables when possible. */
finished_solution = BITMAP_GGC_ALLOC ();
stats.points_to_sets_created++;
- if (TREE_CODE (ptr) == SSA_NAME)
- ptr = SSA_NAME_VAR (ptr);
-
set_uids_in_ptset (finished_solution, vi->solution, pt);
result = shared_bitmap_lookup (finished_solution);
if (!result)
pt->anything = true;
}
+/* Set the points-to solution *PT to point only to the variables
+ in VARS. */
+
+void
+pt_solution_set (struct pt_solution *pt, bitmap vars)
+{
+ bitmap_iterator bi;
+ unsigned i;
+
+ memset (pt, 0, sizeof (struct pt_solution));
+ pt->vars = vars;
+ EXECUTE_IF_SET_IN_BITMAP (vars, 0, i, bi)
+ {
+ tree var = referenced_var_lookup (i);
+ if (is_global_var (var))
+ {
+ pt->vars_contains_global = true;
+ break;
+ }
+ }
+}
+
/* Return true if the points-to solution *PT is empty. */
static bool
return res;
}
+/* Return true if both points-to solutions PT1 and PT2 for two restrict
+ qualified pointers are possibly based on the same pointer. */
+
+bool
+pt_solutions_same_restrict_base (struct pt_solution *pt1,
+ struct pt_solution *pt2)
+{
+ /* If we deal with points-to solutions of two restrict qualified
+ pointers solely rely on the pointed-to variable bitmap intersection.
+ For two pointers that are based on each other the bitmaps will
+ intersect. */
+ if (pt1->vars_contains_restrict
+ && pt2->vars_contains_restrict)
+ {
+ gcc_assert (pt1->vars && pt2->vars);
+ return bitmap_intersect_p (pt1->vars, pt2->vars);
+ }
+
+ return true;
+}
+
/* Dump points-to information to OUTFILE. */
init_base_vars (void)
{
struct constraint_expr lhs, rhs;
+ varinfo_t var_anything;
+ varinfo_t var_nothing;
+ varinfo_t var_readonly;
+ varinfo_t var_escaped;
+ varinfo_t var_nonlocal;
+ varinfo_t var_callused;
+ varinfo_t var_storedanything;
+ varinfo_t var_integer;
/* Create the NULL variable, used to represent that a variable points
to NULL. */
- nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
- var_nothing = new_var_info (nothing_tree, nothing_id, "NULL");
- insert_vi_for_tree (nothing_tree, var_nothing);
+ var_nothing = new_var_info (NULL_TREE, "NULL");
+ gcc_assert (var_nothing->id == nothing_id);
var_nothing->is_artificial_var = 1;
var_nothing->offset = 0;
var_nothing->size = ~0;
var_nothing->fullsize = ~0;
var_nothing->is_special_var = 1;
- VEC_safe_push (varinfo_t, heap, varmap, var_nothing);
/* Create the ANYTHING variable, used to represent that a variable
points to some unknown piece of memory. */
- anything_tree = create_tmp_var_raw (ptr_type_node, "ANYTHING");
- var_anything = new_var_info (anything_tree, anything_id, "ANYTHING");
- insert_vi_for_tree (anything_tree, var_anything);
+ var_anything = new_var_info (NULL_TREE, "ANYTHING");
+ gcc_assert (var_anything->id == anything_id);
var_anything->is_artificial_var = 1;
var_anything->size = ~0;
var_anything->offset = 0;
/* Anything points to anything. This makes deref constraints just
work in the presence of linked list and other p = *p type loops,
by saying that *ANYTHING = ANYTHING. */
- VEC_safe_push (varinfo_t, heap, varmap, var_anything);
lhs.type = SCALAR;
lhs.var = anything_id;
lhs.offset = 0;
/* Create the READONLY variable, used to represent that a variable
points to readonly memory. */
- readonly_tree = create_tmp_var_raw (ptr_type_node, "READONLY");
- var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY");
+ var_readonly = new_var_info (NULL_TREE, "READONLY");
+ gcc_assert (var_readonly->id == readonly_id);
var_readonly->is_artificial_var = 1;
var_readonly->offset = 0;
var_readonly->size = ~0;
var_readonly->fullsize = ~0;
var_readonly->next = NULL;
var_readonly->is_special_var = 1;
- insert_vi_for_tree (readonly_tree, var_readonly);
- VEC_safe_push (varinfo_t, heap, varmap, var_readonly);
/* readonly memory points to anything, in order to make deref
easier. In reality, it points to anything the particular
/* Create the ESCAPED variable, used to represent the set of escaped
memory. */
- escaped_tree = create_tmp_var_raw (ptr_type_node, "ESCAPED");
- var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED");
- insert_vi_for_tree (escaped_tree, var_escaped);
+ var_escaped = new_var_info (NULL_TREE, "ESCAPED");
+ gcc_assert (var_escaped->id == escaped_id);
var_escaped->is_artificial_var = 1;
var_escaped->offset = 0;
var_escaped->size = ~0;
var_escaped->fullsize = ~0;
var_escaped->is_special_var = 0;
- VEC_safe_push (varinfo_t, heap, varmap, var_escaped);
- gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped);
/* Create the NONLOCAL variable, used to represent the set of nonlocal
memory. */
- nonlocal_tree = create_tmp_var_raw (ptr_type_node, "NONLOCAL");
- var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL");
- insert_vi_for_tree (nonlocal_tree, var_nonlocal);
+ var_nonlocal = new_var_info (NULL_TREE, "NONLOCAL");
+ gcc_assert (var_nonlocal->id == nonlocal_id);
var_nonlocal->is_artificial_var = 1;
var_nonlocal->offset = 0;
var_nonlocal->size = ~0;
var_nonlocal->fullsize = ~0;
var_nonlocal->is_special_var = 1;
- VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal);
/* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc. */
lhs.type = SCALAR;
/* Create the CALLUSED variable, used to represent the set of call-used
memory. */
- callused_tree = create_tmp_var_raw (ptr_type_node, "CALLUSED");
- var_callused = new_var_info (callused_tree, callused_id, "CALLUSED");
- insert_vi_for_tree (callused_tree, var_callused);
+ var_callused = new_var_info (NULL_TREE, "CALLUSED");
+ gcc_assert (var_callused->id == callused_id);
var_callused->is_artificial_var = 1;
var_callused->offset = 0;
var_callused->size = ~0;
var_callused->fullsize = ~0;
var_callused->is_special_var = 0;
- VEC_safe_push (varinfo_t, heap, varmap, var_callused);
/* CALLUSED = *CALLUSED, because call-used is may-deref'd at calls, etc. */
lhs.type = SCALAR;
/* Create the STOREDANYTHING variable, used to represent the set of
variables stored to *ANYTHING. */
- storedanything_tree = create_tmp_var_raw (ptr_type_node, "STOREDANYTHING");
- var_storedanything = new_var_info (storedanything_tree, storedanything_id,
- "STOREDANYTHING");
- insert_vi_for_tree (storedanything_tree, var_storedanything);
+ var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING");
+ gcc_assert (var_storedanything->id == storedanything_id);
var_storedanything->is_artificial_var = 1;
var_storedanything->offset = 0;
var_storedanything->size = ~0;
var_storedanything->fullsize = ~0;
var_storedanything->is_special_var = 0;
- VEC_safe_push (varinfo_t, heap, varmap, var_storedanything);
/* Create the INTEGER variable, used to represent that a variable points
to what an INTEGER "points to". */
- integer_tree = create_tmp_var_raw (ptr_type_node, "INTEGER");
- var_integer = new_var_info (integer_tree, integer_id, "INTEGER");
- insert_vi_for_tree (integer_tree, var_integer);
+ var_integer = new_var_info (NULL_TREE, "INTEGER");
+ gcc_assert (var_integer->id == integer_id);
var_integer->is_artificial_var = 1;
var_integer->size = ~0;
var_integer->fullsize = ~0;
var_integer->offset = 0;
var_integer->next = NULL;
var_integer->is_special_var = 1;
- VEC_safe_push (varinfo_t, heap, varmap, var_integer);
/* INTEGER = ANYTHING, because we don't know where a dereference of
a random integer will point to. */
init_alias_heapvars (void)
{
if (!heapvar_for_stmt)
- heapvar_for_stmt = htab_create_ggc (11, tree_map_hash, tree_map_eq,
+ heapvar_for_stmt = htab_create_ggc (11, tree_map_hash, heapvar_map_eq,
NULL);
}
struct scc_info *si;
basic_block bb;
unsigned i;
+ varinfo_t vi;
timevar_push (TV_TREE_PTA);
/* Compute the points-to sets for ESCAPED and CALLUSED used for
call-clobber analysis. */
- find_what_var_points_to (var_escaped, &cfun->gimple_df->escaped);
- find_what_var_points_to (var_callused, &cfun->gimple_df->callused);
+ find_what_var_points_to (get_varinfo (escaped_id),
+ &cfun->gimple_df->escaped);
+ find_what_var_points_to (get_varinfo (callused_id),
+ &cfun->gimple_df->callused);
/* Make sure the ESCAPED solution (which is used as placeholder in
other solutions) does not reference itself. This simplifies
points-to solution queries. */
cfun->gimple_df->escaped.escaped = 0;
+ /* Mark escaped HEAP variables as global. */
+ for (i = 0; VEC_iterate (varinfo_t, varmap, i, vi); ++i)
+ if (vi->is_heap_var
+ && !vi->is_restrict_var
+ && !vi->is_global_var)
+ DECL_EXTERNAL (vi->decl) = vi->is_global_var
+ = pt_solution_includes (&cfun->gimple_df->escaped, vi->decl);
+
/* Compute the points-to sets for pointer SSA_NAMEs. */
for (i = 0; i < num_ssa_names; ++i)
{