aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-alias.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-alias.c')
-rw-r--r--gcc/tree-ssa-alias.c168
1 files changed, 76 insertions, 92 deletions
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 6a95bcd2a11..1adcd833e91 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -43,6 +43,8 @@ Boston, MA 02111-1307, USA. */
#include "convert.h"
#include "params.h"
+/* 'true' after aliases have been computed (see compute_may_aliases). */
+bool aliases_computed_p;
/* Structure to map a variable to its alias set and keep track of the
virtual operands that will be needed to represent it. */
@@ -94,6 +96,9 @@ struct alias_info
/* Number of function calls found in the program. */
size_t num_calls_found;
+ /* Number of const/pure function calls found in the program. */
+ size_t num_pure_const_calls_found;
+
/* Array of counters to keep track of how many times each pointer has
been dereferenced in the program. This is used by the alias grouping
heuristic in compute_flow_insensitive_aliasing. */
@@ -145,7 +150,7 @@ static void compute_points_to_and_addr_escape (struct alias_info *);
static void compute_flow_sensitive_aliasing (struct alias_info *);
static void setup_pointers_and_addressables (struct alias_info *);
static bool collect_points_to_info_r (tree, tree, void *);
-static bool is_escape_site (tree, size_t *);
+static bool is_escape_site (tree, struct alias_info *);
static void add_pointed_to_var (struct alias_info *, tree, tree);
static void create_global_var (void);
static void collect_points_to_info_for (struct alias_info *, tree);
@@ -441,7 +446,7 @@ count_uses_and_derefs (tree ptr, tree stmt, unsigned *num_uses_p,
rhs = stmt;
}
- if (lhs && EXPR_P (lhs))
+ if (lhs && (TREE_CODE (lhs) == TREE_LIST || EXPR_P (lhs)))
{
struct count_ptr_d count;
count.ptr = ptr;
@@ -451,7 +456,7 @@ count_uses_and_derefs (tree ptr, tree stmt, unsigned *num_uses_p,
*num_derefs_p = count.count;
}
- if (rhs && EXPR_P (rhs))
+ if (rhs && (TREE_CODE (rhs) == TREE_LIST || EXPR_P (rhs)))
{
struct count_ptr_d count;
count.ptr = ptr;
@@ -465,80 +470,22 @@ count_uses_and_derefs (tree ptr, tree stmt, unsigned *num_uses_p,
}
-/* Count the number of calls in the function and conditionally
- create GLOBAL_VAR. This is performed before translation
- into SSA (and thus before alias analysis) to avoid compile time
- and memory utilization explosions in functions with many
- of calls and call clobbered variables. */
-
-static void
-count_calls_and_maybe_create_global_var (void)
-{
- struct alias_info ai;
- basic_block bb;
- bool temp;
-
- memset (&ai, 0, sizeof (struct alias_info));
-
- /* First count the number of calls in the IL. */
- FOR_EACH_BB (bb)
- {
- block_stmt_iterator si;
-
- for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
- {
- tree stmt = bsi_stmt (si);
-
- if (get_call_expr_in (stmt) != NULL_TREE)
- ai.num_calls_found++;
- }
- }
-
- /* If there are no call clobbered variables, then maybe_create_global_var
- will always create a GLOBAL_VAR. At this point we do not want that
- behavior. So we turn on one bit in CALL_CLOBBERED_VARs, call
- maybe_create_global_var, then reset the bit to its original state. */
- temp = bitmap_bit_p (call_clobbered_vars, 0);
- bitmap_set_bit (call_clobbered_vars, 0);
- maybe_create_global_var (&ai);
- if (!temp)
- bitmap_clear_bit (call_clobbered_vars, 0);
-}
-
-struct tree_opt_pass pass_maybe_create_global_var =
-{
- "maybe_create_global_var", /* name */
- NULL, /* gate */
- count_calls_and_maybe_create_global_var, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_MAY_ALIAS, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
-};
-
/* Initialize the data structures used for alias analysis. */
static struct alias_info *
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 = sbitmap_alloc (num_ssa_names);
sbitmap_zero (ai->ssa_names_visited);
VARRAY_TREE_INIT (ai->processed_ptrs, 50, "processed_ptrs");
- ai->addresses_needed = BITMAP_XMALLOC ();
+ ai->addresses_needed = BITMAP_ALLOC (NULL);
VARRAY_UINT_INIT (ai->num_references, num_referenced_vars, "num_references");
- ai->written_vars = BITMAP_XMALLOC ();
- ai->dereferenced_ptrs_store = BITMAP_XMALLOC ();
- ai->dereferenced_ptrs_load = BITMAP_XMALLOC ();
+ ai->written_vars = BITMAP_ALLOC (NULL);
+ ai->dereferenced_ptrs_store = BITMAP_ALLOC (NULL);
+ ai->dereferenced_ptrs_load = BITMAP_ALLOC (NULL);
/* If aliases have been computed before, clear existing information. */
if (aliases_computed_p)
@@ -626,7 +573,7 @@ delete_alias_info (struct alias_info *ai)
sbitmap_free (ai->ssa_names_visited);
ai->processed_ptrs = NULL;
- BITMAP_XFREE (ai->addresses_needed);
+ BITMAP_FREE (ai->addresses_needed);
for (i = 0; i < ai->num_addressable_vars; i++)
{
@@ -643,9 +590,9 @@ delete_alias_info (struct alias_info *ai)
free (ai->pointers);
ai->num_references = NULL;
- BITMAP_XFREE (ai->written_vars);
- BITMAP_XFREE (ai->dereferenced_ptrs_store);
- BITMAP_XFREE (ai->dereferenced_ptrs_load);
+ BITMAP_FREE (ai->written_vars);
+ BITMAP_FREE (ai->dereferenced_ptrs_store);
+ BITMAP_FREE (ai->dereferenced_ptrs_load);
free (ai);
}
@@ -695,7 +642,7 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
{
bitmap addr_taken;
tree stmt = bsi_stmt (si);
- bool stmt_escapes_p = is_escape_site (stmt, &ai->num_calls_found);
+ bool stmt_escapes_p = is_escape_site (stmt, ai);
bitmap_iterator bi;
/* Mark all the variables whose address are taken by the
@@ -1116,6 +1063,7 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
/* Since TAG2 does not have any aliases of its own, add
TAG2 itself to the alias set of TAG1. */
add_may_alias (tag1, tag2);
+ SET_BIT (may_aliases1, var_ann (tag2)->uid);
}
}
}
@@ -1585,22 +1533,56 @@ maybe_create_global_var (struct alias_info *ai)
n_clobbered++;
}
- if (ai->num_calls_found * n_clobbered >= (size_t) GLOBAL_VAR_THRESHOLD)
+ /* If the number of virtual operands that would be needed to
+ model all the call-clobbered variables is larger than
+ GLOBAL_VAR_THRESHOLD, create .GLOBAL_VAR.
+
+ Also create .GLOBAL_VAR if there are no call-clobbered
+ variables and the program contains a mixture of pure/const
+ and regular function calls. This is to avoid the problem
+ described in PR 20115:
+
+ int X;
+ int func_pure (void) { return X; }
+ int func_non_pure (int a) { X += a; }
+ int foo ()
+ {
+ int a = func_pure ();
+ func_non_pure (a);
+ a = func_pure ();
+ return a;
+ }
+
+ Since foo() has no call-clobbered variables, there is
+ no relationship between the calls to func_pure and
+ func_non_pure. Since func_pure has no side-effects, value
+ numbering optimizations elide the second call to func_pure.
+ So, if we have some pure/const and some regular calls in the
+ program we create .GLOBAL_VAR to avoid missing these
+ relations. */
+ if (ai->num_calls_found * n_clobbered >= (size_t) GLOBAL_VAR_THRESHOLD
+ || (n_clobbered == 0
+ && ai->num_calls_found > 0
+ && ai->num_pure_const_calls_found > 0
+ && ai->num_calls_found > ai->num_pure_const_calls_found))
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 (global_var)
- EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
- {
- tree var = referenced_var (i);
- if (var != global_var)
- {
- add_may_alias (var, global_var);
- bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
- }
- }
+ /* Mark all call-clobbered symbols for renaming. Since the initial
+ rewrite into SSA ignored all call sites, we may need to rename
+ .GLOBAL_VAR and the call-clobbered variables. */
+ EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
+ {
+ tree var = referenced_var (i);
+
+ /* If the function has calls to clobbering functions and
+ .GLOBAL_VAR has been created, make it an alias for all
+ call-clobbered variables. */
+ if (global_var && var != global_var)
+ add_may_alias (var, global_var);
+
+ bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
+ }
}
@@ -1761,8 +1743,8 @@ set_pt_malloc (tree ptr)
/* Given two different pointers DEST and ORIG. Merge the points-to
- information in ORIG into DEST. AI is as in
- collect_points_to_info. */
+ information in ORIG into DEST. AI contains all the alias
+ information collected up to this point. */
static void
merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
@@ -1907,7 +1889,7 @@ add_pointed_to_expr (struct alias_info *ai, tree ptr, tree expr)
/* If VALUE is of the form &DECL, add DECL to the set of variables
pointed-to by PTR. Otherwise, add VALUE as a pointed-to expression by
- PTR. AI is as in collect_points_to_info. */
+ PTR. AI points to the collected alias information. */
static void
add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
@@ -2039,16 +2021,18 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
3- STMT is an assignment to a non-local variable, or
4- STMT is a return statement.
- If NUM_CALLS_P is not NULL, the counter is incremented if STMT contains
- a function call. */
+ AI points to the alias information collected so far. */
static bool
-is_escape_site (tree stmt, size_t *num_calls_p)
+is_escape_site (tree stmt, struct alias_info *ai)
{
- if (get_call_expr_in (stmt) != NULL_TREE)
+ tree call = get_call_expr_in (stmt);
+ if (call != NULL_TREE)
{
- if (num_calls_p)
- (*num_calls_p)++;
+ ai->num_calls_found++;
+
+ if (!TREE_SIDE_EFFECTS (call))
+ ai->num_pure_const_calls_found++;
return true;
}