summaryrefslogtreecommitdiff
path: root/gcc/cgraph.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r--gcc/cgraph.c141
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"