From 4a444e581667f110bfa936aa8d364cd751237770 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 15 May 2010 01:39:39 +0200 Subject: 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 --- gcc/ChangeLog | 21 ++++++++++ gcc/cgraph.h | 14 +++++++ gcc/ipa-reference.c | 74 ++--------------------------------- gcc/ipa.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++----- gcc/varpool.c | 2 +- 5 files changed, 140 insertions(+), 81 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 17de8d1..651b67d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,26 @@ 2010-05-14 Jan Hubicka + * 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 + * ipa.c (cgraph_remove_unreachable_nodes): Revert accidental commit. 2010-05-14 Richard Guenther diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 1ccae09..6348033 100644 --- a/gcc/cgraph.h +++ b/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); diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c index 184229d..3180a9d 100644 --- a/gcc/ipa-reference.c +++ b/gcc/ipa-reference.c @@ -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; } diff --git a/gcc/ipa.c b/gcc/ipa.c index 93e83ce..9d2b023 100644 --- a/gcc/ipa.c +++ b/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) { diff --git a/gcc/varpool.c b/gcc/varpool.c index f6e1449..c713a77 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -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)) -- cgit v1.1