X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fvarpool.c;h=c2d88c3bd761a897ef882c898acfc387238af05a;hp=817a3197901e81528727340a1a1804c2f60ac7ae;hb=1f5a839c957bc03e63b234ccf1cd7dca437b5482;hpb=79ee0029f41dabc810aabd2a600f8e8b32568ecb diff --git a/gcc/varpool.c b/gcc/varpool.c index 817a3197901..c2d88c3bd76 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -1,5 +1,5 @@ /* Callgraph handling code. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc. Contributed by Jan Hubicka @@ -107,7 +107,7 @@ eq_varpool_node (const void *p1, const void *p2) /* Return varpool node assigned to DECL without creating new one. */ struct varpool_node * -varpool_get_node (tree decl) +varpool_get_node (const_tree decl) { struct varpool_node key, **slot; @@ -116,7 +116,7 @@ varpool_get_node (tree decl) if (!varpool_hash) return NULL; - key.decl = decl; + key.decl = CONST_CAST2 (tree, const_tree, decl); slot = (struct varpool_node **) htab_find_slot (varpool_hash, &key, NO_INSERT); if (!slot) @@ -131,7 +131,7 @@ varpool_node (tree decl) struct varpool_node key, *node, **slot; gcc_assert (TREE_CODE (decl) == VAR_DECL - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))); + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p)); if (!varpool_hash) varpool_hash = htab_create_ggc (10, hash_varpool_node, @@ -162,25 +162,14 @@ varpool_remove_node (struct varpool_node *node) gcc_assert (*slot == node); htab_clear_slot (varpool_hash, slot); gcc_assert (!varpool_assembled_nodes_queue); - if (!node->alias) - while (node->extra_name) - varpool_remove_node (node->extra_name); if (node->next) node->next->prev = node->prev; if (node->prev) node->prev->next = node->next; else { - if (node->alias && node->extra_name) - { - gcc_assert (node->extra_name->extra_name == node); - node->extra_name->extra_name = node->next; - } - else - { - gcc_assert (varpool_nodes == node); - varpool_nodes = node->next; - } + gcc_assert (varpool_nodes == node); + varpool_nodes = node->next; } if (varpool_first_unanalyzed_node == node) varpool_first_unanalyzed_node = node->next_needed; @@ -241,6 +230,9 @@ dump_varpool_node (FILE *f, struct varpool_node *node) fprintf (f, " output"); if (node->externally_visible) fprintf (f, " externally_visible"); + if (node->resolution != LDPR_UNKNOWN) + fprintf (f, " %s", + ld_plugin_symbol_resolution_names[(int)node->resolution]); if (node->in_other_partition) fprintf (f, " in_other_partition"); else if (node->used_from_other_partition) @@ -308,8 +300,6 @@ varpool_enqueue_needed_node (struct varpool_node *node) void varpool_mark_needed_node (struct varpool_node *node) { - if (node->alias && node->extra_name) - node = node->extra_name; if (!node->needed && node->finalized && !TREE_ASM_WRITTEN (node->decl)) varpool_enqueue_needed_node (node); @@ -331,31 +321,64 @@ varpool_reset_queue (void) bool decide_is_variable_needed (struct varpool_node *node, tree decl) { - if (node->used_from_other_partition) - return true; /* If the user told us it is used, then it must be so. */ - if ((node->externally_visible && !DECL_COMDAT (decl)) - || node->force_output) + if (node->force_output) return true; + gcc_assert (!DECL_EXTERNAL (decl)); + /* Externally visible variables must be output. The exception is COMDAT variables that must be output only when they are needed. */ if (TREE_PUBLIC (decl) - && !flag_whole_program - && !flag_lto - && !flag_whopr && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; /* When not reordering top level variables, we have to assume that we are going to keep everything. */ - if (flag_toplevel_reorder) + if (!flag_toplevel_reorder) + return true; + return false; +} + +/* Return if DECL is constant and its initial value is known (so we can do + constant folding using DECL_INITIAL (decl)). */ + +bool +const_value_known_p (tree decl) +{ + if (TREE_CODE (decl) != VAR_DECL + &&TREE_CODE (decl) != CONST_DECL) return false; - /* We want to emit COMDAT variables only when absolutely necessary. */ - if (DECL_COMDAT (decl)) + if (TREE_CODE (decl) == CONST_DECL + || DECL_IN_CONSTANT_POOL (decl)) + return true; + + gcc_assert (TREE_CODE (decl) == VAR_DECL); + + if (!TREE_READONLY (decl) || TREE_THIS_VOLATILE (decl)) return false; + + /* Gimplifier takes away constructors of local vars */ + if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + return DECL_INITIAL (decl) != NULL; + + gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); + + /* Variables declared 'const' without an initializer + have zero as the initializer if they may not be + overridden at link or run time. */ + if (!DECL_INITIAL (decl) + && (DECL_EXTERNAL (decl) + || decl_replaceable_p (decl))) + return false; + + /* Variables declared `const' with an initializer are considered + to not be overwritable with different initializer by default. + + ??? Previously we behaved so for scalar variables but not for array + accesses. */ return true; } @@ -387,15 +410,24 @@ varpool_finalize_decl (tree decl) if (decide_is_variable_needed (node, decl)) varpool_mark_needed_node (node); - /* Since we reclaim unreachable nodes at the end of every language - level unit, we need to be conservative about possible entry points - there. */ - else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) - varpool_mark_needed_node (node); if (cgraph_global_info_ready) varpool_assemble_pending_decls (); } +/* Add the variable DECL to the varpool. + Unlike varpool_finalize_decl function is intended to be used + by middle end and allows insertion of new variable at arbitrary point + of compilation. */ +void +varpool_add_new_variable (tree decl) +{ + struct varpool_node *node; + varpool_finalize_decl (decl); + node = varpool_node (decl); + if (varpool_externally_visible_p (node, false)) + node->externally_visible = true; +} + /* Return variable availability. See cgraph.h for description of individual return values. */ enum availability @@ -409,7 +441,7 @@ cgraph_variable_initializer_availability (struct varpool_node *node) /* If the variable can be overwritten, return OVERWRITABLE. Takes care of at least two notable extensions - the COMDAT variables used to share template instantiations in C++. */ - if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl)) + if (!decl_replaceable_p (node->decl)) return AVAIL_OVERWRITABLE; return AVAIL_AVAILABLE; } @@ -442,7 +474,51 @@ varpool_analyze_pending_decls (void) already informed about increased alignment. */ align_variable (decl, 0); } - if (DECL_INITIAL (decl)) + if (node->alias && node->alias_of) + { + struct varpool_node *tgt = varpool_node (node->alias_of); + struct varpool_node *n; + + for (n = tgt; n && n->alias; + n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) + if (n == node) + { + error ("variable %q+D part of alias cycle", node->decl); + node->alias = false; + continue; + } + if (!VEC_length (ipa_ref_t, node->ref_list.references)) + ipa_record_reference (NULL, node, NULL, tgt, IPA_REF_ALIAS, NULL); + /* C++ FE sometimes change linkage flags after producing same body aliases. */ + if (node->extra_name_alias) + { + DECL_WEAK (node->decl) = DECL_WEAK (node->alias_of); + TREE_PUBLIC (node->decl) = TREE_PUBLIC (node->alias_of); + DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->alias_of); + DECL_VISIBILITY (node->decl) = DECL_VISIBILITY (node->alias_of); + if (TREE_PUBLIC (node->decl)) + { + DECL_COMDAT (node->decl) = DECL_COMDAT (node->alias_of); + DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->alias_of); + if (DECL_ONE_ONLY (node->alias_of) && !node->same_comdat_group) + { + node->same_comdat_group = tgt; + if (!tgt->same_comdat_group) + tgt->same_comdat_group = node; + else + { + struct varpool_node *n; + for (n = tgt->same_comdat_group; + n->same_comdat_group != tgt; + n = n->same_comdat_group) + ; + n->same_comdat_group = node; + } + } + } + } + } + else if (DECL_INITIAL (decl)) record_references_in_initializer (decl, analyzed); if (node->same_comdat_group) { @@ -457,6 +533,23 @@ varpool_analyze_pending_decls (void) return changed; } +/* Assemble thunks and aliases asociated to NODE. */ + +static void +assemble_aliases (struct varpool_node *node) +{ + int i; + struct ipa_ref *ref; + for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct varpool_node *alias = ipa_ref_refering_varpool_node (ref); + assemble_alias (alias->decl, + DECL_ASSEMBLER_NAME (alias->alias_of)); + assemble_aliases (alias); + } +} + /* Output one variable, if necessary. Return whether we output it. */ bool varpool_assemble_decl (struct varpool_node *node) @@ -472,25 +565,13 @@ varpool_assemble_decl (struct varpool_node *node) assemble_variable (decl, 0, 1, 0); if (TREE_ASM_WRITTEN (decl)) { - struct varpool_node *alias; - node->next_needed = varpool_assembled_nodes_queue; node->prev_needed = NULL; if (varpool_assembled_nodes_queue) varpool_assembled_nodes_queue->prev_needed = node; varpool_assembled_nodes_queue = node; node->finalized = 1; - - /* Also emit any extra name aliases. */ - for (alias = node->extra_name; alias; alias = alias->next) - { - /* Update linkage fields in case they've changed. */ - DECL_WEAK (alias->decl) = DECL_WEAK (decl); - TREE_PUBLIC (alias->decl) = TREE_PUBLIC (decl); - DECL_VISIBILITY (alias->decl) = DECL_VISIBILITY (decl); - assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl)); - } - + assemble_aliases (node); return true; } } @@ -517,18 +598,14 @@ varpool_remove_unreferenced_decls (void) while (node) { - tree decl = node->decl; next = node->next_needed; node->needed = 0; - if (node->finalized - && (decide_is_variable_needed (node, decl) - /* ??? Cgraph does not yet rule the world with an iron hand, - and does not control the emission of debug information. - After a variable has its DECL_RTL set, we must assume that - it may be referenced by the debug information, and we can - no longer elide it. */ - || DECL_RTL_SET_P (decl))) + if (node->analyzed + && (!varpool_can_remove_if_no_refs (node) + /* We just expanded all function bodies. See if any of + them needed the variable. */ + || DECL_RTL_SET_P (node->decl))) varpool_mark_needed_node (node); node = next; @@ -538,11 +615,29 @@ varpool_remove_unreferenced_decls (void) varpool_analyze_pending_decls (); } +/* For variables in named sections make sure get_variable_section + is called before we switch to those sections. Then section + conflicts between read-only and read-only requiring relocations + sections can be resolved. */ +void +varpool_finalize_named_section_flags (struct varpool_node *node) +{ + if (!TREE_ASM_WRITTEN (node->decl) + && !node->alias + && !node->in_other_partition + && !DECL_EXTERNAL (node->decl) + && TREE_CODE (node->decl) == VAR_DECL + && !DECL_HAS_VALUE_EXPR_P (node->decl) + && DECL_SECTION_NAME (node->decl)) + get_variable_section (node->decl, false); +} + /* Output all variables enqueued to be assembled. */ bool varpool_assemble_pending_decls (void) { bool changed = false; + struct varpool_node *node; if (seen_error ()) return false; @@ -553,6 +648,9 @@ varpool_assemble_pending_decls (void) elsewhere. */ varpool_analyze_pending_decls (); + for (node = varpool_nodes_queue; node; node = node->next_needed) + varpool_finalize_named_section_flags (node); + while (varpool_nodes_queue) { struct varpool_node *node = varpool_nodes_queue; @@ -621,40 +719,80 @@ add_new_static_var (tree type) /* Attempt to mark ALIAS as an alias to DECL. Return TRUE if successful. Extra name aliases are output whenever DECL is output. */ -bool +struct varpool_node * +varpool_create_variable_alias (tree alias, tree decl) +{ + struct varpool_node *alias_node; + + gcc_assert (TREE_CODE (decl) == VAR_DECL); + gcc_assert (TREE_CODE (alias) == VAR_DECL); + alias_node = varpool_node (alias); + alias_node->alias = 1; + if (!DECL_EXTERNAL (alias)) + alias_node->finalized = 1; + alias_node->alias_of = decl; + if ((!DECL_EXTERNAL (alias) + && decide_is_variable_needed (alias_node, alias)) + || alias_node->needed) + varpool_mark_needed_node (alias_node); + return alias_node; +} + +/* Attempt to mark ALIAS as an alias to DECL. Return TRUE if successful. + Extra name aliases are output whenever DECL is output. */ + +struct varpool_node * varpool_extra_name_alias (tree alias, tree decl) { - struct varpool_node key, *alias_node, *decl_node, **slot; + struct varpool_node *alias_node; #ifndef ASM_OUTPUT_DEF /* If aliases aren't supported by the assembler, fail. */ - return false; + return NULL; #endif + alias_node = varpool_create_variable_alias (alias, decl); + alias_node->extra_name_alias = true; + return alias_node; +} - gcc_assert (TREE_CODE (decl) == VAR_DECL); - gcc_assert (TREE_CODE (alias) == VAR_DECL); - /* Make sure the hash table has been created. */ - decl_node = varpool_node (decl); +/* Return true when NODE is known to be used from other (non-LTO) object file. + Known only when doing LTO via linker plugin. */ - key.decl = alias; +bool +varpool_used_from_object_file_p (struct varpool_node *node) +{ + if (!TREE_PUBLIC (node->decl)) + return false; + if (resolution_used_from_other_file_p (node->resolution)) + return true; + return false; +} - slot = (struct varpool_node **) htab_find_slot (varpool_hash, &key, INSERT); +/* Call calback on NODE and aliases asociated to NODE. + When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are + skipped. */ - /* If the varpool_node has been already created, fail. */ - if (*slot) - return false; +bool +varpool_for_node_and_aliases (struct varpool_node *node, + bool (*callback) (struct varpool_node *, void *), + void *data, + bool include_overwritable) +{ + int i; + struct ipa_ref *ref; - alias_node = ggc_alloc_cleared_varpool_node (); - alias_node->decl = alias; - alias_node->alias = 1; - alias_node->extra_name = decl_node; - alias_node->next = decl_node->extra_name; - ipa_empty_ref_list (&alias_node->ref_list); - if (decl_node->extra_name) - decl_node->extra_name->prev = alias_node; - decl_node->extra_name = alias_node; - *slot = alias_node; - return true; + if (callback (node, data)) + return true; + for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct varpool_node *alias = ipa_ref_refering_varpool_node (ref); + if (include_overwritable + || cgraph_variable_initializer_availability (alias) > AVAIL_OVERWRITABLE) + if (varpool_for_node_and_aliases (alias, callback, data, + include_overwritable)) + return true; + } + return false; } - #include "gt-varpool.h"