Commit 4a444e58 by Jan Hubicka Committed by Jan Hubicka

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
parent c13af44b
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.
2010-05-14 Richard Guenther <rguenther@suse.de>
......
......@@ -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;
}
......
......@@ -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))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment