diff options
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r-- | gcc/cgraph.c | 141 |
1 files changed, 124 insertions, 17 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c index aaa50b607d2..63fed497b47 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -97,6 +97,7 @@ The callgraph: #include "diagnostic-core.h" #include "rtl.h" #include "ipa-utils.h" +#include "lto-streamer.h" static void cgraph_node_remove_callers (struct cgraph_node *node); static inline void cgraph_edge_remove_caller (struct cgraph_edge *e); @@ -604,6 +605,29 @@ cgraph_add_thunk (tree alias, tree decl, bool this_adjusting, is assigned. */ struct cgraph_node * +cgraph_get_node_or_alias (tree decl) +{ + struct cgraph_node key, *node = NULL, **slot; + + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); + + if (!cgraph_hash) + return NULL; + + key.decl = decl; + + slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, + NO_INSERT); + + if (slot && *slot) + node = *slot; + return node; +} + +/* Returns the cgraph node assigned to DECL or NULL if no cgraph node + is assigned. */ + +struct cgraph_node * cgraph_get_node (tree decl) { struct cgraph_node key, *node = NULL, **slot; @@ -1952,20 +1976,43 @@ debug_cgraph (void) void change_decl_assembler_name (tree decl, tree name) { - gcc_assert (!assembler_name_hash); + struct cgraph_node *node; + void **slot; if (!DECL_ASSEMBLER_NAME_SET_P (decl)) + SET_DECL_ASSEMBLER_NAME (decl, name); + else { - SET_DECL_ASSEMBLER_NAME (decl, name); - return; - } - if (name == DECL_ASSEMBLER_NAME (decl)) - return; + if (name == DECL_ASSEMBLER_NAME (decl)) + return; - if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - && DECL_RTL_SET_P (decl)) - warning (0, "%D renamed after being referenced in assembly", decl); + if (assembler_name_hash + && TREE_CODE (decl) == FUNCTION_DECL + && (node = cgraph_get_node_or_alias (decl)) != NULL) + { + tree old_name = DECL_ASSEMBLER_NAME (decl); + slot = htab_find_slot_with_hash (assembler_name_hash, old_name, + decl_assembler_name_hash (old_name), + NO_INSERT); + /* Inline clones are not hashed. */ + if (slot && *slot == node) + htab_clear_slot (assembler_name_hash, slot); + } + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + && DECL_RTL_SET_P (decl)) + warning (0, "%D renamed after being referenced in assembly", decl); - SET_DECL_ASSEMBLER_NAME (decl, name); + SET_DECL_ASSEMBLER_NAME (decl, name); + } + if (assembler_name_hash + && TREE_CODE (decl) == FUNCTION_DECL + && (node = cgraph_get_node_or_alias (decl)) != NULL) + { + slot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + INSERT); + gcc_assert (!*slot); + *slot = node; + } } /* Add a top-level asm statement to the list. */ @@ -2255,7 +2302,7 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, struct cgraph_node *orig_node; for (orig_node = old_node; orig_node->clone_of; orig_node = orig_node->clone_of) ; - for (arg = DECL_ARGUMENTS (orig_node->decl); arg; arg = TREE_CHAIN (arg), oldi++) + for (arg = DECL_ARGUMENTS (orig_node->decl); arg; arg = DECL_CHAIN (arg), oldi++) { if (bitmap_bit_p (old_node->clone.combined_args_to_skip, oldi)) { @@ -2432,15 +2479,50 @@ cgraph_make_decl_local (tree decl) if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; - else if (TREE_CODE (decl) == FUNCTION_DECL) + else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); + + if (DECL_COMDAT (decl)) { + /* It is possible that we are linking against library defining same COMDAT + function. To avoid conflict we need to rename our local name of the + function just in the case WHOPR partitioning decide to make it hidden + to avoid cross partition references. */ + if (flag_wpa) + { + const char *old_name; + + old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + if (TREE_CODE (decl) == FUNCTION_DECL) + { + struct cgraph_node *node = cgraph_get_node_or_alias (decl); + change_decl_assembler_name (decl, + clone_function_name (decl, "local")); + if (node->local.lto_file_data) + lto_record_renamed_decl (node->local.lto_file_data, + old_name, + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (decl))); + } + else if (TREE_CODE (decl) == VAR_DECL) + { + struct varpool_node *vnode = varpool_get_node (decl); + /* change_decl_assembler_name will warn here on vtables because + C++ frontend still sets TREE_SYMBOL_REFERENCED on them. */ + SET_DECL_ASSEMBLER_NAME (decl, + clone_function_name (decl, "local")); + if (vnode->lto_file_data) + lto_record_renamed_decl (vnode->lto_file_data, + old_name, + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (decl))); + } + } + DECL_SECTION_NAME (decl) = 0; DECL_COMDAT (decl) = 0; - DECL_COMDAT_GROUP (decl) = 0; - DECL_WEAK (decl) = 0; - DECL_EXTERNAL (decl) = 0; } - else - gcc_unreachable (); + DECL_COMDAT_GROUP (decl) = 0; + DECL_WEAK (decl) = 0; + DECL_EXTERNAL (decl) = 0; TREE_PUBLIC (decl) = 0; if (!DECL_RTL_SET_P (decl)) return; @@ -2627,4 +2709,29 @@ cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e) return cgraph_node_cannot_return (e->callee); } +/* Return true when function NODE can be excpected to be removed + from program when direct calls in this compilation unit are removed. + + As a special case COMDAT functions are + cgraph_can_remove_if_no_direct_calls_p while the are not + cgraph_only_called_directly_p (it is possible they are called from other + unit) + + This function behaves as cgraph_only_called_directly_p because eliminating + all uses of COMDAT function does not make it neccesarily disappear from + the program unless we are compiling whole program or we do LTO. In this + case we know we win since dynamic linking will not really discard the + linkonce section. */ + +bool +cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node) +{ + if (node->local.used_from_object_file) + return false; + if (!in_lto_p && !flag_whole_program) + return cgraph_only_called_directly_p (node); + else + return cgraph_can_remove_if_no_direct_calls_p (node); +} + #include "gt-cgraph.h" |