OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / cgraph.c
index 4dffdc4..78e131b 100644 (file)
@@ -110,7 +110,8 @@ const char * const ld_plugin_symbol_resolution_names[]=
   "preempted_ir",
   "resolved_ir",
   "resolved_exec",
-  "resolved_dyn"
+  "resolved_dyn",
+  "prevailing_def_ironly_exp"
 };
 
 static void cgraph_node_remove_callers (struct cgraph_node *node);
@@ -208,6 +209,9 @@ static GTY(()) struct cgraph_node *free_nodes;
    Do not GTY((delete)) this list so UIDs gets reliably recycled.  */
 static GTY(()) struct cgraph_edge *free_edges;
 
+/* Did procss_same_body_aliases run?  */
+bool same_body_aliases_done;
+
 /* Macros to access the next item in the list of free cgraph nodes and
    edges. */
 #define NEXT_FREE_NODE(NODE) (NODE)->next
@@ -408,7 +412,7 @@ cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *entry)
 }
 
 /* Call all node duplication hooks.  */
-static void
+void
 cgraph_call_node_duplication_hooks (struct cgraph_node *node1,
                                    struct cgraph_node *node2)
 {
@@ -542,33 +546,23 @@ cgraph_get_create_node (tree decl)
 /* Mark ALIAS as an alias to DECL.  DECL_NODE is cgraph node representing
    the function body is associated with (not neccesarily cgraph_node (DECL).  */
 
-static struct cgraph_node *
-cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl)
+struct cgraph_node *
+cgraph_create_function_alias (tree alias, tree decl)
 {
-  struct cgraph_node key, *alias_node, **slot;
+  struct cgraph_node *alias_node;
 
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
   gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
-
-  key.decl = alias;
-
-  slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
-
-  /* If the cgraph_node has been already created, fail.  */
-  if (*slot)
-    return NULL;
-
-  alias_node = cgraph_allocate_node ();
-  alias_node->decl = alias;
-  alias_node->same_body_alias = 1;
-  alias_node->same_body = decl_node;
-  alias_node->previous = NULL;
-  if (decl_node->same_body)
-    decl_node->same_body->previous = alias_node;
-  alias_node->next = decl_node->same_body;
+  alias_node = cgraph_get_create_node (alias);
+  gcc_assert (!alias_node->local.finalized);
   alias_node->thunk.alias = decl;
-  decl_node->same_body = alias_node;
-  *slot = alias_node;
+  alias_node->local.finalized = true;
+  alias_node->alias = 1;
+
+  if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias))
+      || (DECL_VIRTUAL_P (alias)
+         && (DECL_COMDAT (alias) || DECL_EXTERNAL (alias))))
+    cgraph_mark_reachable_node (alias_node);
   return alias_node;
 }
 
@@ -578,16 +572,24 @@ cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl)
    and cgraph_get_node (ALIAS) transparently returns cgraph_get_node (DECL).  */
 
 struct cgraph_node *
-cgraph_same_body_alias (struct cgraph_node *decl_node, tree alias, tree decl)
+cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree alias, tree decl)
 {
+  struct cgraph_node *n;
 #ifndef ASM_OUTPUT_DEF
   /* If aliases aren't supported by the assembler, fail.  */
   return NULL;
 #endif
+  /* Langhooks can create same body aliases of symbols not defined.
+     Those are useless. Drop them on the floor.  */
+  if (cgraph_global_info_ready)
+    return NULL;
 
-  /*gcc_assert (!assembler_name_hash);*/
-
-  return cgraph_same_body_alias_1 (decl_node, alias, decl);
+  n = cgraph_create_function_alias (alias, decl);
+  n->same_body_alias = true;
+  if (same_body_aliases_done)
+    ipa_record_reference (n, NULL, cgraph_get_node (decl), NULL, IPA_REF_ALIAS,
+                         NULL);
+  return n;
 }
 
 /* Add thunk alias into callgraph.  The alias declaration is ALIAS and it
@@ -633,29 +635,7 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED,
       || (DECL_VIRTUAL_P (decl)
          && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
     cgraph_mark_reachable_node (node);
-  return node;
-}
-
-/* Returns the cgraph node assigned to DECL or NULL if no cgraph node
-   is assigned.  */
-
-struct cgraph_node *
-cgraph_get_node_or_alias (const_tree decl)
-{
-  struct cgraph_node key, *node = NULL, **slot;
-
-  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
-
-  if (!cgraph_hash)
-    return NULL;
-
-  key.decl = CONST_CAST2 (tree, const_tree, decl);
 
-  slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key,
-                                                NO_INSERT);
-
-  if (slot && *slot)
-    node = *slot;
   return node;
 }
 
@@ -678,11 +658,7 @@ cgraph_get_node (const_tree decl)
                                                 NO_INSERT);
 
   if (slot && *slot)
