The concept of 'escaping' is the same one used in the Java world. When
a pointer or an ADDR_EXPR escapes, it means that it has been exposed
outside of the current function. So, assignment to global variables,
- function arguments and returning a pointer are all escape sites.
+ function arguments and returning a pointer are all escape sites, as are
+ conversions between pointers and integers.
This is where we are currently limited. Since not everything is renamed
into SSA, we lose track of escape properties when a pointer is stashed
0 /* letter */
};
+/* 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. */
{
unsigned i;
bitmap_iterator bi;
+ basic_block bb;
+
+ /* Make sure that every statement has a valid set of operands.
+ If a statement needs to be scanned for operands while we
+ compute aliases, it may get erroneous operands because all
+ the alias relations are not built at that point.
+ FIXME: This code will become obsolete when operands are not
+ lazily updated. */
+ FOR_EACH_BB (bb)
+ {
+ block_stmt_iterator si;
+ for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+ get_stmt_operands (bsi_stmt (si));
+ }
/* Clear the call-clobbered set. We are going to re-discover
call-clobbered variables. */
if (stmt_escapes_p)
block_ann->has_escape_site = 1;
- /* Special case for silly ADDR_EXPR tricks
- (gcc.c-torture/unsorted/pass.c). If this statement is an
- assignment to a non-pointer variable and the RHS takes the
- address of a variable, assume that the variable on the RHS is
- call-clobbered. We could add the LHS to the list of
- "pointers" and follow it to see if it really escapes, but it's
- not worth the pain. */
- if (addr_taken
- && TREE_CODE (stmt) == MODIFY_EXPR
- && !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 0))))
- EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
- {
- tree var = referenced_var (i);
- mark_call_clobbered (var);
- }
-
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
{
var_ann_t v_ann = var_ann (SSA_NAME_VAR (op));
compute_flow_insensitive_aliasing (struct alias_info *ai)
{
size_t i;
- sbitmap res;
/* Initialize counter for the total number of virtual operands that
aliasing will introduce. When AI->TOTAL_ALIAS_VOPS goes beyond the
To avoid this problem, we do a final traversal of AI->POINTERS
looking for pairs of pointers that have no aliased symbols in
common and yet have conflicting alias set numbers. */
- res = sbitmap_alloc (num_referenced_vars);
-
for (i = 0; i < ai->num_pointers; i++)
{
size_t j;
/* The two pointers may alias each other. If they already have
symbols in common, do nothing. */
- sbitmap_a_and_b (res, may_aliases1, may_aliases2);
- if (sbitmap_first_set_bit (res) >= 0)
+ if (sbitmap_any_common_bits (may_aliases1, may_aliases2))
continue;
if (sbitmap_first_set_bit (may_aliases2) >= 0)
}
}
- sbitmap_free (res);
-
if (dump_file)
fprintf (dump_file, "%s: Total number of aliased vops: %ld\n",
get_name (current_function_decl),
group_aliases (struct alias_info *ai)
{
size_t i;
- sbitmap res;
/* Sort the POINTERS array in descending order of contributed
virtual operands. */
qsort (ai->pointers, ai->num_pointers, sizeof (struct alias_map_d *),
total_alias_vops_cmp);
- res = sbitmap_alloc (num_referenced_vars);
-
/* For every pointer in AI->POINTERS, reverse the roles of its tag
and the tag's may-aliases set. */
for (i = 0; i < ai->num_pointers; i++)
{
sbitmap tag2_aliases = ai->pointers[j]->may_aliases;
- sbitmap_a_and_b (res, tag1_aliases, tag2_aliases);
- if (sbitmap_first_set_bit (res) >= 0)
+ if (sbitmap_any_common_bits (tag1_aliases, tag2_aliases))
{
tree tag2 = var_ann (ai->pointers[j]->var)->type_mem_tag;
}
}
- sbitmap_free (res);
-
if (dump_file)
fprintf (dump_file,
"%s: Total number of aliased vops after grouping: %ld%s\n",
if (lhs == NULL_TREE)
return true;
+ /* If the RHS is a conversion between a pointer and an integer, the
+ pointer escapes since we can't track the integer. */
+ if ((TREE_CODE (TREE_OPERAND (stmt, 1)) == NOP_EXPR
+ || TREE_CODE (TREE_OPERAND (stmt, 1)) == CONVERT_EXPR
+ || TREE_CODE (TREE_OPERAND (stmt, 1)) == VIEW_CONVERT_EXPR)
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND
+ (TREE_OPERAND (stmt, 1), 0)))
+ && !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 1))))
+ return true;
+
/* If the LHS is an SSA name, it can't possibly represent a non-local
memory store. */
if (TREE_CODE (lhs) == SSA_NAME)
create_global_var (void)
{
global_var = build_decl (VAR_DECL, get_identifier (".GLOBAL_VAR"),
- size_type_node);
+ void_type_node);
DECL_ARTIFICIAL (global_var) = 1;
TREE_READONLY (global_var) = 0;
DECL_EXTERNAL (global_var) = 1;