static tree get_tmt_for (tree, struct alias_info *);
static tree get_nmt_for (tree);
static void add_may_alias (tree, tree);
+static void replace_may_alias (tree, size_t, tree);
static struct alias_info *init_alias_info (void);
static void delete_alias_info (struct alias_info *);
static void compute_points_to_and_addr_escape (struct alias_info *);
static void maybe_create_global_var (struct alias_info *ai);
static void group_aliases (struct alias_info *);
static struct ptr_info_def *get_ptr_info (tree t);
+static void set_pt_anything (tree ptr);
+static void set_pt_malloc (tree ptr);
/* Global declarations. */
variable). */
bitmap addressable_vars;
-/* 'true' after aliases have been computed (see compute_may_aliases). This
- is used by get_stmt_operands and its helpers to determine what to do
- when scanning an operand for a variable that may be aliased. If
- may-alias information is still not available, the statement is marked as
- having volatile operands. */
-bool aliases_computed_p;
-
/* When the program has too many call-clobbered variables and call-sites,
this variable is used to represent the clobbering effects of function
calls. In these cases, all the call clobbered variables in the program
/* Deallocate memory used by aliasing data structures. */
delete_alias_info (ai);
-
- /* Indicate that may-alias information is now available. */
- aliases_computed_p = true;
}
struct tree_opt_pass pass_may_alias =
0, /* static_pass_number */
TV_TREE_MAY_ALIAS, /* tv_id */
PROP_cfg | PROP_ssa | PROP_pta, /* properties_required */
- 0, /* properties_provided */
+ PROP_alias, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_rename_vars
- | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
+ | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
+ 0 /* letter */
};
init_alias_info (void)
{
struct alias_info *ai;
+ static bool aliases_computed_p = false;
ai = xcalloc (1, sizeof (struct alias_info));
ai->ssa_names_visited = BITMAP_XMALLOC ();
ai->dereferenced_ptrs_store = BITMAP_XMALLOC ();
ai->dereferenced_ptrs_load = BITMAP_XMALLOC ();
+ /* If aliases have been computed before, clear existing information. */
+ if (aliases_computed_p)
+ {
+ size_t i;
+
+ /* Clear the call-clobbered set. We are going to re-discover
+ call-clobbered variables. */
+ EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
+ {
+ tree var = referenced_var (i);
+
+ /* Variables that are intrinsically call-clobbered (globals,
+ local statics, etc) will not be marked by the aliasing
+ code, so we can't remove them from CALL_CLOBBERED_VARS. */
+ if (!is_call_clobbered (var))
+ bitmap_clear_bit (call_clobbered_vars, var_ann (var)->uid);
+ });
+
+ /* Similarly, clear the set of addressable variables. In this
+ case, we can just clear the set because addressability is
+ only computed here. */
+ bitmap_clear (addressable_vars);
+
+ /* Clear flow-insensitive alias information from each symbol. */
+ for (i = 0; i < num_referenced_vars; i++)
+ {
+ var_ann_t ann = var_ann (referenced_var (i));
+ ann->is_alias_tag = 0;
+ ann->may_aliases = NULL;
+ }
+
+ /* Clear flow-sensitive points-to information from each SSA name. */
+ for (i = 1; i < num_ssa_names; i++)
+ {
+ tree name = ssa_name (i);
+
+ if (!POINTER_TYPE_P (TREE_TYPE (name)))
+ continue;
+
+ if (SSA_NAME_PTR_INFO (name))
+ {
+ struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name);
+
+ /* Clear all the flags but keep the name tag to
+ avoid creating new temporaries unnecessarily. If
+ this pointer is found to point to a subset or
+ superset of its former points-to set, then a new
+ tag will need to be created in create_name_tags. */
+ pi->pt_anything = 0;
+ pi->pt_malloc = 0;
+ pi->value_escapes_p = 0;
+ pi->is_dereferenced = 0;
+ if (pi->pt_vars)
+ bitmap_clear (pi->pt_vars);
+ }
+ }
+ }
+
+ /* Next time, we will need to reset alias information. */
+ aliases_computed_p = true;
+
return ai;
}
if (!bitmap_bit_p (ai->ssa_names_visited, SSA_NAME_VERSION (ptr)))
{
bitmap_set_bit (ai->ssa_names_visited, SSA_NAME_VERSION (ptr));
- walk_use_def_chains (ptr, collect_points_to_info_r, ai);
+ walk_use_def_chains (ptr, collect_points_to_info_r, ai, true);
VARRAY_PUSH_TREE (ai->processed_ptrs, ptr);
}
}
{
basic_block bb;
size_t i;
+ tree op;
+ ssa_op_iter iter;
timevar_push (TV_TREE_PTA);
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{
- use_optype uses;
- def_optype defs;
- v_may_def_optype v_may_defs;
- v_must_def_optype v_must_defs;
- stmt_ann_t ann;
bitmap addr_taken;
tree stmt = bsi_stmt (si);
bool stmt_escapes_p = is_escape_site (stmt, &ai->num_calls_found);
mark_call_clobbered (var);
});
- ann = stmt_ann (stmt);
- uses = USE_OPS (ann);
- for (i = 0; i < NUM_USES (uses); i++)
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
{
- tree op = USE_OP (uses, i);
var_ann_t v_ann = var_ann (SSA_NAME_VAR (op));
struct ptr_info_def *pi;
bool is_store;
collect_points_to_info_for (ai, op);
- pi = SSA_NAME_PTR_INFO (op);
+ pi = SSA_NAME_PTR_INFO (op);
if (ptr_is_dereferenced_by (op, stmt, &is_store))
{
- /* If we found OP to point to a set of variables or
- malloc, then mark it as being dereferenced. In a
- subsequent pass, dereferenced pointers that point
- to a set of variables will be assigned a name tag
- to alias all the variables OP points to. */
- if (pi->pt_malloc || pi->pt_vars)
- pi->is_dereferenced = 1;
+ /* Mark OP as dereferenced. In a subsequent pass,
+ dereferenced pointers that point to a set of
+ variables will be assigned a name tag to alias
+ all the variables OP points to. */
+ pi->is_dereferenced = 1;
/* Keep track of how many time we've dereferenced each
pointer. Again, we don't need to grow
that pointer OP will be dereferenced in a store
operation inside the called function. */
if (get_call_expr_in (stmt))
- bitmap_set_bit (ai->dereferenced_ptrs_store, v_ann->uid);
+ {
+ bitmap_set_bit (ai->dereferenced_ptrs_store, v_ann->uid);
+ pi->is_dereferenced = 1;
+ }
}
}
/* Update reference counter for definitions to any
potentially aliased variable. This is used in the alias
grouping heuristics. */
- defs = DEF_OPS (ann);
- for (i = 0; i < NUM_DEFS (defs); i++)
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
{
- tree op = DEF_OP (defs, i);
tree var = SSA_NAME_VAR (op);
var_ann_t ann = var_ann (var);
bitmap_set_bit (ai->written_vars, ann->uid);
}
/* Mark variables in V_MAY_DEF operands as being written to. */
- v_may_defs = V_MAY_DEF_OPS (ann);
- for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
{
- tree op = V_MAY_DEF_OP (v_may_defs, i);
tree var = SSA_NAME_VAR (op);
var_ann_t ann = var_ann (var);
bitmap_set_bit (ai->written_vars, ann->uid);
}
- /* Mark variables in V_MUST_DEF operands as being written to. */
- v_must_defs = V_MUST_DEF_OPS (ann);
- for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
- {
- tree op = V_MUST_DEF_OP (v_must_defs, i);
- tree var = SSA_NAME_VAR (op);
- var_ann_t ann = var_ann (var);
- bitmap_set_bit (ai->written_vars, ann->uid);
- }
-
/* After promoting variables and computing aliasing we will
need to re-scan most statements. FIXME: Try to minimize the
number of statements re-scanned. It's not really necessary to
tree ptr = VARRAY_TREE (ai->processed_ptrs, i);
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
- /* If we could not determine where PTR was pointing to, clear
- all the other points-to flags. */
- pi = SSA_NAME_PTR_INFO (ptr);
- if (pi->pt_anything)
+ if (pi->pt_anything || !pi->is_dereferenced)
{
- pi->pt_malloc = 0;
- pi->pt_vars = NULL;
- pi->is_dereferenced = 0;
+ /* No name tags for pointers that have not been
+ dereferenced or point to an arbitrary location. */
+ pi->name_mem_tag = NULL_TREE;
+ continue;
}
- if (!pi->is_dereferenced)
- continue;
-
- if (pi->pt_vars)
+ if (pi->pt_vars
+ && bitmap_first_set_bit (pi->pt_vars) >= 0)
{
size_t j;
+ tree old_name_tag = pi->name_mem_tag;
/* If PTR points to a set of variables, check if we don't
have another pointer Q with the same points-to set before
problems if they both had different name tags because
they would have different SSA version numbers (which
would force us to take the name tags in and out of SSA). */
- pi->name_mem_tag = NULL_TREE;
for (j = 0; j < i; j++)
{
tree q = VARRAY_TREE (ai->processed_ptrs, j);
}
}
+ /* If we didn't find a pointer with the same points-to set
+ as PTR, create a new name tag if needed. */
if (pi->name_mem_tag == NULL_TREE)
pi->name_mem_tag = get_nmt_for (ptr);
+
+ /* If the new name tag computed for PTR is different than
+ the old name tag that it used to have, then the old tag
+ needs to be removed from the IL, so we mark it for
+ renaming. */
+ if (old_name_tag && old_name_tag != pi->name_mem_tag)
+ bitmap_set_bit (vars_to_rename, var_ann (old_name_tag)->uid);
}
else if (pi->pt_malloc)
{
/* Only pointers that may point to malloc or other variables
may receive a name tag. If the pointer does not point to
a known spot, we should use type tags. */
- abort ();
+ set_pt_anything (ptr);
+ continue;
}
/* Mark the new name tag for renaming. */
if (pi->value_escapes_p || pi->pt_anything)
{
/* If PTR escapes or may point to anything, then its associated
- memory tags are call-clobbered. */
+ memory tags and pointed-to variables are call-clobbered. */
if (pi->name_mem_tag)
mark_call_clobbered (pi->name_mem_tag);
if (v_ann->type_mem_tag)
mark_call_clobbered (v_ann->type_mem_tag);
- /* If PTR may point to anything, mark call-clobbered all the
- addressables with the same alias set as the type pointed-to by
- PTR. */
- if (pi->pt_anything)
- {
- HOST_WIDE_INT ptr_set;
- ptr_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
- for (j = 0; j < ai->num_addressable_vars; j++)
- {
- struct alias_map_d *alias_map = ai->addressable_vars[j];
- if (alias_map->set == ptr_set)
- mark_call_clobbered (alias_map->var);
- }
- }
-
- /* If PTR's value may escape and PTR is never dereferenced, we
- need to mark all the variables PTR points-to as
- call-clobbered. Note that we only need do this it PTR is
- never dereferenced. If PTR is dereferenced, it will have a
- name memory tag, which will have been marked call-clobbered.
- This will in turn mark the pointed-to variables as
- call-clobbered when we call add_may_alias below. */
- if (pi->value_escapes_p
- && pi->name_mem_tag == NULL_TREE
- && pi->pt_vars)
+ if (pi->pt_vars)
EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j,
mark_call_clobbered (referenced_var (j)));
}
num_tag_refs = VARRAY_UINT (ai->num_references, tag_ann->uid);
num_var_refs = VARRAY_UINT (ai->num_references, v_ann->uid);
+ /* If TAG is call clobbered, so is VAR. */
+ if (is_call_clobbered (tag))
+ mark_call_clobbered (var);
+
/* Add VAR to TAG's may-aliases set. */
add_may_alias (tag, var);
sbitmap_a_and_b (res, tag1_aliases, tag2_aliases);
if (sbitmap_first_set_bit (res) >= 0)
{
+ size_t k;
+
tree tag2 = var_ann (ai->pointers[j]->var)->type_mem_tag;
+ if (!is_call_clobbered (tag1) && is_call_clobbered (tag2))
+ {
+ mark_call_clobbered (tag1);
+ EXECUTE_IF_SET_IN_SBITMAP (tag1_aliases, 0, k,
+ {
+ tree var = referenced_var (k);
+ mark_call_clobbered (var);
+ });
+ }
+ else if (is_call_clobbered (tag1) && !is_call_clobbered (tag2))
+ {
+ mark_call_clobbered (tag2);
+ EXECUTE_IF_SET_IN_SBITMAP (tag2_aliases, 0, k,
+ {
+ tree var = referenced_var (k);
+ mark_call_clobbered (var);
+ });
+ }
+
sbitmap_a_or_b (tag1_aliases, tag1_aliases, tag2_aliases);
/* TAG2 does not need its aliases anymore. */
{
tree alias = VARRAY_TREE (aliases, j);
var_ann_t ann = var_ann (alias);
- if (ann->may_aliases)
+
+ if (ann->mem_tag_kind == NOT_A_TAG && ann->may_aliases)
{
+ tree new_alias;
+
#if defined ENABLE_CHECKING
if (VARRAY_ACTIVE_SIZE (ann->may_aliases) != 1)
abort ();
#endif
- VARRAY_TREE (aliases, j) = VARRAY_TREE (ann->may_aliases, 0);
+ new_alias = VARRAY_TREE (ann->may_aliases, 0);
+ replace_may_alias (name_tag, j, new_alias);
}
}
}
struct alias_map_d *alias_map;
alias_map = xcalloc (1, sizeof (*alias_map));
alias_map->var = var;
-
- if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
- alias_map->set = get_alias_set (TREE_TYPE (TREE_TYPE (var)));
- else
- alias_map->set = get_alias_set (var);
+ alias_map->set = get_alias_set (var);
ai->addressable_vars[ai->num_addressable_vars++] = alias_map;
}
if (POINTER_TYPE_P (TREE_TYPE (var)))
{
- /* Since we don't keep track of volatile variables nor
- variables with hidden uses, assume that these pointers
- are used in indirect store operations. */
- var_ann_t ann = var_ann (var);
- if (TREE_THIS_VOLATILE (var) || ann->has_hidden_use)
- bitmap_set_bit (ai->dereferenced_ptrs_store, ann->uid);
+ /* Since we don't keep track of volatile variables, assume that
+ these pointers are used in indirect store operations. */
+ if (TREE_THIS_VOLATILE (var))
+ bitmap_set_bit (ai->dereferenced_ptrs_store, var_ann (var)->uid);
num_pointers++;
}
if (TREE_ADDRESSABLE (var))
{
if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid)
- && !v_ann->has_hidden_use
&& v_ann->mem_tag_kind == NOT_A_TAG
- && !needs_to_live_in_memory (var))
+ && !is_global_var (var))
{
/* The address of VAR is not needed, remove the
addressable bit, so that it can be optimized as a
/* Add pointer variables that have been dereferenced to the POINTERS
array and create a type memory tag for them. */
- if (POINTER_TYPE_P (TREE_TYPE (var))
- && (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid)
- || bitmap_bit_p (ai->dereferenced_ptrs_load, v_ann->uid)))
+ if (POINTER_TYPE_P (TREE_TYPE (var)))
{
- tree tag = v_ann->type_mem_tag;
- var_ann_t t_ann;
-
- /* If pointer VAR still doesn't have a memory tag associated
- with it, create it now or re-use an existing one. */
- if (tag == NULL_TREE)
- tag = get_tmt_for (var, ai);
- t_ann = var_ann (tag);
-
- /* The type tag will need to be renamed into SSA afterwards.
- Note that we cannot do this inside get_tmt_for because
- aliasing may run multiple times and we only create type
- tags the first time. */
- bitmap_set_bit (vars_to_rename, t_ann->uid);
-
- /* Associate the tag with pointer VAR. */
- v_ann->type_mem_tag = tag;
-
- /* If pointer VAR has been used in a store operation, then its
- memory tag must be marked as written-to. */
- if (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid))
- bitmap_set_bit (ai->written_vars, t_ann->uid);
-
- /* If pointer VAR is a global variable or a PARM_DECL, then its
- memory tag should be considered a global variable. */
- if (TREE_CODE (var) == PARM_DECL || needs_to_live_in_memory (var))
- mark_call_clobbered (tag);
-
- /* All the dereferences of pointer VAR count as references of
- TAG. Since TAG can be associated with several pointers, add
- the dereferences of VAR to the TAG. We may need to grow
- AI->NUM_REFERENCES because we have been adding name and
- type tags. */
- if (t_ann->uid >= VARRAY_SIZE (ai->num_references))
- VARRAY_GROW (ai->num_references, t_ann->uid + 10);
-
- VARRAY_UINT (ai->num_references, t_ann->uid)
- += VARRAY_UINT (ai->num_references, v_ann->uid);
+ if ((bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid)
+ || bitmap_bit_p (ai->dereferenced_ptrs_load, v_ann->uid)))
+ {
+ tree tag;
+ var_ann_t t_ann;
+
+ /* If pointer VAR still doesn't have a memory tag
+ associated with it, create it now or re-use an
+ existing one. */
+ tag = get_tmt_for (var, ai);
+ t_ann = var_ann (tag);
+
+ /* The type tag will need to be renamed into SSA
+ afterwards. Note that we cannot do this inside
+ get_tmt_for because aliasing may run multiple times
+ and we only create type tags the first time. */
+ bitmap_set_bit (vars_to_rename, t_ann->uid);
+
+ /* Associate the tag with pointer VAR. */
+ v_ann->type_mem_tag = tag;
+
+ /* If pointer VAR has been used in a store operation,
+ then its memory tag must be marked as written-to. */
+ if (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid))
+ bitmap_set_bit (ai->written_vars, t_ann->uid);
+
+ /* If pointer VAR is a global variable or a PARM_DECL,
+ then its memory tag should be considered a global
+ variable. */
+ if (TREE_CODE (var) == PARM_DECL || is_global_var (var))
+ mark_call_clobbered (tag);
+
+ /* All the dereferences of pointer VAR count as
+ references of TAG. Since TAG can be associated with
+ several pointers, add the dereferences of VAR to the
+ TAG. We may need to grow AI->NUM_REFERENCES because
+ we have been adding name and type tags. */
+ if (t_ann->uid >= VARRAY_SIZE (ai->num_references))
+ VARRAY_GROW (ai->num_references, t_ann->uid + 10);
+
+ VARRAY_UINT (ai->num_references, t_ann->uid)
+ += VARRAY_UINT (ai->num_references, v_ann->uid);
+ }
+ else
+ {
+ /* The pointer has not been dereferenced. If it had a
+ type memory tag, remove it and mark the old tag for
+ renaming to remove it out of the IL. */
+ var_ann_t ann = var_ann (var);
+ tree tag = ann->type_mem_tag;
+ if (tag)
+ {
+ bitmap_set_bit (vars_to_rename, var_ann (tag)->uid);
+ ann->type_mem_tag = NULL_TREE;
+ }
+ }
}
}
{
size_t i, n_clobbered;
- /* Count all the call-clobbered variables. */
- n_clobbered = 0;
- EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, n_clobbered++);
+ /* No need to create it, if we have one already. */
+ if (global_var == NULL_TREE)
+ {
+ /* Count all the call-clobbered variables. */
+ n_clobbered = 0;
+ EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, n_clobbered++);
- /* Create .GLOBAL_VAR if we have too many call-clobbered variables.
- We also create .GLOBAL_VAR when there no call-clobbered variables
- to prevent code motion transformations from re-arranging function
- calls that may have side effects. For instance,
+ /* Create .GLOBAL_VAR if we have too many call-clobbered
+ variables. We also create .GLOBAL_VAR when there no
+ call-clobbered variables to prevent code motion
+ transformations from re-arranging function calls that may
+ have side effects. For instance,
- foo ()
+ foo ()
{
int a = f ();
g ();
h (a);
}
- There are no call-clobbered variables in foo(), so it would be
- entirely possible for a pass to want to move the call to f()
- after the call to g(). If f() has side effects, that would be
- wrong. Creating .GLOBAL_VAR in this case will insert VDEFs for
- it and prevent such transformations. */
- if (n_clobbered == 0
- || ai->num_calls_found * n_clobbered >= (size_t) GLOBAL_VAR_THRESHOLD)
- create_global_var ();
+ There are no call-clobbered variables in foo(), so it would
+ be entirely possible for a pass to want to move the call to
+ f() after the call to g(). If f() has side effects, that
+ would be wrong. Creating .GLOBAL_VAR in this case will
+ insert VDEFs for it and prevent such transformations. */
+ if (n_clobbered == 0
+ || ai->num_calls_found * n_clobbered >= (size_t) GLOBAL_VAR_THRESHOLD)
+ create_global_var ();
+ }
/* If the function has calls to clobbering functions and .GLOBAL_VAR has
been created, make it an alias for all call-clobbered variables. */
if (alias == VARRAY_TREE (v_ann->may_aliases, i))
return;
- /* If VAR is a call-clobbered variable, so is its new ALIAS. */
- if (is_call_clobbered (var))
- mark_call_clobbered (alias);
-
- /* Likewise. If ALIAS is call-clobbered, so is VAR. */
- else if (is_call_clobbered (alias))
- mark_call_clobbered (var);
-
VARRAY_PUSH_TREE (v_ann->may_aliases, alias);
a_ann->is_alias_tag = 1;
}
+/* Replace alias I in the alias sets of VAR with NEW_ALIAS. */
+
+static void
+replace_may_alias (tree var, size_t i, tree new_alias)
+{
+ var_ann_t v_ann = var_ann (var);
+ VARRAY_TREE (v_ann->may_aliases, i) = new_alias;
+}
+
+
+/* Mark pointer PTR as pointing to an arbitrary memory location. */
+
+static void
+set_pt_anything (tree ptr)
+{
+ struct ptr_info_def *pi = get_ptr_info (ptr);
+
+ pi->pt_anything = 1;
+ pi->pt_malloc = 0;
+
+ /* The pointer used to have a name tag, but we now found it pointing
+ to an arbitrary location. The name tag needs to be renamed and
+ disassociated from PTR. */
+ if (pi->name_mem_tag)
+ {
+ bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
+ pi->name_mem_tag = NULL_TREE;
+ }
+}
+
+
+/* Mark pointer PTR as pointing to a malloc'd memory area. */
+
+static void
+set_pt_malloc (tree ptr)
+{
+ struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+
+ /* If the pointer has already been found to point to arbitrary
+ memory locations, it is unsafe to mark it as pointing to malloc. */
+ if (pi->pt_anything)
+ return;
+
+ pi->pt_malloc = 1;
+}
+
+
/* Given two pointers DEST and ORIG. Merge the points-to information in
ORIG into DEST. AI is as in collect_points_to_info. */
if (orig_pi)
{
- dest_pi->pt_anything |= orig_pi->pt_anything;
+ dest_pi->pt_global_mem |= orig_pi->pt_global_mem;
/* Notice that we never merge PT_MALLOC. This attribute is only
true if the pointer is the result of a malloc() call.
malloc call. Copy propagation before aliasing should cure
this. */
dest_pi->pt_malloc = 0;
- if (orig_pi->pt_malloc)
- dest_pi->pt_anything = 1;
- if (orig_pi->pt_vars)
+ if (orig_pi->pt_malloc || orig_pi->pt_anything)
+ set_pt_anything (dest);
+
+ if (!dest_pi->pt_anything
+ && orig_pi->pt_vars
+ && bitmap_first_set_bit (orig_pi->pt_vars) >= 0)
{
if (dest_pi->pt_vars == NULL)
{
orig_pi->pt_vars);
}
}
+ else
+ set_pt_anything (dest);
}
static void
add_pointed_to_expr (tree ptr, tree value)
{
- struct ptr_info_def *pi;
+ if (TREE_CODE (value) == WITH_SIZE_EXPR)
+ value = TREE_OPERAND (value, 0);
#if defined ENABLE_CHECKING
/* Pointer variables should have been handled by merge_pointed_to_info. */
abort ();
#endif
- pi = get_ptr_info (ptr);
+ get_ptr_info (ptr);
/* If VALUE is the result of a malloc-like call, then the area pointed to
PTR is guaranteed to not alias with anything else. */
if (TREE_CODE (value) == CALL_EXPR
&& (call_expr_flags (value) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
- pi->pt_malloc = 1;
+ set_pt_malloc (ptr);
else
- pi->pt_anything = 1;
+ set_pt_anything (ptr);
if (dump_file)
{
+ struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+
fprintf (dump_file, "Pointer ");
print_generic_expr (dump_file, ptr, dump_flags);
fprintf (dump_file, " points to ");
static void
add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
{
- if (TREE_CODE (value) == ADDR_EXPR)
+ struct ptr_info_def *pi = get_ptr_info (ptr);
+ tree pt_var;
+ size_t uid;
+
+#if defined ENABLE_CHECKING
+ if (TREE_CODE (value) != ADDR_EXPR)
+ abort ();
+#endif
+
+ pt_var = TREE_OPERAND (value, 0);
+ if (TREE_CODE_CLASS (TREE_CODE (pt_var)) == 'r')
+ pt_var = get_base_address (pt_var);
+
+ if (pt_var && SSA_VAR_P (pt_var))
{
- tree pt_var;
- struct ptr_info_def *pi;
- size_t uid;
+ uid = var_ann (pt_var)->uid;
+ bitmap_set_bit (ai->addresses_needed, uid);
- pt_var = TREE_OPERAND (value, 0);
- if (TREE_CODE_CLASS (TREE_CODE (pt_var)) == 'r')
- pt_var = get_base_address (pt_var);
+ if (pi->pt_vars == NULL)
+ pi->pt_vars = BITMAP_GGC_ALLOC ();
+ bitmap_set_bit (pi->pt_vars, uid);
- if (pt_var && SSA_VAR_P (pt_var))
- {
- pi = get_ptr_info (ptr);
- uid = var_ann (pt_var)->uid;
- if (pi->pt_vars == NULL)
- pi->pt_vars = BITMAP_GGC_ALLOC ();
- bitmap_set_bit (pi->pt_vars, uid);
- bitmap_set_bit (ai->addresses_needed, uid);
- }
- else
- add_pointed_to_expr (ptr, value);
+ /* If the variable is a global, mark the pointer as pointing to
+ global memory (which will make its tag a global variable). */
+ if (is_global_var (pt_var))
+ pi->pt_global_mem = 1;
}
- else
- add_pointed_to_expr (ptr, value);
}
tree rhs = TREE_OPERAND (stmt, 1);
STRIP_NOPS (rhs);
- /* Found P_i = CONST. */
- if (is_gimple_min_invariant (rhs))
+ /* Found P_i = ADDR_EXPR */
+ if (TREE_CODE (rhs) == ADDR_EXPR)
add_pointed_to_var (ai, var, rhs);
/* Found P_i = Q_j. */
tree op0 = TREE_OPERAND (rhs, 0);
tree op1 = TREE_OPERAND (rhs, 1);
- if (TREE_CODE (op0) == SSA_NAME
- && POINTER_TYPE_P (TREE_TYPE (op0)))
- merge_pointed_to_info (ai, var, op0);
- else if (TREE_CODE (op1) == SSA_NAME
- && POINTER_TYPE_P (TREE_TYPE (op1)))
- merge_pointed_to_info (ai, var, op1);
- else if (is_gimple_min_invariant (op0))
- add_pointed_to_var (ai, var, op0);
- else if (is_gimple_min_invariant (op1))
- add_pointed_to_var (ai, var, op1);
- else
+ /* Both operands may be of pointer type. FIXME: Shouldn't
+ we just expect PTR + OFFSET always? */
+ if (POINTER_TYPE_P (TREE_TYPE (op0)))
+ {
+ if (TREE_CODE (op0) == SSA_NAME)
+ merge_pointed_to_info (ai, var, op0);
+ else if (TREE_CODE (op0) == ADDR_EXPR)
+ add_pointed_to_var (ai, var, op0);
+ else
+ add_pointed_to_expr (var, op0);
+ }
+
+ if (POINTER_TYPE_P (TREE_TYPE (op1)))
+ {
+ if (TREE_CODE (op1) == SSA_NAME)
+ merge_pointed_to_info (ai, var, op1);
+ else if (TREE_CODE (op1) == ADDR_EXPR)
+ add_pointed_to_var (ai, var, op1);
+ else
+ add_pointed_to_expr (var, op1);
+ }
+
+ /* Neither operand is a pointer? VAR can be pointing
+ anywhere. FIXME: Is this right? If we get here, we
+ found PTR = INT_CST + INT_CST. */
+ if (!POINTER_TYPE_P (TREE_TYPE (op0))
+ && !POINTER_TYPE_P (TREE_TYPE (op1)))
add_pointed_to_expr (var, rhs);
}
else if (TREE_CODE (stmt) == ASM_EXPR)
{
/* Pointers defined by __asm__ statements can point anywhere. */
- get_ptr_info (var)->pt_anything = 1;
+ set_pt_anything (var);
}
else if (IS_EMPTY_STMT (stmt))
{
}
else if (TREE_CODE (stmt) == PHI_NODE)
{
+ /* It STMT is a PHI node, then VAR is one of its arguments. The
+ variable that we are analyzing is the LHS of the PHI node. */
tree lhs = PHI_RESULT (stmt);
- if (is_gimple_min_invariant (var))
+ if (TREE_CODE (var) == ADDR_EXPR)
add_pointed_to_var (ai, lhs, var);
else if (TREE_CODE (var) == SSA_NAME)
merge_pointed_to_info (ai, lhs, var);
+ else if (is_gimple_min_invariant (var))
+ add_pointed_to_expr (lhs, var);
else
abort ();
}
tree tag = pi->name_mem_tag;
if (tag == NULL_TREE)
- {
- tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
+ tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
- /* If PTR is a PARM_DECL, its memory tag should be considered a
- global variable. */
- if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL)
- mark_call_clobbered (tag);
-
- /* Similarly, if PTR points to malloc, then TAG is a global. */
- if (pi->pt_malloc)
- mark_call_clobbered (tag);
- }
+ /* If PTR is a PARM_DECL, it points to a global variable or malloc,
+ then its name tag should be considered a global variable. */
+ if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL
+ || pi->pt_malloc
+ || pi->pt_global_mem)
+ mark_call_clobbered (tag);
return tag;
}
{
struct alias_map_d *alias_map;
- /* Create a new MT.* artificial variable representing the memory
- location pointed-to by PTR. */
- tag = create_memory_tag (tag_type, true);
+ /* If PTR did not have a type tag already, create a new TMT.*
+ artificial variable representing the memory location
+ pointed-to by PTR. */
+ if (var_ann (ptr)->type_mem_tag == NULL_TREE)
+ tag = create_memory_tag (tag_type, true);
+ else
+ tag = var_ann (ptr)->type_mem_tag;
/* Add PTR to the POINTERS array. Note that we are not interested in
PTR's alias set. Instead, we cache the alias set for the memory that
ai->pointers[ai->num_pointers++] = alias_map;
}
+#if defined ENABLE_CHECKING
+ /* Make sure that the type tag has the same alias set as the
+ pointed-to type. */
+ if (tag_set != get_alias_set (tag))
+ abort ();
+#endif
+
+
return tag;
}
size_type_node);
DECL_ARTIFICIAL (global_var) = 1;
TREE_READONLY (global_var) = 0;
- DECL_EXTERNAL (global_var) = 0;
+ DECL_EXTERNAL (global_var) = 1;
TREE_STATIC (global_var) = 1;
TREE_USED (global_var) = 1;
DECL_CONTEXT (global_var) = NULL_TREE;
const char *funcname
= lang_hooks.decl_printable_name (current_function_decl, 2);
- fprintf (file, "\nAlias information for %s\n\n", funcname);
+ fprintf (file, "\nFlow-insensitive alias information for %s\n\n", funcname);
+
+ fprintf (file, "Aliased symbols\n\n");
+ for (i = 0; i < num_referenced_vars; i++)
+ {
+ tree var = referenced_var (i);
+ if (may_be_aliased (var))
+ dump_variable (file, var);
+ }
+ fprintf (file, "\nDereferenced pointers\n\n");
for (i = 0; i < num_referenced_vars; i++)
{
tree var = referenced_var (i);
var_ann_t ann = var_ann (var);
- if (ann->may_aliases
- || ann->type_mem_tag
- || ann->is_alias_tag
- || ann->mem_tag_kind != NOT_A_TAG)
+ if (ann->type_mem_tag)
+ dump_variable (file, var);
+ }
+
+ fprintf (file, "\nType memory tags\n\n");
+ for (i = 0; i < num_referenced_vars; i++)
+ {
+ tree var = referenced_var (i);
+ var_ann_t ann = var_ann (var);
+ if (ann->mem_tag_kind == TYPE_TAG)
+ dump_variable (file, var);
+ }
+
+ fprintf (file, "\n\nFlow-sensitive alias information for %s\n\n", funcname);
+
+ fprintf (file, "SSA_NAME pointers\n\n");
+ for (i = 1; i < num_ssa_names; i++)
+ {
+ tree ptr = ssa_name (i);
+ struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+ if (!SSA_NAME_IN_FREE_LIST (ptr)
+ && pi
+ && pi->name_mem_tag)
+ dump_points_to_info_for (file, ptr);
+ }
+
+ fprintf (file, "\nName memory tags\n\n");
+ for (i = 0; i < num_referenced_vars; i++)
+ {
+ tree var = referenced_var (i);
+ var_ann_t ann = var_ann (var);
+ if (ann->mem_tag_kind == NAME_TAG)
dump_variable (file, var);
}
{
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
- fprintf (file, "Pointer ");
print_generic_expr (file, ptr, dump_flags);
if (pi)
basic_block bb;
block_stmt_iterator si;
size_t i;
+ ssa_op_iter iter;
const char *fname =
lang_hooks.decl_printable_name (current_function_decl, 2);
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{
- stmt_ann_t ann = stmt_ann (bsi_stmt (si));
- def_optype defs = DEF_OPS (ann);
- if (defs)
- for (i = 0; i < NUM_DEFS (defs); i++)
- if (POINTER_TYPE_P (TREE_TYPE (DEF_OP (defs, i))))
- dump_points_to_info_for (file, DEF_OP (defs, i));
+ tree stmt = bsi_stmt (si);
+ tree def;
+ FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+ if (POINTER_TYPE_P (TREE_TYPE (def)))
+ dump_points_to_info_for (file, def);
}
}
{
dump_may_aliases_for (stderr, var);
}
+
+/* Return true if VAR may be aliased. */
+
+bool
+may_be_aliased (tree var)
+{
+ /* Obviously. */
+ if (TREE_ADDRESSABLE (var))
+ return true;
+
+ /* Globally visible variables can have their addresses taken by other
+ translation units. */
+ if (DECL_EXTERNAL (var) || TREE_PUBLIC (var))
+ return true;
+
+ /* Automatic variables can't have their addresses escape any other way.
+ This must be after the check for global variables, as extern declarations
+ do not have TREE_STATIC set. */
+ if (!TREE_STATIC (var))
+ return false;
+
+ /* If we're in unit-at-a-time mode, then we must have seen all occurrences
+ of address-of operators, and so we can trust TREE_ADDRESSABLE. Otherwise
+ we can only be sure the variable isn't addressable if it's local to the
+ current function. */
+ if (flag_unit_at_a_time)
+ return false;
+ if (decl_function_context (var) == current_function_decl)
+ return false;
+
+ return true;
+}
+