-    {
-      node = *slot;
-      if (node->same_body_alias)
-       node = node->same_body;
-    }
+    node = *slot;
   return node;
 }
 
@@ -745,21 +721,6 @@ cgraph_node_for_asm (tree asmname)
               so lets hope for the best.  */
            if (!*slot)
              *slot = node;
-           if (node->same_body)
-             {
-               struct cgraph_node *alias;
-
-               for (alias = node->same_body; alias; alias = alias->next)
-                 {
-                   hashval_t hash;
-                   name = DECL_ASSEMBLER_NAME (alias->decl);
-                   hash = decl_assembler_name_hash (name);
-                   slot = htab_find_slot_with_hash (assembler_name_hash, name,
-                                                    hash,  INSERT);
-                   if (!*slot)
-                     *slot = alias;
-                 }
-             }
          }
     }
 
@@ -770,8 +731,6 @@ cgraph_node_for_asm (tree asmname)
   if (slot)
     {
       node = (struct cgraph_node *) *slot;
-      if (node->same_body_alias)
-       node = node->same_body;
       return node;
     }
   return NULL;
@@ -877,7 +836,7 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt)
       struct cgraph_node *new_callee = cgraph_get_node (decl);
 
       gcc_checking_assert (new_callee);
-      cgraph_make_edge_direct (e, new_callee, 0);
+      cgraph_make_edge_direct (e, new_callee);
     }
 
   push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
@@ -1029,8 +988,12 @@ cgraph_create_edge_1 (struct cgraph_node *caller, struct cgraph_node *callee,
   edge->can_throw_external
     = call_stmt ? stmt_can_throw_external (call_stmt) : false;
   pop_cfun ();
-  edge->call_stmt_cannot_inline_p =
-    (call_stmt ? gimple_call_cannot_inline_p (call_stmt) : false);
+  if (call_stmt
+      && callee && callee->decl
+      && !gimple_check_call_matching_types (call_stmt, callee->decl))
+    edge->call_stmt_cannot_inline_p = true;
+  else
+    edge->call_stmt_cannot_inline_p = false;
   if (call_stmt && caller->call_site_hash)
     cgraph_add_edge_to_call_site_hash (edge);
 
@@ -1203,11 +1166,9 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n)
    pointer (first parameter) to compensate for skipping a thunk adjustment.  */
 
 void
-cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee,
-                        HOST_WIDE_INT delta)
+cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee)
 {
   edge->indirect_unknown_callee = 0;
-  edge->indirect_info->thunk_delta = delta;
 
   /* Get the edge out of the indirect edge list. */
   if (edge->prev_callee)
@@ -1227,6 +1188,10 @@ cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee,
   /* Insert to callers list of the new callee.  */
   cgraph_set_edge_callee (edge, callee);
 
+  if (edge->call_stmt)
+    edge->call_stmt_cannot_inline_p
+      = !gimple_check_call_matching_types (edge->call_stmt, callee->decl);
+
   /* We need to re-determine the inlining status of the edge.  */
   initialize_inline_failed (edge);
 }
@@ -1432,44 +1397,6 @@ cgraph_release_function_body (struct cgraph_node *node)
     DECL_INITIAL (node->decl) = error_mark_node;
 }
 
-/* Remove same body alias node.  */
-
-void
-cgraph_remove_same_body_alias (struct cgraph_node *node)
-{
-  void **slot;
-  int uid = node->uid;
-
-  gcc_assert (node->same_body_alias);
-  if (node->previous)
-    node->previous->next = node->next;
-  else
-    node->same_body->same_body = node->next;
-  if (node->next)
-    node->next->previous = node->previous;
-  node->next = NULL;
-  node->previous = NULL;
-  slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
-  if (*slot == node)
-    htab_clear_slot (cgraph_hash, slot);
-  if (assembler_name_hash)
-    {
-      tree name = DECL_ASSEMBLER_NAME (node->decl);
-      slot = htab_find_slot_with_hash (assembler_name_hash, name,
-                                      decl_assembler_name_hash (name),
-                                      NO_INSERT);
-      if (slot && *slot == node)
-       htab_clear_slot (assembler_name_hash, slot);
-    }
-
-  /* Clear out the node to NULL all pointers and add the node to the free
-     list.  */
-  memset (node, 0, sizeof(*node));
-  node->uid = uid;
-  NEXT_FREE_NODE (node) = free_nodes;
-  free_nodes = node;
-}
-
 /* Remove the node from cgraph.  */
 
 void
@@ -1631,9 +1558,6 @@ cgraph_remove_node (struct cgraph_node *node)
        }
     }
 
-  while (node->same_body)
-    cgraph_remove_same_body_alias (node->same_body);
-
   if (node->same_comdat_group)
     {
       struct cgraph_node *prev;
@@ -1690,6 +1614,31 @@ cgraph_remove_node (struct cgraph_node *node)
   free_nodes = node;
 }
 
