re PR middle-end/37448 (cannot compile big function)

PR middle-end/37448
	* ipa-reference.c (ipa_reference_local_vars_info_d,
	ipa_reference_global_vars_info_d,
	ipa_reference_local_vars_info_t, ipa_reference_global_vars_info_t,
	ipa_reference_vars_info_t): Move here from ipa-reference.h
	(node_duplication_hook_holder, node_removal_hook_holder): New.
	(get_reference_vars_info_from_cgraph): Rename to ...
	(get_reference_vars_info): ... this one, use cgraph uids.
	(get_local_reference_vars_info, get_global_reference_vars_info):
	Use cgraph instead of decl.
	(ipa_reference_get_read_local, ipa_reference_get_written_local): Remove.
	(ipa_reference_get_read_global, ipa_reference_get_not_read_global
	ipa_reference_get_written_global, ipa_reference_get_not_written_global): Use
	cgraph argument.
	(check_call): Simplify avail check.
	(scan_stmt_for_static_refs): Update.
	(propagate_bits): Update.
	(merge_callee_local_info): Remove.
	(init_function_info): Use cgraph nodes.
	(clean_function_local_data): Break out from ...
	(clean_function): ... here.
	(copy_local_bitmap, copy_global_bitmap): New functions.
	(duplicate_node_data, remove_node_data): New functions.
	(generate_summary): Register hooks; use visibility instead of
	master clones.
	(propafate): Use cgraph nodes; copy bitmap to each node in cycle.
	* ipa-reference.h (ipa_reference_local_vars_info_d,
	ipa_reference_global_vars_info_d,
	ipa_reference_local_vars_info_t, ipa_reference_global_vars_info_t,
	ipa_reference_vars_info_t): Move to ipa-reference.c
	(ipa_reference_get_read_local, ipa_reference_get_written_local):
	Remove.
	(ipa_reference_get_read_global, ipa_reference_get_written_global,
	ipa_reference_get_not_read_global, ipa_reference_get_not_written_global):
	Update prototype.
	* ipa-pure-const.c (funct_state_vec): Turn into VECtor.
	(init_state): Remove.
	(node_duplication_hook_holder, node_removal_hook_holder): New.
	(get_function_state, set_function_state): Use VECtor.
	(analyze_function): Check body availability.
	(add_new_function): Likewise.
	(duplicate_node_data, remove_node_data): New.
	(generate_summary): Register hooks; do not care about clones.
	(propafate): Do not care about clones; recursive functions are not looping.
	* ipa-utils.c (searchc, ipa_utils_reduced_inorder): Do not skip clones.
	* ipa-prop.c (edge_removal_hook_holder, node_removal_hook_holder,
	* edge_duplication_hook_holder, node_duplication_hook_holder): Make
	static.
	* tree-flow.h (function_ann_d): Remove reference_vars_info.
	* tree-ssa-opreands.c (add_call_clobber_ops, add_call_read_ops): Update call of
	ipa-reference accesors.

From-SVN: r140463
This commit is contained in:
Jan Hubicka 2008-09-18 19:28:40 +02:00 committed by Jan Hubicka
parent 52d1bfd8cd
commit e2c9111c0e
7 changed files with 361 additions and 300 deletions

View File

@ -1,3 +1,57 @@
2008-09-18 Jan Hubicka <jh@suse.cz>
PR middle-end/37448
* ipa-reference.c (ipa_reference_local_vars_info_d,
ipa_reference_global_vars_info_d,
ipa_reference_local_vars_info_t, ipa_reference_global_vars_info_t,
ipa_reference_vars_info_t): Move here from ipa-reference.h
(node_duplication_hook_holder, node_removal_hook_holder): New.
(get_reference_vars_info_from_cgraph): Rename to ...
(get_reference_vars_info): ... this one, use cgraph uids.
(get_local_reference_vars_info, get_global_reference_vars_info):
Use cgraph instead of decl.
(ipa_reference_get_read_local, ipa_reference_get_written_local): Remove.
(ipa_reference_get_read_global, ipa_reference_get_not_read_global
ipa_reference_get_written_global, ipa_reference_get_not_written_global): Use
cgraph argument.
(check_call): Simplify avail check.
(scan_stmt_for_static_refs): Update.
(propagate_bits): Update.
(merge_callee_local_info): Remove.
(init_function_info): Use cgraph nodes.
(clean_function_local_data): Break out from ...
(clean_function): ... here.
(copy_local_bitmap, copy_global_bitmap): New functions.
(duplicate_node_data, remove_node_data): New functions.
(generate_summary): Register hooks; use visibility instead of
master clones.
(propafate): Use cgraph nodes; copy bitmap to each node in cycle.
* ipa-reference.h (ipa_reference_local_vars_info_d,
ipa_reference_global_vars_info_d,
ipa_reference_local_vars_info_t, ipa_reference_global_vars_info_t,
ipa_reference_vars_info_t): Move to ipa-reference.c
(ipa_reference_get_read_local, ipa_reference_get_written_local):
Remove.
(ipa_reference_get_read_global, ipa_reference_get_written_global,
ipa_reference_get_not_read_global, ipa_reference_get_not_written_global):
Update prototype.
* ipa-pure-const.c (funct_state_vec): Turn into VECtor.
(init_state): Remove.
(node_duplication_hook_holder, node_removal_hook_holder): New.
(get_function_state, set_function_state): Use VECtor.
(analyze_function): Check body availability.
(add_new_function): Likewise.
(duplicate_node_data, remove_node_data): New.
(generate_summary): Register hooks; do not care about clones.
(propafate): Do not care about clones; recursive functions are not looping.
* ipa-utils.c (searchc, ipa_utils_reduced_inorder): Do not skip clones.
* ipa-prop.c (edge_removal_hook_holder, node_removal_hook_holder,
* edge_duplication_hook_holder, node_duplication_hook_holder): Make
static.
* tree-flow.h (function_ann_d): Remove reference_vars_info.
* tree-ssa-opreands.c (add_call_clobber_ops, add_call_read_ops): Update call of
ipa-reference accesors.
2008-09-18 Simon Baldwin <simonb@google.com>
* c-opts.c (c_common_handle_option): Add handling for

View File

@ -40,10 +40,10 @@ VEC (ipa_node_params_t, heap) *ipa_node_params_vector;
VEC (ipa_edge_args_t, heap) *ipa_edge_args_vector;
/* Holders of ipa cgraph hooks: */
struct cgraph_edge_hook_list *edge_removal_hook_holder;
struct cgraph_node_hook_list *node_removal_hook_holder;
struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
struct cgraph_2node_hook_list *node_duplication_hook_holder;
static struct cgraph_edge_hook_list *edge_removal_hook_holder;
static struct cgraph_node_hook_list *node_removal_hook_holder;
static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
static struct cgraph_2node_hook_list *node_duplication_hook_holder;
/* Initialize worklist to contain all functions. */
struct ipa_func_list *

View File

@ -94,19 +94,14 @@ typedef struct funct_state_d * funct_state;
/* Array, indexed by cgraph node uid, of function states. */
static funct_state *funct_state_vec;
DEF_VEC_P (funct_state);
DEF_VEC_ALLOC_P (funct_state, heap);
static VEC (funct_state, heap) *funct_state_vec;
/* Holders of ipa cgraph hooks: */
static struct cgraph_node_hook_list *function_insertion_hook_holder;
/* Init the function state. */
static void
init_state (void)
{
funct_state_vec = XCNEWVEC (funct_state, cgraph_max_uid);
}
static struct cgraph_2node_hook_list *node_duplication_hook_holder;
static struct cgraph_node_hook_list *node_removal_hook_holder;
/* Init the function state. */
@ -122,7 +117,10 @@ finish_state (void)
static inline funct_state
get_function_state (struct cgraph_node *node)
{
return funct_state_vec[node->uid];
if (!funct_state_vec
|| VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid)
return NULL;
return VEC_index (funct_state, funct_state_vec, node->uid);
}
/* Set the function state S for NODE. */
@ -130,7 +128,10 @@ get_function_state (struct cgraph_node *node)
static inline void
set_function_state (struct cgraph_node *node, funct_state s)
{
funct_state_vec[node->uid] = s;
if (!funct_state_vec
|| VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid)
VEC_safe_grow_cleared (funct_state, heap, funct_state_vec, node->uid + 1);
VEC_replace (funct_state, funct_state_vec, node->uid, s);
}
/* Check to see if the use (or definition when CHECKING_WRITE is true)
@ -585,6 +586,9 @@ analyze_function (struct cgraph_node *fn)
tree decl = fn->decl;
funct_state l = XCNEW (struct funct_state_d);
if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE)
return;
set_function_state (fn, l);
l->pure_const_state = IPA_CONST;
@ -683,7 +687,8 @@ end:
static void
add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
funct_state_vec = XRESIZEVEC (funct_state, funct_state_vec, cgraph_max_uid);
if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
return;
/* There are some shared nodes, in particular the initializers on
static declarations. We do not need to scan them more than once
since all we would be interested in are the addressof
@ -694,6 +699,33 @@ add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
visited_nodes = NULL;
}
/* Called when new clone is inserted to callgraph late. */
static void
duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
void *data ATTRIBUTE_UNUSED)
{
if (get_function_state (src))
{
funct_state l = XNEW (struct funct_state_d);
gcc_assert (!get_function_state (dst));
memcpy (l, get_function_state (src), sizeof (*l));
set_function_state (dst, l);
}
}
/* Called when new clone is inserted to callgraph late. */
static void
remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
if (get_function_state (node))
{
free (get_function_state (node));
set_function_state (node, NULL);
}
}
/* Analyze each function in the cgraph to see if it is locally PURE or
CONST. */
@ -703,9 +735,12 @@ generate_summary (void)
{
struct cgraph_node *node;
node_removal_hook_holder =
cgraph_add_node_removal_hook (&remove_node_data, NULL);
node_duplication_hook_holder =
cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
function_insertion_hook_holder =
cgraph_add_function_insertion_hook (&add_new_function, NULL);
init_state ();
/* There are some shared nodes, in particular the initializers on
static declarations. We do not need to scan them more than once
since all we would be interested in are the addressof
@ -714,14 +749,12 @@ generate_summary (void)
/* Process all of the functions.
We do not want to process any of the clones so we check that this
is a master clone. However, we do NOT process any
AVAIL_OVERWRITABLE functions (these are never clones) we cannot
We do NOT process any AVAIL_OVERWRITABLE functions, we cannot
guarantee that what we learn about the one we see will be true
for the one that overrides it.
*/
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed && cgraph_is_master_clone (node))
if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
analyze_function (node);
pointer_set_destroy (visited_nodes);
@ -745,6 +778,8 @@ propagate (void)
struct ipa_dfs_info * w_info;
cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
cgraph_remove_node_duplication_hook (node_duplication_hook_holder);
cgraph_remove_node_removal_hook (node_removal_hook_holder);
order_pos = ipa_utils_reduced_inorder (order, true, false);
if (dump_file)
{
@ -788,12 +823,8 @@ propagate (void)
for (e = w->callees; e; e = e->next_callee)
{
struct cgraph_node *y = e->callee;
/* Only look at the master nodes and skip external nodes. */
y = cgraph_master_clone (y);
if (w == y)
looping = true;
if (y)
if (cgraph_function_body_availability (y) > AVAIL_OVERWRITABLE)
{
funct_state y_l = get_function_state (y);
if (pure_const_state < y_l->pure_const_state)
@ -861,11 +892,12 @@ propagate (void)
free (node->aux);
node->aux = NULL;
}
if (node->analyzed && cgraph_is_master_clone (node))
if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
free (get_function_state (node));
}
free (order);
VEC_free (funct_state, heap, funct_state_vec);
finish_state ();
return 0;
}
@ -873,7 +905,7 @@ propagate (void)
static bool
gate_pure_const (void)
{
return (flag_ipa_pure_const
return (flag_ipa_pure_const
/* Don't bother doing anything if the program has errors. */
&& !(errorcount || sorrycount));
}

View File

@ -69,6 +69,52 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "langhooks.h"
/* The static variables defined within the compilation unit that are
loaded or stored directly by function that owns this structure. */
struct ipa_reference_local_vars_info_d
{
bitmap statics_read;
bitmap statics_written;
/* Set when this function calls another function external to the
compilation unit or if the function has a asm clobber of memory.
In general, such calls are modeled as reading and writing all
variables (both bits on) but sometime there are attributes on the
called function so we can do better. */
bool calls_read_all;
bool calls_write_all;
};
/* Statics that are read and written by some set of functions. The
local ones are based on the loads and stores local to the function.
The global ones are based on the local info as well as the
transitive closure of the functions that are called. The
structures are separated to allow the global structures to be
shared between several functions since every function within a
strongly connected component will have the same information. This
sharing saves both time and space in the computation of the vectors
as well as their translation from decl_uid form to ann_uid
form. */
struct ipa_reference_global_vars_info_d
{
bitmap statics_read;
bitmap statics_written;
bitmap statics_not_read;
bitmap statics_not_written;
};
typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
struct ipa_reference_vars_info_d
{
ipa_reference_local_vars_info_t local;
ipa_reference_global_vars_info_t global;
};
typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t;
/* This splay tree contains all of the static variables that are
being considered by the compilation level alias analysis. For
module_at_a_time compilation, this is the set of static but not
@ -101,6 +147,8 @@ static bitmap_obstack global_info_obstack;
/* Holders of ipa cgraph hooks: */
static struct cgraph_node_hook_list *function_insertion_hook_holder;
static struct cgraph_2node_hook_list *node_duplication_hook_holder;
static struct cgraph_node_hook_list *node_removal_hook_holder;
enum initialization_status_t
{
@ -111,19 +159,37 @@ enum initialization_status_t
tree memory_identifier_string;
/* Vector where the reference var infos are actually stored. */
DEF_VEC_P (ipa_reference_vars_info_t);
DEF_VEC_ALLOC_P (ipa_reference_vars_info_t, heap);
static VEC (ipa_reference_vars_info_t, heap) *ipa_reference_vars_vector;
/* Return the ipa_reference_vars structure starting from the cgraph NODE. */
static inline ipa_reference_vars_info_t
get_reference_vars_info_from_cgraph (struct cgraph_node * node)
get_reference_vars_info (struct cgraph_node *node)
{
return get_function_ann (node->decl)->reference_vars_info;
if (!ipa_reference_vars_vector
|| VEC_length (ipa_reference_vars_info_t, ipa_reference_vars_vector) <= (unsigned int)node->uid)
return NULL;
return VEC_index (ipa_reference_vars_info_t, ipa_reference_vars_vector, node->uid);
}
/* Return the ipa_reference_vars structure starting from the cgraph NODE. */
static inline void
set_reference_vars_info (struct cgraph_node *node, ipa_reference_vars_info_t info)
{
if (!ipa_reference_vars_vector
|| VEC_length (ipa_reference_vars_info_t, ipa_reference_vars_vector) <= (unsigned int)node->uid)
VEC_safe_grow_cleared (ipa_reference_vars_info_t, heap, ipa_reference_vars_vector, node->uid + 1);
VEC_replace (ipa_reference_vars_info_t, ipa_reference_vars_vector, node->uid, info);
}
/* Get a bitmap that contains all of the locally referenced static
variables for function FN. */
static ipa_reference_local_vars_info_t
get_local_reference_vars_info (tree fn)
get_local_reference_vars_info (struct cgraph_node *fn)
{
ipa_reference_vars_info_t info = get_function_ann (fn)->reference_vars_info;
ipa_reference_vars_info_t info = get_reference_vars_info (fn);
if (info)
return info->local;
@ -136,9 +202,9 @@ get_local_reference_vars_info (tree fn)
variables for function FN. */
static ipa_reference_global_vars_info_t
get_global_reference_vars_info (tree fn)
get_global_reference_vars_info (struct cgraph_node *fn)
{
ipa_reference_vars_info_t info = get_function_ann (fn)->reference_vars_info;
ipa_reference_vars_info_t info = get_reference_vars_info (fn);
if (info)
return info->global;
@ -147,40 +213,12 @@ get_global_reference_vars_info (tree fn)
return NULL;
}
/* Return a bitmap indexed by VAR_DECL uid for the static variables
that may be read locally by the execution of the function fn.
Returns NULL if no data is available. */
bitmap
ipa_reference_get_read_local (tree fn)
{
ipa_reference_local_vars_info_t l = get_local_reference_vars_info (fn);
if (l)
return l->statics_read;
else
return NULL;
}
/* Return a bitmap indexed by VAR_DECL uid for the static variables
that may be written locally by the execution of the function fn.
Returns NULL if no data is available. */
bitmap
ipa_reference_get_written_local (tree fn)
{
ipa_reference_local_vars_info_t l = get_local_reference_vars_info (fn);
if (l)
return l->statics_written;
else
return NULL;
}
/* Return a bitmap indexed by VAR_DECL uid for the static variables
that are read during the execution of the function FN. Returns
NULL if no data is available. */
bitmap
ipa_reference_get_read_global (tree fn)
ipa_reference_get_read_global (struct cgraph_node *fn)
{
ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
if (g)
@ -195,7 +233,7 @@ ipa_reference_get_read_global (tree fn)
call. Returns NULL if no data is available. */
bitmap
ipa_reference_get_written_global (tree fn)
ipa_reference_get_written_global (struct cgraph_node *fn)
{
ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
if (g)
@ -209,7 +247,7 @@ ipa_reference_get_written_global (tree fn)
NULL if no data is available. */
bitmap
ipa_reference_get_not_read_global (tree fn)
ipa_reference_get_not_read_global (struct cgraph_node *fn)
{
ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
if (g)
@ -224,7 +262,7 @@ ipa_reference_get_not_read_global (tree fn)
call. Returns NULL if no data is available. */
bitmap
ipa_reference_get_not_written_global (tree fn)
ipa_reference_get_not_written_global (struct cgraph_node *fn)
{
ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
if (g)
@ -360,7 +398,7 @@ check_call (ipa_reference_local_vars_info_t local, gimple stmt)
avail = cgraph_function_body_availability (callee);
}
if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
if (avail <= AVAIL_OVERWRITABLE)
if (local)
{
if (flags & ECF_CONST)
@ -393,7 +431,7 @@ scan_stmt_for_static_refs (gimple_stmt_iterator *gsip,
bitmap_iterator bi;
if (fn)
local = get_reference_vars_info_from_cgraph (fn)->local;
local = get_reference_vars_info (fn)->local;
if (gimple_loaded_syms (stmt))
EXECUTE_IF_SET_IN_BITMAP (gimple_loaded_syms (stmt), 0, i, bi)
@ -472,30 +510,30 @@ get_static_name (int index)
return NULL;
}
/* Or in all of the bits from every callee into X, the caller's, bit
vector. There are several cases to check to avoid the sparse
/* Or in all of the bits from every callee of X into X_GLOBAL, the caller's cycle,
bit vector. There are several cases to check to avoid the sparse
bitmap oring. */
static void
propagate_bits (struct cgraph_node *x)
propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x)
{
ipa_reference_vars_info_t x_info = get_reference_vars_info_from_cgraph (x);
ipa_reference_global_vars_info_t x_global = x_info->global;
struct cgraph_edge *e;
for (e = x->callees; e; e = e->next_callee)
{
struct cgraph_node *y = e->callee;
/* Only look at the master nodes and skip external nodes. */
y = cgraph_master_clone (y);
if (y)
if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE)
{
if (get_reference_vars_info_from_cgraph (y))
if (get_reference_vars_info (y))
{
ipa_reference_vars_info_t y_info
= get_reference_vars_info_from_cgraph (y);
= get_reference_vars_info (y);
ipa_reference_global_vars_info_t y_global = y_info->global;
/* Calls in current cycle do not have global computed yet. */
if (!y_info->global)
continue;
if (x_global->statics_read
!= all_module_statics)
@ -539,70 +577,6 @@ propagate_bits (struct cgraph_node *x)
}
}
/* Look at all of the callees of X to see which ones represent inlined
calls. For each of these callees, merge their local info into
TARGET and check their children recursively.
This function goes away when Jan changes the inliner and IPA
analysis so that this is not run between the time when inlining
decisions are made and when the inlining actually occurs. */
static void
merge_callee_local_info (struct cgraph_node *target,
struct cgraph_node *x)
{
struct cgraph_edge *e;
ipa_reference_local_vars_info_t x_l =
get_reference_vars_info_from_cgraph (target)->local;
/* Make the world safe for tail recursion. */
struct ipa_dfs_info *node_info = (struct ipa_dfs_info *) x->aux;
if (node_info->aux)
return;
node_info->aux = x;
for (e = x->callees; e; e = e->next_callee)
{
struct cgraph_node *y = e->callee;
if (y->global.inlined_to)
{
ipa_reference_vars_info_t y_info;
ipa_reference_local_vars_info_t y_l;
struct cgraph_node* orig_y = y;
y = cgraph_master_clone (y);
if (y)
{
y_info = get_reference_vars_info_from_cgraph (y);
y_l = y_info->local;
if (x_l != y_l)
{
bitmap_ior_into (x_l->statics_read,
y_l->statics_read);
bitmap_ior_into (x_l->statics_written,
y_l->statics_written);
}
x_l->calls_read_all |= y_l->calls_read_all;
x_l->calls_write_all |= y_l->calls_write_all;
merge_callee_local_info (target, y);
}
else
{
fprintf(stderr, "suspect inlining of ");
dump_cgraph_node (stderr, orig_y);
fprintf(stderr, "\ninto ");
dump_cgraph_node (stderr, target);
dump_cgraph (stderr);
gcc_assert(false);
}
}
}
node_info->aux = NULL;
}
/* The init routine for analyzing global static variable usage. See
comments at top for description. */
static void
@ -653,10 +627,9 @@ init_function_info (struct cgraph_node *fn)
= XCNEW (struct ipa_reference_vars_info_d);
ipa_reference_local_vars_info_t l
= XCNEW (struct ipa_reference_local_vars_info_d);
tree decl = fn->decl;
/* Add the info to the tree's annotation. */
get_function_ann (decl)->reference_vars_info = info;
set_reference_vars_info (fn, info);
info->local = l;
l->statics_read = BITMAP_ALLOC (&local_info_obstack);
@ -728,18 +701,12 @@ analyze_function (struct cgraph_node *fn)
current_function_decl = NULL;
}
/* If FN is avail == AVAIL_OVERWRITABLE, replace the effects bit
vectors with worst case bit vectors. We had to analyze it above to
find out if it took the address of any statics. However, now that
we know that, we can get rid of all of the other side effects. */
/* Remove local data associated with function FN. */
static void
clean_function (struct cgraph_node *fn)
clean_function_local_data (struct cgraph_node *fn)
{
ipa_reference_vars_info_t info = get_reference_vars_info_from_cgraph (fn);
ipa_reference_vars_info_t info = get_reference_vars_info (fn);
ipa_reference_local_vars_info_t l = info->local;
ipa_reference_global_vars_info_t g = info->global;
if (l)
{
if (l->statics_read
@ -749,8 +716,19 @@ clean_function (struct cgraph_node *fn)
&&l->statics_written != all_module_statics)
BITMAP_FREE (l->statics_written);
free (l);
info->local = NULL;
}
}
/* Remove all data associated with function FN. */
static void
clean_function (struct cgraph_node *fn)
{
ipa_reference_vars_info_t info = get_reference_vars_info (fn);
ipa_reference_global_vars_info_t g = info->global;
clean_function_local_data (fn);
if (g)
{
if (g->statics_read
@ -769,10 +747,11 @@ clean_function (struct cgraph_node *fn)
&& g->statics_not_written != all_module_statics)
BITMAP_FREE (g->statics_not_written);
free (g);
info->global = NULL;
}
free (get_function_ann (fn->decl)->reference_vars_info);
get_function_ann (fn->decl)->reference_vars_info = NULL;
free (get_reference_vars_info (fn));
set_reference_vars_info (fn, NULL);
}
/* Called when new function is inserted to callgraph late. */
@ -787,6 +766,76 @@ add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
visited_nodes = NULL;
}
static bitmap
copy_local_bitmap (bitmap src)
{
bitmap dst;
if (!src)
return NULL;
if (src == all_module_statics)
return all_module_statics;
dst = BITMAP_ALLOC (&local_info_obstack);
bitmap_copy (dst, src);
return dst;
}
static bitmap
copy_global_bitmap (bitmap src)
{
bitmap dst;
if (!src)
return NULL;
if (src == all_module_statics)
return all_module_statics;
dst = BITMAP_ALLOC (&global_info_obstack);
bitmap_copy (dst, src);
return dst;
}
/* Called when new clone is inserted to callgraph late. */
static void
duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
void *data ATTRIBUTE_UNUSED)
{
ipa_reference_global_vars_info_t ginfo;
ipa_reference_local_vars_info_t linfo;
ipa_reference_global_vars_info_t dst_ginfo;
ipa_reference_local_vars_info_t dst_linfo;
ginfo = get_global_reference_vars_info (src);
linfo = get_local_reference_vars_info (src);
if (!linfo && !ginfo)
return;
init_function_info (dst);
if (linfo)
{
dst_linfo = get_local_reference_vars_info (dst);
dst_linfo->statics_read = copy_local_bitmap (linfo->statics_read);
dst_linfo->statics_written = copy_local_bitmap (linfo->statics_written);
dst_linfo->calls_read_all = linfo->calls_read_all;
dst_linfo->calls_write_all = linfo->calls_write_all;
}
if (ginfo)
{
get_reference_vars_info (dst)->global = XCNEW (struct ipa_reference_global_vars_info_d);
dst_ginfo = get_global_reference_vars_info (dst);
dst_ginfo->statics_read = copy_global_bitmap (ginfo->statics_read);
dst_ginfo->statics_written = copy_global_bitmap (ginfo->statics_written);
dst_ginfo->statics_not_read = copy_global_bitmap (ginfo->statics_not_read);
dst_ginfo->statics_not_written = copy_global_bitmap (ginfo->statics_not_written);
}
}
/* Called when node is removed. */
static void
remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
if (get_reference_vars_info (node))
clean_function (node);
}
/* Analyze each function in the cgraph to see which global or statics
are read or written. */
@ -802,6 +851,10 @@ generate_summary (void)
function_insertion_hook_holder =
cgraph_add_function_insertion_hook (&add_new_function, NULL);
node_removal_hook_holder =
cgraph_add_node_removal_hook (&remove_node_data, NULL);
node_duplication_hook_holder =
cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
ipa_init ();
module_statics_readonly = BITMAP_ALLOC (&local_info_obstack);
bm_temp = BITMAP_ALLOC (&local_info_obstack);
@ -822,10 +875,7 @@ generate_summary (void)
replaced with worst case info.
*/
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed
&& (cgraph_is_master_clone (node)
|| (cgraph_function_body_availability (node)
== AVAIL_OVERWRITABLE)))
if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
analyze_function (node);
pointer_set_destroy (visited_nodes);
@ -890,13 +940,10 @@ generate_summary (void)
}
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed
&& (cgraph_is_master_clone (node)
|| (cgraph_function_body_availability (node)
== AVAIL_OVERWRITABLE)))
if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
{
ipa_reference_local_vars_info_t l;
l = get_reference_vars_info_from_cgraph (node)->local;
l = get_reference_vars_info (node)->local;
/* Any variables that are not in all_module_statics are
removed from the local maps. This will include all of the
@ -913,16 +960,13 @@ generate_summary (void)
if (dump_file)
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed
&& (cgraph_is_master_clone (node)
|| (cgraph_function_body_availability (node)
== AVAIL_OVERWRITABLE)))
if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
{
ipa_reference_local_vars_info_t l;
unsigned int index;
bitmap_iterator bi;
l = get_reference_vars_info_from_cgraph (node)->local;
l = get_reference_vars_info (node)->local;
fprintf (dump_file,
"\nFunction name:%s/%i:",
cgraph_node_name (node), node->uid);
@ -940,6 +984,10 @@ generate_summary (void)
fprintf(dump_file, "%s ",
get_static_name (index));
}
if (l->calls_read_all)
fprintf (dump_file, "\n calls read all: ");
if (l->calls_write_all)
fprintf (dump_file, "\n calls read all: ");
}
}
@ -981,7 +1029,7 @@ propagate (void)
struct ipa_dfs_info * w_info;
node = order[i];
node_info = get_reference_vars_info_from_cgraph (node);
node_info = get_reference_vars_info (node);
if (!node_info)
{
dump_cgraph_node (stderr, node);
@ -989,7 +1037,7 @@ propagate (void)
gcc_unreachable ();
}
node_info->global = node_g;
gcc_assert (!node_info->global);
node_l = node_info->local;
read_all = node_l->calls_read_all;
@ -1002,7 +1050,7 @@ propagate (void)
while (w)
{
ipa_reference_local_vars_info_t w_l =
get_reference_vars_info_from_cgraph (w)->local;
get_reference_vars_info (w)->local;
read_all |= w_l->calls_read_all;
write_all |= w_l->calls_write_all;
@ -1029,16 +1077,14 @@ propagate (void)
node_l->statics_written);
}
propagate_bits (node_g, node);
w_info = (struct ipa_dfs_info *) node->aux;
w = w_info->next_cycle;
while (w)
{
ipa_reference_vars_info_t w_ri =
get_reference_vars_info_from_cgraph (w);
get_reference_vars_info (w);
ipa_reference_local_vars_info_t w_l = w_ri->local;
/* All nodes within a cycle share the same global info bitmaps. */
w_ri->global = node_g;
/* These global bitmaps are initialized from the local info
of all of the nodes in the region. However there is no
@ -1050,36 +1096,25 @@ propagate (void)
if (!write_all)
bitmap_ior_into (node_g->statics_written,
w_l->statics_written);
propagate_bits (node_g, w);
w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
w = node;
while (w)
{
propagate_bits (w);
w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
}
/* Need to fix up the local information sets. The information that
has been gathered so far is preinlining. However, the
compilation will progress post inlining so the local sets for the
inlined calls need to be merged into the callers. Note that the
local sets are not shared between all of the nodes in a cycle so
those nodes in the cycle must be processed explicitly. */
for (i = 0; i < order_pos; i++ )
{
struct ipa_dfs_info * w_info;
node = order[i];
merge_callee_local_info (node, node);
/* All nodes within a cycle have the same global info bitmaps. */
node_info->global = node_g;
w_info = (struct ipa_dfs_info *) node->aux;
w = w_info->next_cycle;
while (w)
{
merge_callee_local_info (w, w);
ipa_reference_vars_info_t w_ri =
get_reference_vars_info (w);
gcc_assert (!w_ri->global);
w_ri->global = XCNEW (struct ipa_reference_global_vars_info_d);
w_ri->global->statics_read = copy_global_bitmap (node_g->statics_read);
w_ri->global->statics_written = copy_global_bitmap (node_g->statics_written);
w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
@ -1097,7 +1132,7 @@ propagate (void)
struct ipa_dfs_info * w_info;
node = order[i];
node_info = get_reference_vars_info_from_cgraph (node);
node_info = get_reference_vars_info (node);
node_g = node_info->global;
node_l = node_info->local;
fprintf (dump_file,
@ -1123,7 +1158,7 @@ propagate (void)
while (w)
{
ipa_reference_vars_info_t w_ri =
get_reference_vars_info_from_cgraph (w);
get_reference_vars_info (w);
ipa_reference_local_vars_info_t w_l = w_ri->local;
fprintf (dump_file, "\n next cycle: %s/%i ",
cgraph_node_name (w), w->uid);
@ -1170,7 +1205,7 @@ propagate (void)
ipa_reference_vars_info_t node_info;
ipa_reference_global_vars_info_t node_g;
node = order[i];
node_info = get_reference_vars_info_from_cgraph (node);
node_info = get_reference_vars_info (node);
node_g = node_info->global;
/* Create the complimentary sets. These are more useful for
@ -1179,11 +1214,9 @@ propagate (void)
node_g->statics_not_written = BITMAP_ALLOC (&global_info_obstack);
if (node_g->statics_read != all_module_statics)
{
bitmap_and_compl (node_g->statics_not_read,
all_module_statics,
node_g->statics_read);
}
bitmap_and_compl (node_g->statics_not_read,
all_module_statics,
node_g->statics_read);
if (node_g->statics_written
!= all_module_statics)
@ -1197,7 +1230,7 @@ propagate (void)
for (node = cgraph_nodes; node; node = node->next)
{
ipa_reference_vars_info_t node_info;
node_info = get_reference_vars_info_from_cgraph (node);
node_info = get_reference_vars_info (node);
/* Get rid of the aux information. */
if (node->aux)
@ -1206,19 +1239,10 @@ propagate (void)
node->aux = NULL;
}
if (node->analyzed
&& (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE))
if (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE)
clean_function (node);
else if (node_info)
{
/* Remove local info we no longer need. */
if (node_info->local->statics_read
&& node_info->local->statics_read != all_module_statics)
BITMAP_FREE (node_info->local->statics_read);
if (node_info->local->statics_written
&& node_info->local->statics_written != all_module_statics)
BITMAP_FREE (node_info->local->statics_written);
}
clean_function_local_data (node);
}
bitmap_obstack_release (&local_info_obstack);
return 0;

View File

@ -23,60 +23,11 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "tree.h"
/* The static variables defined within the compilation unit that are
loaded or stored directly by function that owns this structure. */
struct ipa_reference_local_vars_info_d
{
bitmap statics_read;
bitmap statics_written;
/* Set when this function calls another function external to the
compilation unit or if the function has a asm clobber of memory.
In general, such calls are modeled as reading and writing all
variables (both bits on) but sometime there are attributes on the
called function so we can do better. */
bool calls_read_all;
bool calls_write_all;
};
struct ipa_reference_global_vars_info_d
{
bitmap statics_read;
bitmap statics_written;
bitmap statics_not_read;
bitmap statics_not_written;
};
/* Statics that are read and written by some set of functions. The
local ones are based on the loads and stores local to the function.
The global ones are based on the local info as well as the
transitive closure of the functions that are called. The
structures are separated to allow the global structures to be
shared between several functions since every function within a
strongly connected component will have the same information. This
sharing saves both time and space in the computation of the vectors
as well as their translation from decl_uid form to ann_uid
form. */
typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
struct ipa_reference_vars_info_d
{
ipa_reference_local_vars_info_t local;
ipa_reference_global_vars_info_t global;
};
typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t;
/* In ipa-reference.c */
bitmap ipa_reference_get_read_local (tree fn);
bitmap ipa_reference_get_written_local (tree fn);
bitmap ipa_reference_get_read_global (tree fn);
bitmap ipa_reference_get_written_global (tree fn);
bitmap ipa_reference_get_not_read_global (tree fn);
bitmap ipa_reference_get_not_written_global (tree fn);
bitmap ipa_reference_get_read_global (struct cgraph_node *fn);
bitmap ipa_reference_get_written_global (struct cgraph_node *fn);
bitmap ipa_reference_get_not_read_global (struct cgraph_node *fn);
bitmap ipa_reference_get_not_written_global (struct cgraph_node *fn);
#endif /* GCC_IPA_REFERENCE_H */

View File

@ -100,10 +100,8 @@ searchc (struct searchc_env* env, struct cgraph_node *v)
{
struct ipa_dfs_info * w_info;
struct cgraph_node *w = edge->callee;
/* Bypass the clones and only look at the master node. Skip
external and other bogus nodes. */
w = cgraph_master_clone (w);
if (w && w->aux)
if (w->aux && cgraph_function_body_availability (edge->callee) > AVAIL_OVERWRITABLE)
{
w_info = (struct ipa_dfs_info *) w->aux;
if (w_info->new_node)
@ -168,27 +166,29 @@ ipa_utils_reduced_inorder (struct cgraph_node **order,
env.reduce = reduce;
for (node = cgraph_nodes; node; node = node->next)
if ((node->analyzed)
&& (cgraph_is_master_clone (node)
|| (allow_overwritable
&& (cgraph_function_body_availability (node) ==
AVAIL_OVERWRITABLE))))
{
/* Reuse the info if it is already there. */
struct ipa_dfs_info *info = (struct ipa_dfs_info *) node->aux;
if (!info)
info = XCNEW (struct ipa_dfs_info);
info->new_node = true;
info->on_stack = false;
info->next_cycle = NULL;
node->aux = info;
splay_tree_insert (env.nodes_marked_new,
(splay_tree_key)node->uid,
(splay_tree_value)node);
}
else
node->aux = NULL;
{
enum availability avail = cgraph_function_body_availability (node);
if (avail > AVAIL_OVERWRITABLE
|| (allow_overwritable
&& (avail == AVAIL_OVERWRITABLE)))
{
/* Reuse the info if it is already there. */
struct ipa_dfs_info *info = (struct ipa_dfs_info *) node->aux;
if (!info)
info = XCNEW (struct ipa_dfs_info);
info->new_node = true;
info->on_stack = false;
info->next_cycle = NULL;
node->aux = info;
splay_tree_insert (env.nodes_marked_new,
(splay_tree_key)node->uid,
(splay_tree_value)node);
}
else
node->aux = NULL;
}
result = splay_tree_min (env.nodes_marked_new);
while (result)
{

View File

@ -1653,8 +1653,8 @@ add_call_clobber_ops (gimple stmt, tree callee ATTRIBUTE_UNUSED)
/* Get info for local and module level statics. There is a bit
set for each static if the call being processed does not read
or write that variable. */
not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
not_written_b = callee ? ipa_reference_get_not_written_global (callee) : NULL;
not_read_b = callee ? ipa_reference_get_not_read_global (cgraph_node (callee)) : NULL;
not_written_b = callee ? ipa_reference_get_not_written_global (cgraph_node (callee)) : NULL;
/* Add a VDEF operand for every call clobbered variable. */
EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, u, bi)
@ -1705,7 +1705,7 @@ add_call_read_ops (gimple stmt, tree callee ATTRIBUTE_UNUSED)
if (gimple_call_flags (stmt) & ECF_CONST)
return;
not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL;
not_read_b = callee ? ipa_reference_get_not_read_global (cgraph_node (callee)) : NULL;
/* For pure functions we compute non-escaped uses separately. */
if (gimple_call_flags (stmt) & ECF_PURE)