cgraph.h (ipa_discover_readonly_nonaddressable_vars): Declare.
* cgraph.h (ipa_discover_readonly_nonaddressable_vars): Declare. (varpool_all_refs_explicit_p): New inline function. * ipa-reference.c: Update comment. (module_statics_written): Remove. (get_static_decl): Remove. (ipa_init): Do not initialize module_statics_written. (analyze_function): Likewise. (generate_summary): Likewise; do not compute module_statics_readonly and do not update variable flags. (propagate): Call ipa_discover_readonly_nonaddressable_vars. * ipa.c: Inlucde flags.h (cgraph_local_node_p): New. (cgraph_remove_unreachable_nodes): Return early when not optimizing; promote functions to local. (ipa_discover_readonly_nonaddressable_vars): New function. (function_and_variable_visibility): Use cgraph_local_node_p. * varpool.c (varpool_finalize_decl): Set force_output for DECL_PRESERVE_P vars. From-SVN: r159421
This commit is contained in:
parent
c13af44bcc
commit
4a444e5816
5 changed files with 140 additions and 81 deletions
|
@ -1,3 +1,24 @@
|
|||
2010-05-14 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* cgraph.h (ipa_discover_readonly_nonaddressable_vars): Declare.
|
||||
(varpool_all_refs_explicit_p): New inline function.
|
||||
* ipa-reference.c: Update comment.
|
||||
(module_statics_written): Remove.
|
||||
(get_static_decl): Remove.
|
||||
(ipa_init): Do not initialize module_statics_written.
|
||||
(analyze_function): Likewise.
|
||||
(generate_summary): Likewise; do not compute module_statics_readonly
|
||||
and do not update variable flags.
|
||||
(propagate): Call ipa_discover_readonly_nonaddressable_vars.
|
||||
* ipa.c: Inlucde flags.h
|
||||
(cgraph_local_node_p): New.
|
||||
(cgraph_remove_unreachable_nodes): Return early when not optimizing;
|
||||
promote functions to local.
|
||||
(ipa_discover_readonly_nonaddressable_vars): New function.
|
||||
(function_and_variable_visibility): Use cgraph_local_node_p.
|
||||
* varpool.c (varpool_finalize_decl): Set force_output for
|
||||
DECL_PRESERVE_P vars.
|
||||
|
||||
2010-05-14 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* ipa.c (cgraph_remove_unreachable_nodes): Revert accidental commit.
|
||||
|
|
14
gcc/cgraph.h
14
gcc/cgraph.h
|
@ -644,6 +644,7 @@ void varpool_node_set_add (varpool_node_set, struct varpool_node *);
|
|||
void varpool_node_set_remove (varpool_node_set, struct varpool_node *);
|
||||
void dump_varpool_node_set (FILE *, varpool_node_set);
|
||||
void debug_varpool_node_set (varpool_node_set);
|
||||
void ipa_discover_readonly_nonaddressable_vars (void);
|
||||
|
||||
/* In predict.c */
|
||||
bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);
|
||||
|
@ -878,6 +879,19 @@ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
|
|||
return !node->address_taken && cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
|
||||
}
|
||||
|
||||
/* Return true when all references to VNODE must be visible in ipa_ref_list.
|
||||
i.e. if the variable is not externally visible or not used in some magic
|
||||
way (asm statement or such).
|
||||
The magic uses are all sumarized in force_output flag. */
|
||||
|
||||
static inline bool
|
||||
varpool_all_refs_explicit_p (struct varpool_node *vnode)
|
||||
{
|
||||
return (!vnode->externally_visible
|
||||
&& !vnode->used_from_other_partition
|
||||
&& !vnode->force_output);
|
||||
}
|
||||
|
||||
/* Constant pool accessor function. */
|
||||
htab_t constant_pool_htab (void);
|
||||
|
||||
|
|
|
@ -22,13 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
/* This file gathers information about how variables whose scope is
|
||||
confined to the compilation unit are used.
|
||||
|
||||
There are two categories of information produced by this pass:
|
||||
|
||||
1) The addressable (TREE_ADDRESSABLE) bit and readonly
|
||||
(TREE_READONLY) bit associated with these variables is properly set
|
||||
based on scanning all of the code withing the compilation unit.
|
||||
|
||||
2) The transitive call site specific clobber effects are computed
|
||||
The transitive call site specific clobber effects are computed
|
||||
for the variables whose scope is contained within this compilation
|
||||
unit.
|
||||
|
||||
|
@ -41,12 +35,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
side effects of each call. In later parts of the compiler, these
|
||||
local and global sets are examined to make the call clobbering less
|
||||
traumatic, promote some statics to registers, and improve aliasing
|
||||
information.
|
||||
|
||||
Currently must be run after inlining decisions have been made since
|
||||
otherwise, the local sets will not contain information that is
|
||||
consistent with post inlined state. The global sets are not prone
|
||||
to this problem since they are by definition transitive. */
|
||||
information. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
|
@ -136,10 +125,6 @@ static GTY((param1_is(int), param2_is(tree)))
|
|||
addresses have been taken and passed around. */
|
||||
static bitmap module_statics_escape;
|
||||
|
||||
/* This bitmap is used to knock out the module static variables that
|
||||
are not readonly. */
|
||||
static bitmap module_statics_written;
|
||||
|
||||
/* A bit is set for every module static we are considering. This is
|
||||
ored into the local info when asm code is found that clobbers all
|
||||
memory. */
|
||||
|
@ -308,17 +293,6 @@ is_proper_for_analysis (tree t)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Lookup the tree node for the static variable that has UID. */
|
||||
static tree
|
||||
get_static_decl (int index)
|
||||
{
|
||||
splay_tree_node stn =
|
||||
splay_tree_lookup (reference_vars_to_consider, index);
|
||||
if (stn)
|
||||
return (tree)stn->value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Lookup the tree node for the static variable that has UID and
|
||||
convert the name to a string for debugging. */
|
||||
|
||||
|
@ -419,7 +393,6 @@ ipa_init (void)
|
|||
bitmap_obstack_initialize (&local_info_obstack);
|
||||
bitmap_obstack_initialize (&global_info_obstack);
|
||||
module_statics_escape = BITMAP_ALLOC (&local_info_obstack);
|
||||
module_statics_written = BITMAP_ALLOC (&local_info_obstack);
|
||||
all_module_statics = BITMAP_ALLOC (&global_info_obstack);
|
||||
|
||||
node_removal_hook_holder =
|
||||
|
@ -524,7 +497,6 @@ analyze_function (struct cgraph_node *fn)
|
|||
break;
|
||||
case IPA_REF_STORE:
|
||||
bitmap_set_bit (local->statics_written, DECL_UID (var));
|
||||
bitmap_set_bit (module_statics_written, DECL_UID (var));
|
||||
break;
|
||||
case IPA_REF_ADDR:
|
||||
bitmap_set_bit (module_statics_escape, DECL_UID (var));
|
||||
|
@ -656,11 +628,9 @@ generate_summary (void)
|
|||
struct varpool_node *vnode;
|
||||
unsigned int index;
|
||||
bitmap_iterator bi;
|
||||
bitmap module_statics_readonly;
|
||||
bitmap bm_temp;
|
||||
|
||||
ipa_init ();
|
||||
module_statics_readonly = BITMAP_ALLOC (&local_info_obstack);
|
||||
bm_temp = BITMAP_ALLOC (&local_info_obstack);
|
||||
|
||||
/* Process all of the variables first. */
|
||||
|
@ -682,46 +652,8 @@ generate_summary (void)
|
|||
bitmap_and_compl_into (all_module_statics,
|
||||
module_statics_escape);
|
||||
|
||||
bitmap_and_compl (module_statics_readonly, all_module_statics,
|
||||
module_statics_written);
|
||||
|
||||
/* If the address is not taken, we can unset the addressable bit
|
||||
on this variable. */
|
||||
EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
|
||||
{
|
||||
tree var = get_static_decl (index);
|
||||
TREE_ADDRESSABLE (var) = 0;
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Not TREE_ADDRESSABLE var %s\n",
|
||||
get_static_name (index));
|
||||
}
|
||||
|
||||
/* If the variable is never written, we can set the TREE_READONLY
|
||||
flag. Additionally if it has a DECL_INITIAL that is made up of
|
||||
constants we can treat the entire global as a constant. */
|
||||
|
||||
bitmap_and_compl (module_statics_readonly, all_module_statics,
|
||||
module_statics_written);
|
||||
EXECUTE_IF_SET_IN_BITMAP (module_statics_readonly, 0, index, bi)
|
||||
{
|
||||
tree var = get_static_decl (index);
|
||||
|
||||
/* Ignore variables in named sections - changing TREE_READONLY
|
||||
changes the section flags, potentially causing conflicts with
|
||||
other variables in the same named section. */
|
||||
if (DECL_SECTION_NAME (var) == NULL_TREE)
|
||||
{
|
||||
TREE_READONLY (var) = 1;
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "read-only var %s\n",
|
||||
get_static_name (index));
|
||||
}
|
||||
}
|
||||
|
||||
BITMAP_FREE(module_statics_escape);
|
||||
BITMAP_FREE(module_statics_written);
|
||||
module_statics_escape = NULL;
|
||||
module_statics_written = NULL;
|
||||
|
||||
if (dump_file)
|
||||
EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
|
||||
|
@ -748,7 +680,6 @@ generate_summary (void)
|
|||
all_module_statics);
|
||||
}
|
||||
|
||||
BITMAP_FREE(module_statics_readonly);
|
||||
BITMAP_FREE(bm_temp);
|
||||
|
||||
if (dump_file)
|
||||
|
@ -1093,6 +1024,7 @@ propagate (void)
|
|||
clean_function_local_data (node);
|
||||
}
|
||||
bitmap_obstack_release (&local_info_obstack);
|
||||
ipa_discover_readonly_nonaddressable_vars ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
110
gcc/ipa.c
110
gcc/ipa.c
|
@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "timevar.h"
|
||||
#include "gimple.h"
|
||||
#include "ggc.h"
|
||||
#include "flags.h"
|
||||
|
||||
/* Fill array order with all nodes with output flag set in the reverse
|
||||
topological order. */
|
||||
|
@ -194,6 +195,19 @@ varpool_can_remove_if_no_refs (struct varpool_node *node)
|
|||
&& (DECL_COMDAT (node->decl) || !node->externally_visible));
|
||||
}
|
||||
|
||||
/* Return true when function can be marked local. */
|
||||
|
||||
static bool
|
||||
cgraph_local_node_p (struct cgraph_node *node)
|
||||
{
|
||||
return (cgraph_only_called_directly_p (node)
|
||||
&& node->analyzed
|
||||
&& !DECL_EXTERNAL (node->decl)
|
||||
&& !node->local.externally_visible
|
||||
&& !node->reachable_from_other_partition
|
||||
&& !node->in_other_partition);
|
||||
}
|
||||
|
||||
/* Perform reachability analysis and reclaim all unreachable nodes.
|
||||
If BEFORE_INLINING_P is true this function is called before inlining
|
||||
decisions has been made. If BEFORE_INLINING_P is false this function also
|
||||
|
@ -408,18 +422,31 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
|
|||
}
|
||||
node->aux = NULL;
|
||||
}
|
||||
|
||||
if (file)
|
||||
fprintf (file, "\nReclaiming variables:");
|
||||
fprintf (file, "\n");
|
||||
|
||||
/* We must release unused extern inlines or sanity checking will fail. Rest of transformations
|
||||
are undesirable at -O0 since we do not want to remove anything. */
|
||||
if (!optimize)
|
||||
return changed;
|
||||
|
||||
if (file)
|
||||
fprintf (file, "Reclaiming variables:");
|
||||
for (vnode = varpool_nodes; vnode; vnode = vnext)
|
||||
{
|
||||
vnext = vnode->next;
|
||||
if (!vnode->needed)
|
||||
{
|
||||
if (file)
|
||||
fprintf (file, " %s", varpool_node_name (vnode));
|
||||
varpool_remove_node (vnode);
|
||||
if (file)
|
||||
fprintf (file, " %s", varpool_node_name (vnode));
|
||||
varpool_remove_node (vnode);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now update address_taken flags and try to promote functions to be local. */
|
||||
|
||||
if (file)
|
||||
fprintf (file, "\nClearing address taken flags:");
|
||||
for (node = cgraph_nodes; node; node = node->next)
|
||||
|
@ -431,12 +458,22 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
|
|||
bool found = false;
|
||||
for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref)
|
||||
&& !found; i++)
|
||||
found = true;
|
||||
{
|
||||
gcc_assert (ref->use == IPA_REF_ADDR);
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
if (file)
|
||||
fprintf (file, " %s", cgraph_node_name (node));
|
||||
node->address_taken = false;
|
||||
changed = true;
|
||||
if (cgraph_local_node_p (node))
|
||||
{
|
||||
node->local.local = true;
|
||||
if (file)
|
||||
fprintf (file, " (local)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,6 +488,64 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
|
|||
return changed;
|
||||
}
|
||||
|
||||
/* Discover variables that have no longer address taken or that are read only
|
||||
and update their flags.
|
||||
|
||||
FIXME: This can not be done in between gimplify and omp_expand since
|
||||
readonly flag plays role on what is shared and what is not. Currently we do
|
||||
this transformation as part of ipa-reference pass, but it would make sense
|
||||
to do it before early optimizations. */
|
||||
|
||||
void
|
||||
ipa_discover_readonly_nonaddressable_vars (void)
|
||||
{
|
||||
struct varpool_node *vnode;
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Clearing variable flags:");
|
||||
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
|
||||
if (vnode->finalized && varpool_all_refs_explicit_p (vnode)
|
||||
&& (TREE_ADDRESSABLE (vnode->decl) || !TREE_READONLY (vnode->decl)))
|
||||
{
|
||||
bool written = false;
|
||||
bool address_taken = false;
|
||||
int i;
|
||||
struct ipa_ref *ref;
|
||||
for (i = 0; ipa_ref_list_refering_iterate (&vnode->ref_list, i, ref)
|
||||
&& (!written || !address_taken); i++)
|
||||
switch (ref->use)
|
||||
{
|
||||
case IPA_REF_ADDR:
|
||||
address_taken = true;
|
||||
break;
|
||||
case IPA_REF_LOAD:
|
||||
break;
|
||||
case IPA_REF_STORE:
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
if (TREE_ADDRESSABLE (vnode->decl) && !address_taken)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " %s (addressable)", varpool_node_name (vnode));
|
||||
TREE_ADDRESSABLE (vnode->decl) = 0;
|
||||
}
|
||||
if (!TREE_READONLY (vnode->decl) && !address_taken && !written
|
||||
/* Making variable in explicit section readonly can cause section
|
||||
type conflict.
|
||||
See e.g. gcc.c-torture/compile/pr23237.c */
|
||||
&& DECL_SECTION_NAME (vnode->decl) == NULL)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode));
|
||||
TREE_READONLY (vnode->decl) = 1;
|
||||
}
|
||||
}
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
/* Return true when function NODE should be considered externally visible. */
|
||||
|
||||
static bool
|
||||
cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
|
||||
{
|
||||
|
@ -569,10 +664,7 @@ function_and_variable_visibility (bool whole_program)
|
|||
segfault though. */
|
||||
dissolve_same_comdat_group_list (node);
|
||||
}
|
||||
node->local.local = (cgraph_only_called_directly_p (node)
|
||||
&& node->analyzed
|
||||
&& !DECL_EXTERNAL (node->decl)
|
||||
&& !node->local.externally_visible);
|
||||
node->local.local = cgraph_local_node_p (node);
|
||||
}
|
||||
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
|
||||
{
|
||||
|
|
|
@ -374,7 +374,7 @@ varpool_finalize_decl (tree decl)
|
|||
if (node->needed)
|
||||
varpool_enqueue_needed_node (node);
|
||||
node->finalized = true;
|
||||
if (TREE_THIS_VOLATILE (decl))
|
||||
if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl))
|
||||
node->force_output = true;
|
||||
|
||||
if (decide_is_variable_needed (node, decl))
|
||||
|
|
Loading…
Add table
Reference in a new issue