+/* Add NEW_ to the same comdat group that OLD is in.  */
+
+void
+cgraph_add_to_same_comdat_group (struct cgraph_node *new_,
+                                struct cgraph_node *old)
+{
+  gcc_assert (DECL_ONE_ONLY (old->decl));
+  gcc_assert (!new_->same_comdat_group);
+  gcc_assert (new_ != old);
+
+  DECL_COMDAT_GROUP (new_->decl) = DECL_COMDAT_GROUP (old->decl);
+  new_->same_comdat_group = old;
+  if (!old->same_comdat_group)
+    old->same_comdat_group = new_;
+  else
+    {
+      struct cgraph_node *n;
+      for (n = old->same_comdat_group;
+          n->same_comdat_group != old;
+          n = n->same_comdat_group)
+       ;
+      n->same_comdat_group = new_;
+    }
+}
+
 /* Remove the node from cgraph.  */
 
 void
@@ -1747,6 +1696,14 @@ cgraph_mark_address_taken_node (struct cgraph_node *node)
 {
   gcc_assert (!node->global.inlined_to);
   cgraph_mark_reachable_node (node);
+  /* FIXME: address_taken flag is used both as a shortcut for testing whether
+     IPA_REF_ADDR reference exists (and thus it should be set on node
+     representing alias we take address of) and as a test whether address
+     of the object was taken (and thus it should be set on node alias is
+     referring to).  We should remove the first use and the remove the
+     following set.  */
+  node->address_taken = 1;
+  node = cgraph_function_or_thunk_node (node, NULL);
   node->address_taken = 1;
 }
 
@@ -1889,6 +1846,10 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
     fprintf (f, " only_called_at_startup");
   if (node->only_called_at_exit)
     fprintf (f, " only_called_at_exit");
+  else if (node->alias)
+    fprintf (f, " alias");
+  if (node->tm_clone)
+    fprintf (f, " tm_clone");
 
   fprintf (f, "\n");
 
@@ -1902,6 +1863,15 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
               (int)node->thunk.virtual_value,
               (int)node->thunk.virtual_offset_p);
     }
+  if (node->alias && node->thunk.alias)
+    {
+      fprintf (f, "  alias of %s",
+              lang_hooks.decl_printable_name (node->thunk.alias, 2));
+      if (DECL_ASSEMBLER_NAME_SET_P (node->thunk.alias))
+        fprintf (f, " (asm: %s)",
+                IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias)));
+      fprintf (f, "\n");
+    }
   
   fprintf (f, "  called by: ");
 
@@ -1952,19 +1922,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
   if (indirect_calls_count)
     fprintf (f, "  has %i outgoing edges for indirect calls.\n",
             indirect_calls_count);
-
-  if (node->same_body)
-    {
-      struct cgraph_node *n;
-      fprintf (f, "  aliases:");
-      for (n = node->same_body; n; n = n->next)
-        {
-          fprintf (f, " %s/%i", cgraph_node_name (n), n->uid);
-         if (DECL_ASSEMBLER_NAME_SET_P (n->decl))
-           fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
-       }
-      fprintf (f, "\n");
-    }
 }
 
 
