This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[improved-aliasing]: Better clobbering and clobber stats
- From: Daniel Berlin <dberlin at dberlin dot org>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 29 Sep 2005 13:02:19 -0400
- Subject: [improved-aliasing]: Better clobbering and clobber stats
This improves our local clobbering by teaching it that things that
escape through calls can't escape through calls that don't have writable
pointer arguments.
Before someone says we can do better, this was more or less an exercise
in seeing how much we could improve our local clobbering without
interprocedural and at least call-specific info.
I also added the use of the static read info to remove readonly vuses
when possible in add_call_read_ops.
The stats show that the unescapable stuff sometimes helps, sometimes
doesn't.
The places where it doesn't help, at least for gcc, are places it could
if we attributed our functions or gave it the whole program.
The most often cause of failing the "okay to remove from clobber set"
test was due to three functions:
warning, error, pedwarn
And if you teach it to look through them, you get
fputc, fputs, printf
then fprintf.
At least for gcc.
Anyway, next i'll work on both inteprocedural aliasing, and adding some
attributes + builtins or whatever to teach it these things don't call
back
Bootstrapped and regtested on i686-pc-linux-gnu and powerpc-linux-gnu
Committed to improved-aliasing-branch.
--Dan
2005-09-29 Daniel Berlin <dberlin@dberlin.org>
* ipa-callees.c (scan_for_indirect_calls): New function.
(argument_readonly_nonpointer): New function
(has_nonreadonly_pointer_arguments): Ditto.
(callees_execute): Scan for indirect calls.
Cleanup a small amount.
* tree-flow-inline.h: (mark_call_clobbered): Remove used of call
call clobbered cache.
(mark_non_addressable): Ditto.
(clear_call_clobbered): Ditto.
* tree-flow.h (struct_function_ann_d): Add has_pointer_arguments.
* tree-ssa-alias.c: Fixup function names missed during global replace.
(init_transitive_clobber_worklist): Pass in reason worklist.
Push reason onto second worklist.
(add_to_worklist): Ditto.
(mark_aliases_call_clobbered): Ditto.
(compute_call_clobbered): Ditto.
(set_initial_properties): Handle subvars properly.
* tree-ssa-operands.c (clobber_stats) :New.
(init_ssa_operands): Initialize clobber stats.
(fini_ssa_operands): Print out stats if requested. Remove call
clobbered caches
(add_call_read_ops): Add callee argument. Use escapable
and static read info to avoid clobbers.
Remove cache.
(callee_okay_for_noescape): New function.
(add_call_clobber_ops): Use it.
Use nonescaping info.
* tree-ssa-operands.h: Remove call clobbered cache.
Index: ipa-callees.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ipa-callees.c,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 ipa-callees.c
--- ipa-callees.c 27 Sep 2005 01:33:58 -0000 1.1.2.2
+++ ipa-callees.c 29 Sep 2005 00:53:06 -0000
@@ -67,11 +67,95 @@ debug_bitmap_of_cgraph_nodes (bitmap a)
print_bitmap_of_cgraph_nodes (stderr, a);
}
+/* Mark UID in IDS if FN contains indirect function calls. */
+
+static void
+scan_for_indirect_calls (tree fn, unsigned int uid, bitmap ids)
+{
+ struct function *cfun = DECL_STRUCT_FUNCTION (fn);
+ basic_block bb;
+
+ /* The pop happens in the caller due to the possible early return. */
+ push_cfun (cfun);
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ block_stmt_iterator bsi;
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ tree possible_call = NULL;
+ if (TREE_CODE (stmt) == RETURN_EXPR)
+ stmt = TREE_OPERAND (stmt, 0);
+
+ if (!stmt)
+ continue;
+
+ if (TREE_CODE (stmt) == MODIFY_EXPR
+ || TREE_CODE (stmt) == RETURN_EXPR)
+ possible_call = TREE_OPERAND (stmt, 1);
+ else if (TREE_CODE (stmt) == CALL_EXPR)
+ possible_call = stmt;
+
+ if (possible_call && TREE_CODE (possible_call) == CALL_EXPR)
+ if (!get_callee_fndecl (possible_call))
+ {
+ bitmap_set_bit (ids, uid);
+ return;
+ }
+ }
+ }
+
+}
+
+/* Return true if PARG, a pointer type, points to a readonly
+ non-pointer type. */
+
+static bool
+argument_readonly_nonpointer (tree parg)
+{
+ if (POINTER_TYPE_P (TREE_TYPE (parg)))
+ return false;
+ if (!TYPE_READONLY (TREE_TYPE (parg)))
+ return false;
+ return true;
+}
+
+/* Return true if fn has non-readonly pointer arguments. */
+
+static bool
+has_nonreadonly_pointer_arguments (tree fn)
+{
+ tree arg;
+
+
+ for (arg = DECL_ARGUMENTS (fn);
+ arg;
+ arg = TREE_CHAIN (arg))
+ {
+ if (POINTER_TYPE_P (TREE_TYPE (arg))
+ && !argument_readonly_nonpointer (arg))
+ return true;
+ }
+
+ for (arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ arg && arg != void_list_node;
+ arg = TREE_CHAIN (arg))
+ {
+ if (POINTER_TYPE_P (TREE_VALUE (arg))
+ && !argument_readonly_nonpointer (TREE_VALUE (arg)))
+ return true;
+ }
+
+ return false;
+}
+
static void
callees_execute (void)
{
struct cgraph_node *node;
bitmap global_and_address_taken = BITMAP_ALLOC (NULL);
+ bitmap contains_indirect_call = BITMAP_ALLOC (NULL);
struct cgraph_node **postorder = xcalloc (cgraph_n_nodes,
sizeof (struct cgraph_node *));
bool changed = true;
@@ -83,16 +167,29 @@ callees_execute (void)
/* Go through the cgraph nodes, record which are global or address
taken, and make a first pass at the callees. */
for (node = cgraph_nodes; node; node = node->next)
- if (node->analyzed && cgraph_is_master_clone (node))
{
tree decl = node->decl;
enum availability avail = cgraph_function_body_availability (node);
- function_ann_t ann;
+ function_ann_t ann = get_function_ann (decl);
struct cgraph_edge *e;
+ ann->has_pointer_arguments = has_nonreadonly_pointer_arguments (decl);
+ if (!node->analyzed)
+ continue;
+ /* If this is global, addressable or no body is available,
+ mark it global/address taken. Otherwise, scan for indirect
+ calls. */
+
if (TREE_ADDRESSABLE (decl) || avail == AVAIL_NOT_AVAILABLE)
bitmap_set_bit (global_and_address_taken, node->uid);
- ann = get_function_ann (decl);
+ else if (avail != AVAIL_NOT_AVAILABLE)
+ {
+
+ scan_for_indirect_calls (node->decl, node->uid,
+ contains_indirect_call);
+ pop_cfun ();
+ }
+
ann->callees = BITMAP_ALLOC (&callee_obstack);
for (e = node->callees; e; e = e->next_callee)
{
@@ -104,7 +201,7 @@ callees_execute (void)
order_pos = cgraph_postorder (postorder);
/* Iterate in reverse postorder until we are done with the
- closure.
+ closure.
XXX: Use the SCC stuff to make this faster. */
while (changed)
{
@@ -112,25 +209,31 @@ callees_execute (void)
for (i = order_pos - 1; i >= 0; i--)
{
struct cgraph_edge *e;
+ function_ann_t ann;
node = postorder[i];
+ ann = function_ann (node->decl);
+
+ if (!node->analyzed)
+ continue;
+
+ if (bitmap_bit_p (contains_indirect_call, node->uid))
+ changed |= bitmap_ior_into (ann->callees, global_and_address_taken);
for (e = node->callees; e; e = e->next_callee)
{
struct cgraph_node *cnode = e->callee;
- function_ann_t ann;
- if (!cnode->analyzed)
- continue;
- ann = function_ann (node->decl);
-
- if (cgraph_function_body_availability (cnode) == AVAIL_NOT_AVAILABLE)
+ enum availability avail = cgraph_function_body_availability (cnode);
+ if (avail == AVAIL_NOT_AVAILABLE)
changed |= bitmap_ior_into (ann->callees,
global_and_address_taken);
- changed |= bitmap_ior_into (ann->callees,
- function_ann (cnode->decl)->callees);
+ else
+ changed |= bitmap_ior_into (ann->callees,
+ function_ann (cnode->decl)->callees);
}
}
}
BITMAP_FREE (global_and_address_taken);
+ BITMAP_FREE (contains_indirect_call);
free (postorder);
}
Index: tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow-inline.h,v
retrieving revision 2.56.2.6
diff -u -p -r2.56.2.6 tree-flow-inline.h
--- tree-flow-inline.h 28 Sep 2005 15:43:30 -0000 2.56.2.6
+++ tree-flow-inline.h 29 Sep 2005 00:53:07 -0000
@@ -868,8 +868,6 @@ mark_call_clobbered (tree var, unsigned
{
var_ann (var)->escape_mask |= escape_type;
bitmap_set_bit (call_clobbered_vars, DECL_UID (var));
- ssa_call_clobbered_cache_valid = false;
- ssa_ro_call_cache_valid = false;
}
/* Clear the call-clobbered attribute from variable VAR. */
@@ -881,8 +879,6 @@ clear_call_clobbered (tree var)
if (TREE_CODE (var) != STRUCT_FIELD_TAG && MTAG_P (var))
MTAG_GLOBAL (var) = 0;
bitmap_clear_bit (call_clobbered_vars, DECL_UID (var));
- ssa_call_clobbered_cache_valid = false;
- ssa_ro_call_cache_valid = false;
}
/* Mark variable VAR as being non-addressable. */
@@ -891,8 +887,6 @@ mark_non_addressable (tree var)
{
bitmap_clear_bit (call_clobbered_vars, DECL_UID (var));
TREE_ADDRESSABLE (var) = 0;
- ssa_call_clobbered_cache_valid = false;
- ssa_ro_call_cache_valid = false;
}
/* Return the common annotation for T. Return NULL if the annotation
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 2.132.2.6
diff -u -p -r2.132.2.6 tree-flow.h
--- tree-flow.h 28 Sep 2005 15:43:32 -0000 2.132.2.6
+++ tree-flow.h 29 Sep 2005 00:53:07 -0000
@@ -229,11 +229,18 @@ struct function_ann_d GTY(())
{
struct tree_ann_common_d common;
+ /* True if the function in question has an argument that is a
+ pointer. */
+ unsigned int has_pointer_arguments:1;
+
/* Pointer to the structure that contains the sets of global
variables modified by function calls. This field is only used
for FUNCTION_DECLs. */
ipa_reference_vars_info_t GTY ((skip)) reference_vars_info;
+ /* This bitmap contains the cgraph node ids of all possible callees
+ of this function, including those called by callees (IE it is
+ post-transitive closure). */
bitmap GTY((skip)) callees;
};
Index: tree-ssa-alias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-alias.c,v
retrieving revision 2.109.4.9
diff -u -p -r2.109.4.9 tree-ssa-alias.c
--- tree-ssa-alias.c 27 Sep 2005 01:33:59 -0000 2.109.4.9
+++ tree-ssa-alias.c 29 Sep 2005 00:53:07 -0000
@@ -135,6 +135,9 @@ bitmap addressable_vars;
having to keep track of too many V_MAY_DEF expressions at call sites. */
tree global_var;
+DEF_VEC_I(int);
+DEF_VEC_ALLOC_I(int,heap);
+
/* Return true if TAG can touch global memory. */
static bool
tag_marked_global (tree tag)
@@ -145,7 +148,7 @@ tag_marked_global (tree tag)
/* Mark TAG, an alias tag, as possibly touching global memory. */
static void
-mark_MTAG_GLOBAL (tree tag)
+mark_tag_global (tree tag)
{
gcc_assert (MTAG_P (tag));
MTAG_GLOBAL (tag) = 1;
@@ -163,10 +166,12 @@ sort_tags_by_id (const void *pa, const v
}
/* Initialize WORKLIST to contain those memory tags that are marked call
- clobbered. */
+ clobbered. Initialized WORKLIST2 to contain the reasons these
+ memory tags escaped. */
static void
-init_transitive_clobber_worklist (VEC (tree, heap) **worklist)
+init_transitive_clobber_worklist (VEC (tree, heap) **worklist,
+ VEC (int, heap) **worklist2)
{
referenced_var_iterator rvi;
tree curr;
@@ -174,25 +179,35 @@ init_transitive_clobber_worklist (VEC (t
FOR_EACH_REFERENCED_VAR (curr, rvi)
{
if (MTAG_P (curr) && is_call_clobbered (curr))
- VEC_safe_push (tree, heap, *worklist, curr);
+ {
+ VEC_safe_push (tree, heap, *worklist, curr);
+ VEC_safe_push (int, heap, *worklist2, var_ann (curr)->escape_mask);
+ }
}
}
-/* Add ALIAS to WORKLIST if ALIAS is not already marked call
- clobbered, and is a memory tag. */
+/* Add ALIAS to WORKLIST (and the reason for escaping REASON to WORKLIST2) if
+ ALIAS is not already marked call clobbered, and is a memory
+ tag. */
static void
-add_to_worklist (tree alias, VEC (tree, heap) **worklist)
+add_to_worklist (tree alias, VEC (tree, heap) **worklist,
+ VEC (int, heap) **worklist2,
+ int reason)
{
if (MTAG_P (alias) && !is_call_clobbered (alias))
- VEC_safe_push (tree, heap, *worklist, alias);
+ {
+ VEC_safe_push (tree, heap, *worklist, alias);
+ VEC_safe_push (int, heap, *worklist2, reason);
+ }
}
/* Mark aliases of TAG as call clobbered, and place any tags on the
alias list that were not already call clobbered on WORKLIST. */
static void
-mark_aliases_call_clobbered (tree tag, VEC (tree, heap) **worklist)
+mark_aliases_call_clobbered (tree tag, VEC (tree, heap) **worklist,
+ VEC (int, heap) **worklist2)
{
unsigned int i;
varray_type ma;
@@ -203,12 +218,13 @@ mark_aliases_call_clobbered (tree tag, V
ma = may_aliases (tag);
if (!ma)
return;
+
for (i = 0; i < VARRAY_ACTIVE_SIZE (ma); i++)
{
tree entry = VARRAY_TREE (ma, i);
if (!unmodifiable_var_p (entry))
{
- add_to_worklist (entry, worklist);
+ add_to_worklist (entry, worklist, worklist2, ta->escape_mask);
mark_call_clobbered (entry, ta->escape_mask);
}
}
@@ -285,7 +301,7 @@ compute_tag_properties (void)
/* Global vars cause the tag to be marked global. */
if (is_global_var (entry) && !tag_marked_global (tag))
{
- mark_MTAG_GLOBAL (tag);
+ mark_tag_global (tag);
changed = true;
}
}
@@ -308,7 +324,9 @@ set_initial_properties (struct alias_inf
FOR_EACH_REFERENCED_VAR (var, rvi)
{
- if (is_global_var (var) && !var_can_have_subvars (var))
+ if (is_global_var (var)
+ && (!var_can_have_subvars (var)
+ || get_subvars_for_var (var) == NULL))
if (!unmodifiable_var_p (var))
mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
}
@@ -346,9 +364,9 @@ set_initial_properties (struct alias_inf
mark_call_clobbered (v_ann->type_mem_tag, v_ann->escape_mask);
if ((pi->pt_global_mem || pi->pt_anything) && pi->name_mem_tag)
- mark_MTAG_GLOBAL (pi->name_mem_tag);
+ mark_tag_global (pi->name_mem_tag);
if ((pi->pt_global_mem || pi->pt_anything) && v_ann->type_mem_tag)
- mark_MTAG_GLOBAL (v_ann->type_mem_tag);
+ mark_tag_global (v_ann->type_mem_tag);
}
}
/* Compute which variables need to be marked call clobbered because
@@ -359,16 +377,20 @@ static void
compute_call_clobbered (struct alias_info *ai)
{
VEC (tree, heap) *worklist = NULL;
-
+ VEC(int,heap) *worklist2 = NULL;
+
set_initial_properties (ai);
- init_transitive_clobber_worklist (&worklist);
+ init_transitive_clobber_worklist (&worklist, &worklist2);
while (VEC_length (tree, worklist) != 0)
{
tree curr = VEC_pop (tree, worklist);
- mark_call_clobbered (curr, ESCAPE_TRANSITIVE);
- mark_aliases_call_clobbered (curr, &worklist);
+ int reason = VEC_pop (int, worklist2);
+
+ mark_call_clobbered (curr, reason);
+ mark_aliases_call_clobbered (curr, &worklist, &worklist2);
}
VEC_free (tree, heap, worklist);
+ VEC_free (int, heap, worklist2);
compute_tag_properties ();
}
Index: tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 2.100.4.4
diff -u -p -r2.100.4.4 tree-ssa-operands.c
--- tree-ssa-operands.c 26 Sep 2005 17:05:48 -0000 2.100.4.4
+++ tree-ssa-operands.c 29 Sep 2005 00:53:08 -0000
@@ -132,17 +132,8 @@ static GTY (()) struct opbuild_list_d bu
/* Array for building all the v_must_def operands. */
static GTY (()) struct opbuild_list_d build_v_must_defs;
-/* True if the operands for call clobbered vars are cached and valid. */
-bool ssa_call_clobbered_cache_valid;
-bool ssa_ro_call_cache_valid;
/* These arrays are the cached operand vectors for call clobbered calls. */
-static VEC(tree,heap) *clobbered_v_may_defs;
-static VEC(tree,heap) *clobbered_vuses;
-static VEC(tree,heap) *ro_call_vuses;
-static bool clobbered_aliased_loads;
-static bool clobbered_aliased_stores;
-static bool ro_call_aliased_loads;
static bool ops_active = false;
static GTY (()) struct ssa_operand_memory_d *operand_memory = NULL;
@@ -158,7 +149,7 @@ static inline void append_use (tree *);
static void append_v_may_def (tree);
static void append_v_must_def (tree);
static void add_call_clobber_ops (tree, tree);
-static void add_call_read_ops (tree);
+static void add_call_read_ops (tree, tree);
static void add_stmt_operand (tree *, stmt_ann_t, int);
static void build_ssa_operands (tree stmt);
@@ -394,6 +385,17 @@ ssa_operands_active (void)
}
+static struct
+{
+ unsigned int clobbered_vars;
+ unsigned int static_write_clobbers_avoided;
+ unsigned int static_read_clobbers_avoided;
+ unsigned int unescapable_clobbers_avoided;
+ unsigned int readonly_clobbers;
+ unsigned int static_readonly_clobbers_avoided;
+ unsigned int unescapable_readonly_clobbers_avoided;
+} clobber_stats;
+
/* Initialize the operand cache routines. */
void
@@ -407,6 +409,8 @@ init_ssa_operands (void)
gcc_assert (operand_memory == NULL);
operand_memory_index = SSA_OPERAND_MEMORY_SIZE;
ops_active = true;
+ memset (&clobber_stats, 0, sizeof (clobber_stats));
+
}
@@ -432,10 +436,19 @@ fini_ssa_operands (void)
ggc_free (ptr);
}
- VEC_free (tree, heap, clobbered_v_may_defs);
- VEC_free (tree, heap, clobbered_vuses);
- VEC_free (tree, heap, ro_call_vuses);
ops_active = false;
+
+ if (dump_file && (dump_flags & TDF_STATS))
+ {
+ fprintf (dump_file, "Original clobbered vars:%d\n", clobber_stats.clobbered_vars);
+ fprintf (dump_file, "Static write clobbers avoided:%d\n", clobber_stats.static_write_clobbers_avoided);
+ fprintf (dump_file, "Static read clobbers avoided:%d\n", clobber_stats.static_read_clobbers_avoided);
+ fprintf (dump_file, "Unescapable clobbers avoided:%d\n", clobber_stats.unescapable_clobbers_avoided);
+ fprintf (dump_file, "Original readonly clobbers:%d\n", clobber_stats.readonly_clobbers);
+ fprintf (dump_file, "Static readonly clobbers avoided:%d\n", clobber_stats.static_readonly_clobbers_avoided);
+ fprintf (dump_file, "Unescapable readonly clobbers avoided:%d\n", clobber_stats.unescapable_readonly_clobbers_avoided);
+
+ }
}
@@ -1742,7 +1755,7 @@ get_call_expr_operands (tree stmt, tree
&& !(call_flags & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
add_call_clobber_ops (stmt, get_callee_fndecl (expr));
else if (!(call_flags & ECF_CONST))
- add_call_read_ops (stmt);
+ add_call_read_ops (stmt, get_callee_fndecl (expr));
}
/* Find uses in the called function. */
@@ -1952,6 +1965,31 @@ add_to_addressable_set (tree ref, bitmap
}
}
+/* True if CALLEE doesn't clobber variables in NODE that only escape
+ by address through calls. */
+
+static bool
+callee_okay_for_noescape (struct cgraph_node *node, tree callee)
+{
+ function_ann_t fann;
+ bitmap callees;
+
+ if (callee == NULL)
+ return false;
+ fann = function_ann (callee);
+
+ if (!fann || fann->callees == NULL)
+ return false;
+
+ if (fann->has_pointer_arguments)
+ return false;
+
+ callees = fann->callees;
+ if (bitmap_bit_p ( callees, node->uid))
+ return false;
+
+ return true;
+}
/* Add clobbering definitions for .GLOBAL_VAR or for each of the call
clobbered variables in the function. */
@@ -1959,14 +1997,14 @@ add_to_addressable_set (tree ref, bitmap
static void
add_call_clobber_ops (tree stmt, tree callee)
{
- int i;
unsigned u;
- tree t;
bitmap_iterator bi;
stmt_ann_t s_ann = stmt_ann (stmt);
- struct stmt_ann_d empty_ann;
bitmap not_read_b, not_written_b;
-
+ struct cgraph_node *ournode = cgraph_node (current_function_decl);
+ bool okay_for_call_skip = callee_okay_for_noescape (ournode, callee);
+
+
/* Functions that are not const, pure or never return may clobber
call-clobbered variables. */
if (s_ann)
@@ -1991,97 +2029,44 @@ add_call_clobber_ops (tree stmt, tree ca
not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
not_written_b = callee ? ipa_reference_get_not_written_global (callee) : NULL;
-
- /* If cache is valid, copy the elements into the build vectors. */
- if (ssa_call_clobbered_cache_valid
- && (!not_read_b || bitmap_empty_p (not_read_b))
- && (!not_written_b || bitmap_empty_p (not_written_b)))
- {
- /* Process the caches in reverse order so we are always inserting at
- the head of the list. */
- for (i = VEC_length (tree, clobbered_vuses) - 1; i >=0; i--)
- {
- t = VEC_index (tree, clobbered_vuses, i);
- gcc_assert (TREE_CODE (t) != SSA_NAME);
- var_ann (t)->in_vuse_list = 1;
- opbuild_append_virtual (&build_vuses, t);
- }
- for (i = VEC_length (tree, clobbered_v_may_defs) - 1; i >= 0; i--)
- {
- t = VEC_index (tree, clobbered_v_may_defs, i);
- gcc_assert (TREE_CODE (t) != SSA_NAME);
- var_ann (t)->in_v_may_def_list = 1;
- opbuild_append_virtual (&build_v_may_defs, t);
- }
- if (s_ann)
- {
- s_ann->makes_aliased_loads = clobbered_aliased_loads;
- s_ann->makes_aliased_stores = clobbered_aliased_stores;
- }
- return;
- }
-
- memset (&empty_ann, 0, sizeof (struct stmt_ann_d));
-
/* Add a V_MAY_DEF operand for every call clobbered variable. */
EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, u, bi)
{
tree var = referenced_var (u);
+ bool not_read
+ = not_read_b ? bitmap_bit_p (not_read_b, u) : false;
+ bool not_written
+ = not_written_b ? bitmap_bit_p (not_written_b, u) : false;
+ bool before = okay_for_call_skip;
+
gcc_assert (!unmodifiable_var_p (var));
- {
- bool not_read
- = not_read_b ? bitmap_bit_p (not_read_b, u) : false;
- bool not_written
- = not_written_b ? bitmap_bit_p (not_written_b, u) : false;
+
+ clobber_stats.clobbered_vars++;
- if (not_written)
+ /* See if this variable is really clobbered by this function. */
+ if (okay_for_call_skip)
+ {
+ okay_for_call_skip &= (var_ann (var)->escape_mask & ~(ESCAPE_TO_CALL)) == 0;
+ if (okay_for_call_skip)
{
- if (!not_read)
- add_stmt_operand (&var, &empty_ann, opf_none);
+ clobber_stats.unescapable_clobbers_avoided++;
+ continue;
}
- else
- add_stmt_operand (&var, &empty_ann, opf_is_def);
}
- }
-
- if ((!not_read_b || bitmap_empty_p (not_read_b))
- && (!not_written_b || bitmap_empty_p (not_written_b)))
- {
- clobbered_aliased_loads = empty_ann.makes_aliased_loads;
- clobbered_aliased_stores = empty_ann.makes_aliased_stores;
-
- /* Set the flags for a stmt's annotation. */
- if (s_ann)
+ okay_for_call_skip = before;
+
+ if (not_written)
{
- s_ann->makes_aliased_loads = empty_ann.makes_aliased_loads;
- s_ann->makes_aliased_stores = empty_ann.makes_aliased_stores;
+ clobber_stats.static_write_clobbers_avoided++;
+ if (!not_read)
+ add_stmt_operand (&var, s_ann, opf_none);
+ else
+ clobber_stats.static_read_clobbers_avoided++;
}
-
- /* Prepare empty cache vectors. */
- VEC_truncate (tree, clobbered_vuses, 0);
- VEC_truncate (tree, clobbered_v_may_defs, 0);
-
- /* Now fill the clobbered cache with the values that have been found. */
- for (i = opbuild_first (&build_vuses);
- i != OPBUILD_LAST;
- i = opbuild_next (&build_vuses, i))
- VEC_safe_push (tree, heap, clobbered_vuses,
- opbuild_elem_virtual (&build_vuses, i));
-
- gcc_assert (opbuild_num_elems (&build_vuses)
- == VEC_length (tree, clobbered_vuses));
-
- for (i = opbuild_first (&build_v_may_defs);
- i != OPBUILD_LAST;
- i = opbuild_next (&build_v_may_defs, i))
- VEC_safe_push (tree, heap, clobbered_v_may_defs,
- opbuild_elem_virtual (&build_v_may_defs, i));
-
- gcc_assert (opbuild_num_elems (&build_v_may_defs)
- == VEC_length (tree, clobbered_v_may_defs));
-
- ssa_call_clobbered_cache_valid = true;
+ else
+ add_stmt_operand (&var, s_ann, opf_is_def);
}
+
}
@@ -2089,14 +2074,14 @@ add_call_clobber_ops (tree stmt, tree ca
function. */
static void
-add_call_read_ops (tree stmt)
+add_call_read_ops (tree stmt, tree callee)
{
- int i;
unsigned u;
- tree t;
bitmap_iterator bi;
stmt_ann_t s_ann = stmt_ann (stmt);
- struct stmt_ann_d empty_ann;
+ bitmap not_read_b;
+ struct cgraph_node *ournode = cgraph_node (current_function_decl);
+ bool okay_for_call_skip = callee_okay_for_noescape (ournode, callee);
/* if the function is not pure, it may reference memory. Add
a VUSE for .GLOBAL_VAR if it has been created. See add_referenced_var
@@ -2107,50 +2092,36 @@ add_call_read_ops (tree stmt)
return;
}
- /* If cache is valid, copy the elements into the build vector. */
- if (ssa_ro_call_cache_valid)
- {
- for (i = VEC_length (tree, ro_call_vuses) - 1; i >=0 ; i--)
- {
- /* Process the caches in reverse order so we are always inserting at
- the head of the list. */
- t = VEC_index (tree, ro_call_vuses, i);
- gcc_assert (TREE_CODE (t) != SSA_NAME);
- var_ann (t)->in_vuse_list = 1;
- opbuild_append_virtual (&build_vuses, t);
- }
- if (s_ann)
- s_ann->makes_aliased_loads = ro_call_aliased_loads;
- return;
- }
-
- memset (&empty_ann, 0, sizeof (struct stmt_ann_d));
+ not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
/* Add a VUSE for each call-clobbered variable. */
EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, u, bi)
{
tree var = referenced_var (u);
- add_stmt_operand (&var, &empty_ann, opf_none | opf_non_specific);
+ bool not_read = not_read_b ? bitmap_bit_p (not_read_b, u) : false;
+ bool before = okay_for_call_skip;
+
+ clobber_stats.readonly_clobbers++;
+
+ if (not_read)
+ {
+ clobber_stats.static_readonly_clobbers_avoided++;
+ continue;
+ }
+
+ if (okay_for_call_skip)
+ {
+ okay_for_call_skip &= (var_ann (var)->escape_mask & ~(ESCAPE_TO_CALL)) == 0;
+ if (okay_for_call_skip)
+ {
+ clobber_stats.unescapable_clobbers_avoided++;
+ continue;
+ }
+ }
+
+ add_stmt_operand (&var, s_ann, opf_none | opf_non_specific);
+ okay_for_call_skip = before;
}
-
- ro_call_aliased_loads = empty_ann.makes_aliased_loads;
- if (s_ann)
- s_ann->makes_aliased_loads = empty_ann.makes_aliased_loads;
-
- /* Prepare empty cache vectors. */
- VEC_truncate (tree, ro_call_vuses, 0);
-
- /* Now fill the clobbered cache with the values that have been found. */
- for (i = opbuild_first (&build_vuses);
- i != OPBUILD_LAST;
- i = opbuild_next (&build_vuses, i))
- VEC_safe_push (tree, heap, ro_call_vuses,
- opbuild_elem_virtual (&build_vuses, i));
-
- gcc_assert (opbuild_num_elems (&build_vuses)
- == VEC_length (tree, ro_call_vuses));
-
- ssa_ro_call_cache_valid = true;
}
Index: tree-ssa-operands.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.h,v
retrieving revision 2.20
diff -u -p -r2.20 tree-ssa-operands.h
--- tree-ssa-operands.h 10 Jul 2005 00:27:51 -0000 2.20
+++ tree-ssa-operands.h 29 Sep 2005 00:53:08 -0000
@@ -165,9 +165,6 @@ extern void dump_immediate_uses_for (FIL
extern void debug_immediate_uses (void);
extern void debug_immediate_uses_for (tree var);
-extern bool ssa_call_clobbered_cache_valid;
-extern bool ssa_ro_call_cache_valid;
-
extern bool ssa_operands_active (void);
extern void add_to_addressable_set (tree, bitmap *);