@@ -2015,7 +1972,7 @@ change_decl_assembler_name (tree decl, tree name)
 
       if (assembler_name_hash
          && TREE_CODE (decl) == FUNCTION_DECL
-         && (node = cgraph_get_node_or_alias (decl)) != NULL)
+         && (node = cgraph_get_node (decl)) != NULL)
        {
          tree old_name = DECL_ASSEMBLER_NAME (decl);
          slot = htab_find_slot_with_hash (assembler_name_hash, old_name,
@@ -2033,7 +1990,7 @@ change_decl_assembler_name (tree decl, tree name)
     }
   if (assembler_name_hash
       && TREE_CODE (decl) == FUNCTION_DECL
-      && (node = cgraph_get_node_or_alias (decl)) != NULL)
+      && (node = cgraph_get_node (decl)) != NULL)
     {
       slot = htab_find_slot_with_hash (assembler_name_hash, name,
                                       decl_assembler_name_hash (name),
@@ -2289,7 +2246,7 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
   if (!args_to_skip)
     new_decl = copy_node (old_decl);
   else
-    new_decl = build_function_decl_skip_args (old_decl, args_to_skip);
+    new_decl = build_function_decl_skip_args (old_decl, args_to_skip, false);
   DECL_STRUCT_FUNCTION (new_decl) = NULL;
 
   /* Generate a new name for the new version. */
@@ -2312,6 +2269,7 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
   TREE_PUBLIC (new_node->decl) = 0;
   DECL_COMDAT (new_node->decl) = 0;
   DECL_WEAK (new_node->decl) = 0;
+  DECL_VIRTUAL_P (new_node->decl) = 0;
   DECL_STATIC_CONSTRUCTOR (new_node->decl) = 0;
   DECL_STATIC_DESTRUCTOR (new_node->decl) = 0;
   new_node->clone.tree_map = tree_map;
@@ -2543,7 +2501,7 @@ cgraph_make_decl_local (tree decl)
     DECL_COMMON (decl) = 0;
   else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
 
-  if (DECL_COMDAT (decl))
+  if (DECL_ONE_ONLY (decl) || 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
@@ -2556,7 +2514,7 @@ cgraph_make_decl_local (tree decl)
          old_name  = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
          if (TREE_CODE (decl) == FUNCTION_DECL)
            {
-             struct cgraph_node *node = cgraph_get_node_or_alias (decl);
+             struct cgraph_node *node = cgraph_get_node (decl);
              change_decl_assembler_name (decl,
                                          clone_function_name (decl, "local"));
              if (node->local.lto_file_data)
@@ -2614,18 +2572,28 @@ cgraph_for_node_thunks_and_aliases (struct cgraph_node *node,
                                    bool include_overwritable)
 {
   struct cgraph_edge *e;
-  struct cgraph_node *alias;
+  int i;
+  struct ipa_ref *ref;
 
   if (callback (node, data))
     return true;
-  for (alias = node->same_body; alias; alias = alias->next)
-    if (callback (alias, data))
-      return true;
   for (e = node->callers; e; e = e->next_caller)
     if (e->caller->thunk.thunk_p
        && (include_overwritable
            || cgraph_function_body_availability (e->caller) > AVAIL_OVERWRITABLE))
-      cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable);
+      if (cgraph_for_node_thunks_and_aliases (e->caller, callback, data,
+                                             include_overwritable))
+       return true;
+  for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
+    if (ref->use == IPA_REF_ALIAS)
+      {
+       struct cgraph_node *alias = ipa_ref_refering_node (ref);
+       if (include_overwritable
+           || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
+         if (cgraph_for_node_thunks_and_aliases (alias, callback, data,
+                                                 include_overwritable))
+           return true;
+      }
   return false;
 }
 
@@ -2637,15 +2605,23 @@ bool
 cgraph_for_node_and_aliases (struct cgraph_node *node,
                             bool (*callback) (struct cgraph_node *, void *),
                             void *data,
-                            bool include_overwritable ATTRIBUTE_UNUSED)
+                            bool include_overwritable)
 {
-  struct cgraph_node *alias;
+  int i;
+  struct ipa_ref *ref;
 
   if (callback (node, data))
     return true;
-  for (alias = node->same_body; alias; alias = alias->next)
-    if (callback (alias, data))
-      return true;
+  for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
+    if (ref->use == IPA_REF_ALIAS)
+      {
+       struct cgraph_node *alias = ipa_ref_refering_node (ref);
+       if (include_overwritable
+           || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
+          if (cgraph_for_node_and_aliases (alias, callback, data,
+                                          include_overwritable))
+           return true;
+      }
   return false;
 }
 
@@ -2681,7 +2657,13 @@ cgraph_make_node_local (struct cgraph_node *node)
 static bool
 cgraph_set_nothrow_flag_1 (struct cgraph_node *node, void *data)
 {
+  struct cgraph_edge *e;
+
   TREE_NOTHROW (node->decl) = data != NULL;
+
+  if (data != NULL)
+    for (e = node->callers; e; e = e->next_caller)
+      e->can_throw_external = false;
   return false;
 }
 
@@ -2938,6 +2920,36 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
   return true;
 }
 
+/* Worker for cgraph_can_remove_if_no_direct_calls_p.  */
+
+static bool
+nonremovable_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+  return !cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
+}
+
+/* Return true when function NODE and its aliases can be removed from callgraph
+   if all direct calls are eliminated.  */
+
+bool
+cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
+{
+  /* Extern inlines can always go, we will use the external definition.  */
+  if (DECL_EXTERNAL (node->decl))
+    return true;
+  if (node->address_taken)
+    return false;
+  return !cgraph_for_node_and_aliases (node, nonremovable_p, NULL, true);
+}
+
+/* Worker for cgraph_can_remove_if_no_direct_calls_p.  */
+
+static bool
+used_from_object_file_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+  return cgraph_used_from_object_file_p (node);
+}
+
 /* Return true when function NODE can be expected to be removed
    from program when direct calls in this compilation unit are removed.
 
@@ -2956,7 +2968,7 @@ bool
 cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node)
 {
   gcc_assert (!node->global.inlined_to);
-  if (cgraph_used_from_object_file_p (node))
+  if (cgraph_for_node_and_aliases (node, used_from_object_file_p, NULL, true))
     return false;
   if (!in_lto_p && !flag_whole_program)
     return cgraph_only_called_directly_p (node);