lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code.
authorJan Hubicka <jh@suse.cz>
Sat, 11 Jun 2011 13:01:53 +0000 (15:01 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 11 Jun 2011 13:01:53 +0000 (13:01 +0000)
* lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code.
(lto_symtab_resolve_can_prevail_p): Likewise.
(lto_symtab_merge_cgraph_nodes): Update merging of aliases.
* cgraph.c (same_body_aliases_done): New global var.
(cgraph_same_body_alias_1): Rename to ...
(cgraph_create_function_alias): ... this one; reorg to new
representation.
(cgraph_same_body_alias): Use cgraph_create_function_alias;
record references when asked to.
(cgraph_add_thunk): Fix formating.
(cgraph_get_node): Kill same body alias code.
(cgraph_node_for_asm): Likewise.
(cgraph_remove_same_body_alias): Remove.
(cgraph_remove_node): Kill same body alias code.
(cgraph_mark_address_taken_node): Mark also the aliased function
as having address taken.
(dump_cgraph_node): Dump same body aliases.
(cgraph_for_node_thunks_and_aliases): Update for new alias
representation.
(cgraph_for_node_and_aliases): Likewise.
* cgraph.h (same_body): Kll pointer.
(same_body_alias): Update comment.
(same_body_aliases_done): Declare.
(cgraph_remove_same_body_alias): Remove declaration.
(cgraph_create_function_alias): Declare.
(cgraph_process_same_body_aliases): Declare.
(cgraph_function_with_gimple_body_p): Check for alias.
(cgraph_can_remove_if_no_direct_calls_p): Look for aliases.
(cgraph_alias_aliased_node): New function.
(cgraph_function_node): Update for new aliases.
(cgraph_function_or_thunk_node): Likewise.
* ipa-inline-transform.c (can_remove_node_now_p): Look for aliases.
(inline_call): Remove dead aliases.
* cgraphunit.c (cgraph_decide_is_function_needed): Disable assembler name
hack for same body aliases.
(clone_of_p): Look through aliases.
(verify_cgraph_node): Verify aliases.
(cgraph_analyze_function): Analyze aliases; fixup C++ bugs.
(cgraph_process_same_body_aliases): New function.
(process_function_and_variable_attributes): Disable weakref warning on
alias.
(cgraph_analyze_functions): Handle aliases.
(cgraph_mark_functions_to_output): Handle aliases same way as thunks.
(assemble_thunks): Rename to ...
(assemble_thunks_and_aliases): ... this one; handle aliases, too.
(cgraph_expand_function): Remove alias output code.
(cgraph_output_in_order): Skip aliases.
(cgraph_preserve_function_body_p): Aliases don't need preserving.
* ipa-ref.c (ipa_ref_use_name): Add alias reference.
(ipa_record_reference): Do not assert on alias references.
(ipa_ref_has_aliases_p): New function.
* ipa-ref.h (enum ipa_ref_use): Add IPA_REF_ALIAS.
(ipa_ref_has_aliases_p): Declare.
* lto-cgraph.c (lto_output_node): Handle aliases.
(input_node): Likewise.
* lto-streamer-out.c (lto_output): Skip aliases.
(produce_symtab): Kill same_body_alias code.
* ipa-utils.c (ipa_reverse_postorder): Add FIXME.
(ipa_reverse_postorder): Use cgraph_only_called_directly_or_aliased_p.
* ipa-inline.c (update_caller_keys): Walk aliases.
(inline_small_functions): Fix thinko in previous patch.
* ipa.c (cgraph_externally_visible_p): Do not walk aliases.
(function_and_variable_visibility): Do not walk same body aliases.
* tree-ssa-structalias.c (associate_varinfo_to_alias): New function.
(ipa_pta_execute): Use it.

* lto.c (add_cgraph_node_to_partition_1): Break out from ...
(add_cgraph_node_to_partition) ... here; walk aliases.
(lto_1_to_1_map): Remove same body alias code.
(promote_fn): Likewise.
(lto_promote_cross_file_statics): Update comment.

* decl2.c (cp_write_global_declarations): Process aliases; look trhough
same body aliases.

From-SVN: r174952

19 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/cp/ChangeLog
gcc/cp/decl2.c
gcc/cp/tree.c
gcc/ipa-inline-transform.c
gcc/ipa-inline.c
gcc/ipa-ref.c
gcc/ipa-ref.h
gcc/ipa-utils.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto-streamer-out.c
gcc/lto-symtab.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/tree-ssa-structalias.c

index 1a141e3c160a4bef998d3e7c7c265c6dc851dc17..73c5fb46a871d994df39fad2b92b364be589ae0c 100644 (file)
@@ -1,3 +1,71 @@
+2011-06-11  Jan Hubicka  <jh@suse.cz>
+
+       * lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code.
+       (lto_symtab_resolve_can_prevail_p): Likewise.
+       (lto_symtab_merge_cgraph_nodes): Update merging of aliases.
+       * cgraph.c (same_body_aliases_done): New global var.
+       (cgraph_same_body_alias_1): Rename to ...
+       (cgraph_create_function_alias): ... this one; reorg to new
+       representation.
+       (cgraph_same_body_alias): Use cgraph_create_function_alias;
+       record references when asked to.
+       (cgraph_add_thunk): Fix formating.
+       (cgraph_get_node): Kill same body alias code.
+       (cgraph_node_for_asm): Likewise.
+       (cgraph_remove_same_body_alias): Remove.
+       (cgraph_remove_node): Kill same body alias code.
+       (cgraph_mark_address_taken_node): Mark also the aliased function
+       as having address taken.
+       (dump_cgraph_node): Dump same body aliases.
+       (cgraph_for_node_thunks_and_aliases): Update for new alias
+       representation.
+       (cgraph_for_node_and_aliases): Likewise.
+       * cgraph.h (same_body): Kll pointer.
+       (same_body_alias): Update comment.
+       (same_body_aliases_done): Declare.
+       (cgraph_remove_same_body_alias): Remove declaration.
+       (cgraph_create_function_alias): Declare.
+       (cgraph_process_same_body_aliases): Declare.
+       (cgraph_function_with_gimple_body_p): Check for alias.
+       (cgraph_can_remove_if_no_direct_calls_p): Look for aliases.
+       (cgraph_alias_aliased_node): New function.
+       (cgraph_function_node): Update for new aliases.
+       (cgraph_function_or_thunk_node): Likewise.
+       * ipa-inline-transform.c (can_remove_node_now_p): Look for aliases.
+       (inline_call): Remove dead aliases.
+       * cgraphunit.c (cgraph_decide_is_function_needed): Disable assembler name
+       hack for same body aliases.
+       (clone_of_p): Look through aliases.
+       (verify_cgraph_node): Verify aliases.
+       (cgraph_analyze_function): Analyze aliases; fixup C++ bugs.
+       (cgraph_process_same_body_aliases): New function.
+       (process_function_and_variable_attributes): Disable weakref warning on
+       alias.
+       (cgraph_analyze_functions): Handle aliases.
+       (cgraph_mark_functions_to_output): Handle aliases same way as thunks.
+       (assemble_thunks): Rename to ...
+       (assemble_thunks_and_aliases): ... this one; handle aliases, too.
+       (cgraph_expand_function): Remove alias output code.
+       (cgraph_output_in_order): Skip aliases.
+       (cgraph_preserve_function_body_p): Aliases don't need preserving.
+       * ipa-ref.c (ipa_ref_use_name): Add alias reference.
+       (ipa_record_reference): Do not assert on alias references.
+       (ipa_ref_has_aliases_p): New function.
+       * ipa-ref.h (enum ipa_ref_use): Add IPA_REF_ALIAS.
+       (ipa_ref_has_aliases_p): Declare.
+       * lto-cgraph.c (lto_output_node): Handle aliases.
+       (input_node): Likewise.
+       * lto-streamer-out.c (lto_output): Skip aliases.
+       (produce_symtab): Kill same_body_alias code.
+       * ipa-utils.c (ipa_reverse_postorder): Add FIXME.
+       (ipa_reverse_postorder): Use cgraph_only_called_directly_or_aliased_p.
+       * ipa-inline.c (update_caller_keys): Walk aliases.
+       (inline_small_functions): Fix thinko in previous patch.
+       * ipa.c (cgraph_externally_visible_p): Do not walk aliases.
+       (function_and_variable_visibility): Do not walk same body aliases.
+       * tree-ssa-structalias.c (associate_varinfo_to_alias): New function.
+       (ipa_pta_execute): Use it.
+
 2011-06-11  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/sse.md (vec_dupv4sf): Correct mode of forced register.
index f5fd150baac96fccb6e6d9442aa37a9621174b89..2805d46dfadc403fe9c843cf18668e528bc08932 100644 (file)
@@ -208,6 +208,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
@@ -542,33 +545,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 +571,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,6 +634,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;
 }
 
@@ -678,11 +680,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 +743,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 +753,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;
@@ -1432,44 +1413,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 +1574,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;
@@ -1747,6 +1687,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;
 }
 
@@ -1902,6 +1850,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 +1909,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");
-    }
 }
 
 
@@ -2614,18 +2558,24 @@ 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_function_body_availability (e->caller)))
       cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable);
+  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)
+          cgraph_for_node_thunks_and_aliases (alias, callback, data, include_overwritable);
+      }
   return false;
 }
 
@@ -2637,15 +2587,21 @@ 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)
+          cgraph_for_node_and_aliases (alias, callback, data, include_overwritable);
+      }
   return false;
 }
 
index 055ab4884ef98e0d2d1fd99a058d2799f62154bf..09d99b1c1f7426f4018aa40a4645fb352d36de01 100644 (file)
@@ -165,9 +165,6 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   struct cgraph_node *prev_sibling_clone;
   struct cgraph_node *clones;
   struct cgraph_node *clone_of;
-  /* For normal nodes pointer to the list of alias and thunk nodes,
-     in alias/thunk nodes pointer to the normal node.  */
-  struct cgraph_node *same_body;
   /* Circular list of nodes in the same comdat group if non-NULL.  */
   struct cgraph_node *same_comdat_group;
   /* For functions with many calls sites it holds map from call expression
@@ -236,8 +233,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   unsigned process : 1;
   /* Set for aliases once they got through assemble_alias.  */
   unsigned alias : 1;
-  /* Set for alias and thunk nodes, same_body points to the node they are alias
-     of and they are linked through the next/previous pointers.  */
+  /* Set for aliases created as C++ same body aliases.  */
   unsigned same_body_alias : 1;
   /* How commonly executed the node is.  Initialized during branch
      probabilities pass.  */
@@ -463,6 +459,7 @@ extern GTY(()) struct cgraph_node *cgraph_new_nodes;
 
 extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
 extern GTY(()) int cgraph_order;
+extern bool same_body_aliases_done;
 
 /* In cgraph.c  */
 void dump_cgraph (FILE *);
@@ -488,7 +485,6 @@ struct cgraph_node * cgraph_get_create_node (tree);
 struct cgraph_node * cgraph_same_body_alias (struct cgraph_node *, tree, tree);
 struct cgraph_node * cgraph_add_thunk (struct cgraph_node *, tree, tree, bool, HOST_WIDE_INT,
                                       HOST_WIDE_INT, tree, tree);
-void cgraph_remove_same_body_alias (struct cgraph_node *);
 struct cgraph_node *cgraph_node_for_asm (tree);
 struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
 void cgraph_set_call_stmt (struct cgraph_edge *, gimple);
@@ -508,6 +504,7 @@ struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *,
 struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
                                        int, bool, VEC(cgraph_edge_p,heap) *,
                                        bool);
+struct cgraph_node *cgraph_create_function_alias (tree, tree);
 
 void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
 void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
@@ -577,6 +574,7 @@ void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bi
                               bitmap, basic_block);
 void record_references_in_initializer (tree, bool);
 bool cgraph_process_new_functions (void);
+void cgraph_process_same_body_aliases (void);
 
 bool cgraph_decide_is_function_needed (struct cgraph_node *, tree);
 
@@ -746,7 +744,7 @@ cgraph_next_defined_function (struct cgraph_node *node)
 static inline bool
 cgraph_function_with_gimple_body_p (struct cgraph_node *node)
 {
-  return node->analyzed && !node->thunk.thunk_p;
+  return node->analyzed && !node->thunk.thunk_p && !node->alias;
 }
 
 /* Return first function with body defined.  */
@@ -934,7 +932,8 @@ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
   if (DECL_EXTERNAL (node->decl))
     return true;
   return (!node->address_taken
-         && cgraph_can_remove_if_no_direct_calls_and_refs_p (node));
+         && cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
+         && !ipa_ref_has_aliases_p (&node->ref_list));
 }
 
 /* Return true when function NODE can be removed from callgraph
@@ -968,6 +967,20 @@ htab_t constant_pool_htab (void);
 /* FIXME: inappropriate dependency of cgraph on IPA.  */
 #include "ipa-ref-inline.h"
 
+/* Return node that alias N is aliasing.  */
+
+static inline struct cgraph_node *
+cgraph_alias_aliased_node (struct cgraph_node *n)
+{
+  struct ipa_ref *ref;
+
+  ipa_ref_list_reference_iterate (&n->ref_list, 0, ref);
+  gcc_checking_assert (ref->use == IPA_REF_ALIAS);
+  if (ref->refered_type == IPA_REF_CGRAPH)
+    return ipa_ref_node (ref);
+  return NULL;
+}
+
 /* Given NODE, walk the alias chain to return the function NODE is alias of.
    Walk through thunk, too.
    When AVAILABILITY is non-NULL, get minimal availablity in the chain.  */
@@ -979,11 +992,13 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability)
     *availability = cgraph_function_body_availability (node);
   while (node)
     {
-      if (node->thunk.thunk_p)
+      if (node->alias && node->analyzed)
+       node = cgraph_alias_aliased_node (node);
+      else if (node->thunk.thunk_p)
        node = node->callees->callee;
       else
        return node;
-      if (availability)
+      if (node && availability)
        {
          enum availability a;
          a = cgraph_function_body_availability (node);
@@ -991,6 +1006,8 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability)
            *availability = a;
        }
     }
+  if (*availability)
+    *availability = AVAIL_NOT_AVAILABLE;
   return NULL;
 }
 
@@ -1003,7 +1020,22 @@ cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *avai
 {
   if (availability)
     *availability = cgraph_function_body_availability (node);
-  return node;
+  while (node)
+    {
+      if (node->alias && node->analyzed)
+       node = cgraph_alias_aliased_node (node);
+      else
+       return node;
+      if (node && availability)
+       {
+         enum availability a;
+         a = cgraph_function_body_availability (node);
+         if (a < *availability)
+           *availability = a;
+       }
+    }
+  if (*availability)
+    *availability = AVAIL_NOT_AVAILABLE;
   return NULL;
 }
 
index dd247eb231d7b6a44f55341baa08d557e928d067..b01f22b2b23ecab17bd67f7f106ed8c235b441b0 100644 (file)
@@ -167,6 +167,7 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
      the name later after finalizing the function and the fact is noticed
      in assemble_name then.  This is arguably a bug.  */
   if (DECL_ASSEMBLER_NAME_SET_P (decl)
+      && (!node->thunk.thunk_p && !node->same_body_alias)
       && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
     return true;
 
@@ -391,6 +392,8 @@ cgraph_mark_if_needed (tree decl)
 static bool
 clone_of_p (struct cgraph_node *node, struct cgraph_node *node2)
 {
+  node = cgraph_function_or_thunk_node (node, NULL);
+  node2 = cgraph_function_or_thunk_node (node2, NULL);
   while (node != node2 && node2)
     node2 = node2->clone_of;
   return node2 != NULL;
@@ -619,6 +622,36 @@ verify_cgraph_node (struct cgraph_node *node)
       while (n != node);
     }
 
+  if (node->analyzed && node->alias)
+    {
+      bool ref_found = false;
+      int i;
+      struct ipa_ref *ref;
+
+      if (node->callees)
+       {
+         error ("Alias has call edges");
+          error_found = true;
+       }
+      for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
+       if (ref->use != IPA_REF_ALIAS)
+         {
+           error ("Alias has non-alias refernece");
+           error_found = true;
+         }
+       else if (ref_found)
+         {
+           error ("Alias has more than one alias reference");
+           error_found = true;
+         }
+       else
+         ref_found = true;
+       if (!ref_found)
+         {
+           error ("Analyzed alias has no reference");
+           error_found = true;
+         }
+    }
   if (node->analyzed && node->thunk.thunk_p)
     {
       if (!node->callees)
@@ -669,19 +702,17 @@ verify_cgraph_node (struct cgraph_node *node)
                          }
                        if (!e->indirect_unknown_callee)
                          {
-                           if (e->callee->same_body_alias)
-                             {
-                               error ("edge points to same body alias:");
-                               debug_tree (e->callee->decl);
-                               error_found = true;
-                             }
-                           else if (!e->callee->global.inlined_to
-                                    && decl
-                                    && cgraph_get_node (decl)
-                                    && (e->callee->former_clone_of
-                                        != cgraph_get_node (decl)->decl)
-                                    && !clone_of_p (cgraph_get_node (decl),
-                                                    e->callee))
+                           if (!e->callee->global.inlined_to
+                               && decl
+                               && cgraph_get_node (decl)
+                               && (e->callee->former_clone_of
+                                   != cgraph_get_node (decl)->decl)
+                               /* IPA-CP sometimes redirect edge to clone and then back to the former
+                                  function.  This ping-pong has to go, eventaully.  */
+                               && (cgraph_function_or_thunk_node (cgraph_get_node (decl), NULL)
+                                   != cgraph_function_or_thunk_node (e->callee, NULL))
+                               && !clone_of_p (cgraph_get_node (decl),
+                                               e->callee))
                              {
                                error ("edge points to wrong declaration:");
                                debug_tree (e->callee->decl);
@@ -781,7 +812,53 @@ cgraph_analyze_function (struct cgraph_node *node)
   tree save = current_function_decl;
   tree decl = node->decl;
 
-  if (node->thunk.thunk_p)
+  if (node->alias && node->thunk.alias)
+    {
+      struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
+      if (!VEC_length (ipa_ref_t, node->ref_list.references))
+        ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL);
+      if (node->same_body_alias)
+       { 
+         DECL_VIRTUAL_P (node->decl) = DECL_VIRTUAL_P (node->thunk.alias);
+         DECL_DECLARED_INLINE_P (node->decl)
+            = DECL_DECLARED_INLINE_P (node->thunk.alias);
+         DECL_DISREGARD_INLINE_LIMITS (node->decl)
+            = DECL_DISREGARD_INLINE_LIMITS (node->thunk.alias);
+       }
+
+      /* Fixup visibility nonsences C++ frontend produce on same body aliases.  */
+      if (TREE_PUBLIC (node->decl) && node->same_body_alias)
+       {
+          DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->thunk.alias);
+         if (DECL_COMDAT (node->thunk.alias))
+           {
+             DECL_COMDAT (node->decl) = 1;
+             DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->thunk.alias);
+             if (DECL_ONE_ONLY (node->thunk.alias) && !node->same_comdat_group)
+               {
+                 struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
+                 node->same_comdat_group = tgt;
+                 if (!tgt->same_comdat_group)
+                   tgt->same_comdat_group = node;
+                 else
+                   {
+                     struct cgraph_node *n;
+                     for (n = tgt->same_comdat_group;
+                          n->same_comdat_group != tgt;
+                          n = n->same_comdat_group)
+                       ;
+                     n->same_comdat_group = node;
+                   }
+               }
+           }
+       }
+      cgraph_mark_reachable_node (cgraph_alias_aliased_node (node));
+      if (node->address_taken)
+       cgraph_mark_address_taken_node (cgraph_alias_aliased_node (node));
+      if (cgraph_decide_is_function_needed (node, node->decl))
+       cgraph_mark_needed_node (node);
+    }
+  else if (node->thunk.thunk_p)
     {
       cgraph_create_edge (node, cgraph_get_node (node->thunk.alias),
                          NULL, 0, CGRAPH_FREQ_BASE);
@@ -809,6 +886,26 @@ cgraph_analyze_function (struct cgraph_node *node)
   current_function_decl = save;
 }
 
+/* C++ frontend produce same body aliases all over the place, even before PCH
+   gets streamed out. It relies on us linking the aliases with their function
+   in order to do the fixups, but ipa-ref is not PCH safe.  Consequentely we
+   first produce aliases without links, but once C++ FE is sure he won't sream
+   PCH we build the links via this function.  */
+
+void
+cgraph_process_same_body_aliases (void)
+{
+  struct cgraph_node *node;
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->same_body_alias
+       && !VEC_length (ipa_ref_t, node->ref_list.references))
+      {
+        struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
+        ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL);
+      }
+  same_body_aliases_done = true;
+}
+
 /* Process attributes common for vars and functions.  */
 
 static void
@@ -880,7 +977,7 @@ process_function_and_variable_attributes (struct cgraph_node *first,
             cgraph_mark_needed_node (node);
        }
       if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
-         && node->local.finalized)
+         && (node->local.finalized && !node->alias))
        {
          warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
                      "%<weakref%> attribute ignored"
@@ -979,6 +1076,7 @@ cgraph_analyze_functions (void)
         weak alias attribute to kill its body. See
         gcc.c-torture/compile/20011119-1.c  */
       if (!DECL_STRUCT_FUNCTION (decl)
+         && (!node->alias || !node->thunk.alias)
          && !node->thunk.thunk_p)
        {
          cgraph_reset_node (node);
@@ -1046,11 +1144,13 @@ cgraph_analyze_functions (void)
       next = node->next;
 
       if (node->local.finalized && !gimple_has_body_p (decl)
+         && (!node->alias || !node->thunk.alias)
          && !node->thunk.thunk_p)
        cgraph_reset_node (node);
 
       if (!node->reachable
-         && (gimple_has_body_p (decl) || node->thunk.thunk_p))
+         && (gimple_has_body_p (decl) || node->thunk.thunk_p
+             || (node->alias && node->thunk.alias)))
        {
          if (cgraph_dump_file)
            fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
@@ -1060,6 +1160,7 @@ cgraph_analyze_functions (void)
       else
        node->next_needed = NULL;
       gcc_assert (!node->local.finalized || node->thunk.thunk_p
+                 || node->alias
                  || gimple_has_body_p (decl));
       gcc_assert (node->analyzed == node->local.finalized);
     }
@@ -1157,9 +1258,11 @@ cgraph_mark_functions_to_output (void)
         outside the current compilation unit.  */
       if (node->analyzed
          && !node->thunk.thunk_p
+         && !node->alias
          && !node->global.inlined_to
          && (!cgraph_only_called_directly_p (node)
-             || (e && node->reachable))
+             || ((e || ipa_ref_has_aliases_p (&node->ref_list))
+                 && node->reachable))
          && !TREE_ASM_WRITTEN (decl)
          && !DECL_EXTERNAL (decl))
        {
@@ -1170,7 +1273,7 @@ cgraph_mark_functions_to_output (void)
              for (next = node->same_comdat_group;
                   next != node;
                   next = next->same_comdat_group)
-               if (!next->thunk.thunk_p)
+               if (!next->thunk.thunk_p && !next->alias)
                  next->process = 1;
            }
        }
@@ -1190,6 +1293,7 @@ cgraph_mark_functions_to_output (void)
                 are inside partition, we can end up not removing the body since we no longer
                 have analyzed node pointing to it.  */
              && !node->in_other_partition
+             && !node->alias
              && !DECL_EXTERNAL (decl))
            {
              dump_cgraph_node (stderr, node);
@@ -1219,7 +1323,7 @@ cgraph_mark_functions_to_output (void)
              && !DECL_EXTERNAL (decl))
            {
              dump_cgraph_node (stderr, node);
-             internal_error ("failed to reclaim unneeded function");
+             internal_error ("failed to reclaim unneeded functionin same comdat group");
            }
        }
 #endif
@@ -1569,23 +1673,35 @@ assemble_thunk (struct cgraph_node *node)
 }
 
 
-/* Assemble thunks asociated to NODE.  */
+
+/* Assemble thunks and aliases asociated to NODE.  */
 
 static void
-assemble_thunks (struct cgraph_node *node)
+assemble_thunks_and_aliases (struct cgraph_node *node)
 {
   struct cgraph_edge *e;
+  int i;
+  struct ipa_ref *ref;
+
   for (e = node->callers; e;)
     if (e->caller->thunk.thunk_p)
       {
        struct cgraph_node *thunk = e->caller;
 
        e = e->next_caller;
-       assemble_thunks (thunk);
+       assemble_thunks_and_aliases (thunk);
         assemble_thunk (thunk);
       }
     else
       e = e->next_caller;
+  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);
+       assemble_alias (alias->decl,
+                       DECL_ASSEMBLER_NAME (alias->thunk.alias));
+       assemble_thunks_and_aliases (alias);
+      }
 }
 
 /* Expand function specified by NODE.  */
@@ -1600,27 +1716,7 @@ cgraph_expand_function (struct cgraph_node *node)
 
   announce_function (decl);
   node->process = 0;
-  if (node->same_body)
-    {
-      struct cgraph_node *alias, *next;
-      bool saved_alias = node->alias;
-      for (alias = node->same_body;
-          alias && alias->next; alias = alias->next)
-        ;
-      /* Walk aliases in the order they were created; it is possible that
-         thunks refers to the aliases made earlier.  */
-      for (; alias; alias = next)
-        {
-         next = alias->previous;
-         if (!alias->thunk.thunk_p)
-           assemble_alias (alias->decl,
-                           DECL_ASSEMBLER_NAME (alias->thunk.alias));
-       }
-      node->alias = saved_alias;
-      cgraph_process_new_functions ();
-    }
-
-  assemble_thunks (node);
+  assemble_thunks_and_aliases (node);
   gcc_assert (node->lowered);
 
   /* Generate RTL for the body of DECL.  */
@@ -1736,7 +1832,7 @@ cgraph_output_in_order (void)
 
   for (pf = cgraph_nodes; pf; pf = pf->next)
     {
-      if (pf->process && !pf->thunk.thunk_p)
+      if (pf->process && !pf->thunk.thunk_p && !pf->alias)
        {
          i = pf->order;
          gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
@@ -1810,7 +1906,7 @@ bool
 cgraph_preserve_function_body_p (struct cgraph_node *node)
 {
   gcc_assert (cgraph_global_info_ready);
-  gcc_assert (!node->same_body_alias);
+  gcc_assert (!node->alias && !node->thunk.thunk_p);
 
   /* Look if there is any clone around.  */
   if (node->clones)
index 9f429b51c58f6926e8a9e65e1669abf5efe28298..d214ea2f6de4d80ffac899c4975c5b5f0fc5edc4 100644 (file)
@@ -1,3 +1,8 @@
+2011-06-11  Jan Hubicka  <jh@suse.cz>
+
+       * decl2.c (cp_write_global_declarations): Process aliases; look trhough
+       same body aliases.
+
 2011-06-10  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/41769
index 82d0b11e04024e494dc280f2bed8109fdfce28af..d2f075dab0a2b032e343869232f6470888d3ad3a 100644 (file)
@@ -3672,6 +3672,8 @@ cp_write_global_declarations (void)
   if (pch_file)
     c_common_write_pch ();
 
+  cgraph_process_same_body_aliases ();
+
   /* Handle -fdump-ada-spec[-slim] */
   if (dump_enabled_p (TDI_ada))
     {
@@ -3869,6 +3871,8 @@ cp_write_global_declarations (void)
              struct cgraph_node *node, *next;
 
              node = cgraph_get_node (decl);
+             if (node->same_body_alias)
+               node = cgraph_alias_aliased_node (node);
 
              cgraph_for_node_and_aliases (node, clear_decl_external,
                                           NULL, true);
index 5b988e9e0a1c7eee6af02e6c08e7149468e41f29..c1824b4626ba3377a010fb0d7d7db011176e4171 100644 (file)
@@ -3363,9 +3363,8 @@ cp_fix_function_decl_p (tree decl)
 
       /* Don't fix same_body aliases.  Although they don't have their own
         CFG, they share it with what they alias to.  */
-      if (!node
-         || node->decl == decl
-         || !node->same_body)
+      if (!node || !node->alias
+         || !VEC_length (ipa_ref_t, node->ref_list.references))
        return true;
     }
 
index c5f32a34b763d9dc6103c935b88cf9b0bfd69c94..b62e50b93f0c7f9da926307229d035fa4e91fbf7 100644 (file)
@@ -88,6 +88,7 @@ can_remove_node_now_p (struct cgraph_node *node)
      can remove its offline copy, but we would need to keep unanalyzed node in
      the callgraph so references can point to it.  */
   return (!node->address_taken
+         && !ipa_ref_has_aliases_p (&node->ref_list)
          && cgraph_can_remove_if_no_direct_calls_p (node)
          /* Inlining might enable more devirtualizing, so we want to remove
             those only after all devirtualizable virtual calls are processed.
@@ -192,7 +193,22 @@ inline_call (struct cgraph_edge *e, bool update_original,
   /* If aliases are involved, redirect edge to the actual destination and
      possibly remove the aliases.  */
   if (e->callee != callee)
-    cgraph_redirect_edge_callee (e, callee);
+    {
+      struct cgraph_node *alias = e->callee, *next_alias;
+      cgraph_redirect_edge_callee (e, callee);
+      while (alias && alias != callee)
+       {
+         if (!alias->callers
+             && can_remove_node_now_p (alias))
+           {
+             next_alias = cgraph_alias_aliased_node (alias);
+             cgraph_remove_node (alias);
+             alias = next_alias;
+           }
+         else
+           break;
+       }
+    }
 
   clone_inlined_nodes (e, true, update_original, overall_size);
 
index 6733e9ae356ed37d0b9f59a0f99df0443e025097..4283770a1c3e87b1ff10f74052562d998ebec975 100644 (file)
@@ -965,6 +965,8 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
                    struct cgraph_edge *check_inlinablity_for)
 {
   struct cgraph_edge *edge;
+  int i;
+  struct ipa_ref *ref;
 
   if (!inline_summary (node)->inlinable
       || cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE
@@ -973,6 +975,13 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
   if (!bitmap_set_bit (updated_nodes, node->uid))
     return;
 
+  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);
+        update_caller_keys (heap, alias, updated_nodes, check_inlinablity_for);
+      }
+
   for (edge = node->callers; edge; edge = edge->next_caller)
     if (edge->inline_failed)
       {
@@ -1451,7 +1460,7 @@ inline_small_functions (void)
          where = edge->caller;
          while (where->global.inlined_to)
            {
-             if (where->decl == edge->callee->decl)
+             if (where->decl == callee->decl)
                outer_node = where, depth++;
              where = where->callers->caller;
            }
index db70e6e96af2efce76f1464135d6f3d873f7c79f..f5fd03f67fba09abb8035a7fa91ac96d600815a9 100644 (file)
@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "cgraph.h"
 
-static const char *ipa_ref_use_name[] = {"read","write","addr"};
+static const char *ipa_ref_use_name[] = {"read","write","addr","alias"};
 
 /* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE
    to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
@@ -46,6 +46,7 @@ ipa_record_reference (struct cgraph_node *refering_node,
   gcc_assert ((!refering_node) ^ (!refering_varpool_node));
   gcc_assert ((!refered_node) ^ (!refered_varpool_node));
   gcc_assert (!stmt || refering_node);
+  gcc_assert (use_type != IPA_REF_ALIAS || !stmt);
 
   list = (refering_node ? &refering_node->ref_list
          : &refering_varpool_node->ref_list);
@@ -73,7 +74,7 @@ ipa_record_reference (struct cgraph_node *refering_node,
     {
       ref->refered.cgraph_node = refered_node;
       ref->refered_type = IPA_REF_CGRAPH;
-      gcc_assert (use_type == IPA_REF_ADDR);
+      gcc_assert (use_type == IPA_REF_ADDR || use_type == IPA_REF_ALIAS);
     }
   else
     {
@@ -241,3 +242,15 @@ ipa_ref_cannot_lead_to_return (struct ipa_ref *ref)
 {
   return cgraph_node_cannot_return (ipa_ref_refering_node (ref));
 }
+
+/* Return true if list contains an alias.  */
+bool
+ipa_ref_has_aliases_p (struct ipa_ref_list *ref_list)
+{
+  struct ipa_ref *ref;
+  int i;
+  for (i = 0; ipa_ref_list_refering_iterate (ref_list, i, ref); i++)
+    if (ref->use == IPA_REF_ALIAS)
+      return true;
+  return false;
+}
index 2be73536f8ebf2c520c1c8e502cdb5f74b6e06a0..2fdb6ba4158f1ff7ae33de01fb5a86c537f40bb0 100644 (file)
@@ -27,7 +27,8 @@ enum GTY(()) ipa_ref_use
 {
   IPA_REF_LOAD,
   IPA_REF_STORE,
-  IPA_REF_ADDR
+  IPA_REF_ADDR,
+  IPA_REF_ALIAS
 };
 
 /* Type of refering or refered type.  */
@@ -89,4 +90,4 @@ void ipa_dump_refering (FILE *, struct ipa_ref_list *);
 void ipa_clone_references (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
 void ipa_clone_refering (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
 bool ipa_ref_cannot_lead_to_return (struct ipa_ref *);
-
+bool ipa_ref_has_aliases_p (struct ipa_ref_list *);
index ae207369d18f6ca35f68274437a8f2429c0d5ba5..9abc82dbbd9b88dc53040e3d743aeccbb3d3bda7 100644 (file)
@@ -234,7 +234,8 @@ ipa_free_postorder_info (void)
 }
 
 /* Fill array order with all nodes with output flag set in the reverse
-   topological order.  Return the number of elements in the array.  */
+   topological order.  Return the number of elements in the array.
+   FIXME: While walking, consider aliases, too.  */
 
 int
 ipa_reverse_postorder (struct cgraph_node **order)
@@ -260,7 +261,7 @@ ipa_reverse_postorder (struct cgraph_node **order)
          && (pass
              || (!node->address_taken
                  && !node->global.inlined_to
-                 && !cgraph_only_called_directly_p (node))))
+                 && !cgraph_only_called_directly_or_aliased_p (node))))
        {
          node2 = node;
          if (!node->callers)
index 7822cfde371c1dd2191edc4f9426ff933312d4df..a80f9ba2ba47ba06316b2a4d3661f496268e4ba6 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -581,9 +581,9 @@ cgraph_comdat_can_be_unshared_p (struct cgraph_node *node)
 /* Return true when function NODE should be considered externally visible.  */
 
 static bool
-cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool aliased)
+cgraph_externally_visible_p (struct cgraph_node *node,
+                            bool whole_program, bool aliased)
 {
-  struct cgraph_node *alias;
   if (!node->local.finalized)
     return false;
   if (!DECL_COMDAT (node->decl)
@@ -630,18 +630,6 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
       && cgraph_comdat_can_be_unshared_p (node))
     return false;
 
-  /* See if we have linker information about symbol not being used or
-     if we need to make guess based on the declaration.
-
-     Even if the linker clams the symbol is unused, never bring internal
-     symbols that are declared by user as used or externally visible.
-     This is needed for i.e. references from asm statements.   */
-  for (alias = node->same_body; alias; alias = alias->next)
-    if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY)
-      break;
-  if (!alias && node->resolution == LDPR_PREVAILING_DEF_IRONLY)
-    return false;
-
   /* When doing link time optimizations, hidden symbols become local.  */
   if (in_lto_p
       && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
@@ -881,12 +869,9 @@ function_and_variable_visibility (bool whole_program)
       if (!node->local.externally_visible && node->analyzed
          && !DECL_EXTERNAL (node->decl))
        {
-          struct cgraph_node *alias;
          gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl));
          cgraph_make_decl_local (node->decl);
          node->resolution = LDPR_PREVAILING_DEF_IRONLY;
-         for (alias = node->same_body; alias; alias = alias->next)
-           cgraph_make_decl_local (alias->decl);
          if (node->same_comdat_group)
            /* cgraph_externally_visible_p has already checked all other nodes
               in the group and they will all be made local.  We need to
@@ -900,8 +885,7 @@ function_and_variable_visibility (bool whole_program)
        {
          struct cgraph_node *decl_node = node;
 
-         while (decl_node->thunk.thunk_p)
-           decl_node = decl_node->callees->callee;
+         decl_node = cgraph_function_node (decl_node->callees->callee, NULL);
 
          /* Thunks have the same visibility as function they are attached to.
             For some reason C++ frontend don't seem to care. I.e. in 
@@ -933,9 +917,9 @@ function_and_variable_visibility (bool whole_program)
          if (DECL_EXTERNAL (decl_node->decl))
            DECL_EXTERNAL (node->decl) = 1;
        }
-      node->local.local = cgraph_local_node_p (node);
-
     }
+  for (node = cgraph_nodes; node; node = node->next)
+    node->local.local = cgraph_local_node_p (node);
   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
     {
       /* weak flag makes no sense on local variables.  */
index 3b1115b53f63babf4ac8c89f954fd287bc99ef6e..169de382dbe3a35df6437064fc0344e4afa7039e 100644 (file)
@@ -504,7 +504,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
                     || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1);
   bp_pack_value (&bp, node->lowered, 1);
   bp_pack_value (&bp, in_other_partition, 1);
-  bp_pack_value (&bp, node->alias, 1);
+  bp_pack_value (&bp, node->alias && !boundary_p, 1);
   bp_pack_value (&bp, node->frequency, 2);
   bp_pack_value (&bp, node->only_called_at_startup, 1);
   bp_pack_value (&bp, node->only_called_at_exit, 1);
@@ -523,32 +523,15 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
                                 node->thunk.fixed_offset);
       lto_output_uleb128_stream (ob->main_stream,
                                 node->thunk.virtual_value);
-      lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
-                               node->thunk.alias);
     }
-
-  if (node->same_body)
+  if ((node->alias || node->thunk.thunk_p) && !boundary_p)
     {
-      struct cgraph_node *alias;
-      unsigned long alias_count = 1;
-      for (alias = node->same_body; alias->next; alias = alias->next)
-       alias_count++;
-      lto_output_uleb128_stream (ob->main_stream, alias_count);
-      do
-       {
-         lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
-                                   alias->decl);
-         lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
-                                   alias->thunk.alias);
-         gcc_assert (cgraph_get_node (alias->thunk.alias) == node);
-         lto_output_enum (ob->main_stream, ld_plugin_symbol_resolution,
-                          LDPR_NUM_KNOWN, alias->resolution);
-         alias = alias->previous;
-       }
-      while (alias);
+      lto_output_int_in_range (ob->main_stream, 0, 1,
+                              node->thunk.alias != NULL);
+      if (node->thunk.alias != NULL)
+        lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
+                                 node->thunk.alias);
     }
-  else
-    lto_output_uleb128_stream (ob->main_stream, 0);
 }
 
 /* Output the varpool NODE to OB. 
@@ -997,7 +980,6 @@ input_node (struct lto_file_decl_data *file_data,
   struct bitpack_d bp;
   unsigned decl_index;
   int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND;
-  unsigned long same_body_count = 0;
   int clone_ref;
 
   clone_ref = lto_input_sleb128 (ib);
@@ -1043,31 +1025,20 @@ input_node (struct lto_file_decl_data *file_data,
       int type = lto_input_uleb128 (ib);
       HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib);
       HOST_WIDE_INT virtual_value = lto_input_uleb128 (ib);
-      tree real_alias;
 
-      decl_index = lto_input_uleb128 (ib);
-      real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
       node->thunk.fixed_offset = fixed_offset;
       node->thunk.this_adjusting = (type & 2);
       node->thunk.virtual_value = virtual_value;
       node->thunk.virtual_offset_p = (type & 4);
-      node->thunk.alias = real_alias;
     }
-
-  same_body_count = lto_input_uleb128 (ib);
-  while (same_body_count-- > 0)
+  if (node->thunk.thunk_p || node->alias)
     {
-      tree alias_decl, real_alias;
-      struct cgraph_node *alias;
-
-      decl_index = lto_input_uleb128 (ib);
-      alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
-      decl_index = lto_input_uleb128 (ib);
-      real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
-      alias = cgraph_same_body_alias (node, alias_decl, real_alias);
-      gcc_assert (alias);
-      alias->resolution = lto_input_enum (ib, ld_plugin_symbol_resolution,
-                                         LDPR_NUM_KNOWN);
+      if (lto_input_int_in_range (ib, "alias nonzero flag", 0, 1))
+       {
+          decl_index = lto_input_uleb128 (ib);
+          node->thunk.alias = lto_file_decl_data_get_fn_decl (file_data,
+                                                             decl_index);
+       }
     }
   return node;
 }
index 02ac9583aced8f02e9c77a050ba19f11ff79169d..7a2f3f02361b63b4804926286bf2f962a4c5fd62 100644 (file)
@@ -2253,6 +2253,7 @@ lto_output (cgraph_node_set set, varpool_node_set vset)
     {
       node = lto_cgraph_encoder_deref (encoder, i);
       if (lto_cgraph_encoder_encode_body_p (encoder, node)
+         && !node->alias
          && !node->thunk.thunk_p)
        {
 #ifdef ENABLE_CHECKING
@@ -2551,7 +2552,7 @@ produce_symtab (struct output_block *ob,
   struct lto_streamer_cache_d *cache = ob->writer_cache;
   char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
   struct pointer_set_t *seen;
-  struct cgraph_node *node, *alias;
+  struct cgraph_node *node;
   struct varpool_node *vnode, *valias;
   struct lto_output_stream stream;
   lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
@@ -2584,8 +2585,6 @@ produce_symtab (struct output_block *ob,
       if (node->alias || node->global.inlined_to)
        continue;
       write_symbol (cache, &stream, node->decl, seen, false);
-      for (alias = node->same_body; alias; alias = alias->next)
-        write_symbol (cache, &stream, alias->decl, seen, true);
     }
   for (i = 0; i < lto_cgraph_encoder_size (encoder); i++)
     {
@@ -2598,8 +2597,6 @@ produce_symtab (struct output_block *ob,
       if (node->alias || node->global.inlined_to)
        continue;
       write_symbol (cache, &stream, node->decl, seen, false);
-      for (alias = node->same_body; alias; alias = alias->next)
-        write_symbol (cache, &stream, alias->decl, seen, true);
     }
 
   /* Write all variables.  */
index af8106de94f2586457820c5059690103951d366f..d58da8df2db7e3d2b9f1435788cacc99ccfa0edc 100644 (file)
@@ -209,7 +209,6 @@ lto_cgraph_replace_node (struct cgraph_node *node,
                         struct cgraph_node *prevailing_node)
 {
   struct cgraph_edge *e, *next;
-  bool no_aliases_please = false;
   bool compatible_p;
 
   if (cgraph_dump_file)
@@ -223,13 +222,6 @@ lto_cgraph_replace_node (struct cgraph_node *node,
                 (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)))));
     }
 
-  if (prevailing_node->same_body_alias)
-    {
-      if (prevailing_node->thunk.thunk_p)
-       no_aliases_please = true;
-      prevailing_node = prevailing_node->same_body;
-    }
-
   /* Merge node flags.  */
   if (node->needed)
     cgraph_mark_needed_node (prevailing_node);
@@ -259,36 +251,8 @@ lto_cgraph_replace_node (struct cgraph_node *node,
   /* Redirect incomming references.  */
   ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
 
-  /* If we have aliases, redirect them to the prevailing node.  */
-  if (!node->same_body_alias && node->same_body)
-    {
-      struct cgraph_node *alias, *last;
-      /* We prevail aliases/tunks by a thunk.  This is doable but
-         would need thunk combination.  Hopefully no ABI changes will
-         every be crazy enough.  */
-      gcc_assert (!no_aliases_please);
-
-      for (alias = node->same_body; alias; alias = alias->next)
-       {
-         last = alias;
-         gcc_assert (alias->same_body_alias);
-         alias->same_body = prevailing_node;
-       }
-      last->next = prevailing_node->same_body;
-      /* Node with aliases is prevailed by alias.
-        We could handle this, but combining thunks together will be tricky.
-        Hopefully this does not happen.  */
-      if (prevailing_node->same_body)
-       prevailing_node->same_body->previous = last;
-      prevailing_node->same_body = node->same_body;
-      node->same_body = NULL;
-    }
-
   /* Finally remove the replaced node.  */
-  if (node->same_body_alias)
-    cgraph_remove_same_body_alias (node);
-  else
-    cgraph_remove_node (node);
+  cgraph_remove_node (node);
 }
 
 /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
@@ -472,9 +436,7 @@ lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
 
   /* For functions we need a non-discarded body.  */
   if (TREE_CODE (e->decl) == FUNCTION_DECL)
-    return (e->node
-           && (e->node->analyzed
-               || (e->node->same_body_alias && e->node->same_body->analyzed)));
+    return (e->node && e->node->analyzed);
 
   /* A variable should have a size.  */
   else if (TREE_CODE (e->decl) == VAR_DECL)
@@ -816,20 +778,14 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
 void
 lto_symtab_merge_cgraph_nodes (void)
 {
-  struct cgraph_node *node, *alias, *next;
+  struct cgraph_node *node;
   lto_symtab_maybe_init_hash_table ();
   htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
 
   for (node = cgraph_nodes; node; node = node->next)
-    {
-      if (node->thunk.thunk_p)
-        node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias);
-      for (alias = node->same_body; alias; alias = next)
-       {
-         next = alias->next;
-         alias->thunk.alias = lto_symtab_prevailing_decl (alias->thunk.alias);
-       }
-    }
+    if ((node->thunk.thunk_p || node->alias)
+       && node->thunk.alias)
+      node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias);
 }
 
 /* Given the decl DECL, return the prevailing decl with the same name. */
index 44265df529fa12970e290f95552c04e52f9a1762..9956d791ce3ee302c8353d892b9addcdddad33ef 100644 (file)
@@ -1,3 +1,12 @@
+2011-06-11  Jan Hubicka  <jh@suse.cz>
+
+       * lto.c (add_cgraph_node_to_partition_1): Break out from ...
+       (add_cgraph_node_to_partition) ... here; walk aliases.
+       (lto_1_to_1_map): Remove same body alias code.
+       (promote_fn): Likewise.
+       (lto_promote_cross_file_statics): Update comment.
+
+
 2011-06-07  Diego Novillo  <dnovillo@google.com>
 
        * lto.c (uniquify_nodes): Move code to register decls to
index 6e49ee77b59cc353d5f98f91db6a6d30040ab4fc..f13ee0e03f259538e86317016c4cb66e6ac8cea8 100644 (file)
@@ -1319,7 +1319,7 @@ add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
   for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
     {
       if (ref->refered_type == IPA_REF_CGRAPH
-         && DECL_COMDAT (ipa_ref_node (ref)->decl)
+         && DECL_COMDAT (cgraph_function_node (ipa_ref_node (ref), NULL)->decl)
          && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set))
        add_cgraph_node_to_partition (part, ipa_ref_node (ref));
       else
@@ -1330,6 +1330,34 @@ add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
     }
 }
 
+/* Worker for add_cgraph_node_to_partition.  */
+
+static bool
+add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
+{
+  ltrans_partition part = (ltrans_partition) data;
+
+  /* non-COMDAT aliases of COMDAT functions needs to be output just once.  */
+  if (!DECL_COMDAT (node->decl)
+      && !node->global.inlined_to
+      && node->aux)
+    {
+      gcc_assert (node->thunk.thunk_p || node->alias);
+      return false;
+    }
+
+  if (node->aux)
+    {
+      node->in_other_partition = 1;
+      if (cgraph_dump_file)
+        fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
+                cgraph_node_name (node), node->uid);
+    }
+  node->aux = (void *)((size_t)node->aux + 1);
+  cgraph_node_set_add (part->cgraph_set, node);
+  return false;
+}
+
 /* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */
 
 static void
@@ -1337,42 +1365,34 @@ add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node)
 {
   struct cgraph_edge *e;
   cgraph_node_set_iterator csi;
+  struct cgraph_node *n;
+
+  /* We always decide on functions, not associated thunks and aliases.  */
+  node = cgraph_function_node (node, NULL);
 
   /* If NODE is already there, we have nothing to do.  */
   csi = cgraph_node_set_find (part->cgraph_set, node);
   if (!csi_end_p (csi))
     return;
 
+  cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true);
+
   part->insns += inline_summary (node)->self_size;
 
-  if (node->aux)
-    {
-      node->in_other_partition = 1;
-      if (cgraph_dump_file)
-        fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
-                cgraph_node_name (node), node->uid);
-    }
-  node->aux = (void *)((size_t)node->aux + 1);
 
   cgraph_node_set_add (part->cgraph_set, node);
 
-  /* Thunks always must go along with function they reffer to.  */
-  if (node->thunk.thunk_p)
-    add_cgraph_node_to_partition (part, node->callees->callee);
-  for (e = node->callers; e; e = e->next_caller)
-    if (e->caller->thunk.thunk_p)
-      add_cgraph_node_to_partition (part, e->caller);
-
   for (e = node->callees; e; e = e->next_callee)
-    if ((!e->inline_failed || DECL_COMDAT (e->callee->decl))
+    if ((!e->inline_failed
+        || DECL_COMDAT (cgraph_function_node (e->callee, NULL)->decl))
        && !cgraph_node_in_set_p (e->callee, part->cgraph_set))
       add_cgraph_node_to_partition (part, e->callee);
 
   add_references_to_partition (part, &node->ref_list);
 
-  if (node->same_comdat_group
-      && !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set))
-    add_cgraph_node_to_partition (part, node->same_comdat_group);
+  if (node->same_comdat_group)
+    for (n = node->same_comdat_group; n != node; n = n->same_comdat_group)
+      add_cgraph_node_to_partition (part, n);
 }
 
 /* Add VNODE to partition as well as comdat references partition PART. */
@@ -1500,7 +1520,6 @@ lto_1_to_1_map (void)
        continue;
 
       file_data = node->local.lto_file_data;
-      gcc_assert (!node->same_body_alias);
 
       if (file_data)
        {
@@ -1900,17 +1919,6 @@ promote_fn (struct cgraph_node *node)
   TREE_PUBLIC (node->decl) = 1;
   DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
   DECL_VISIBILITY_SPECIFIED (node->decl) = true;
-  if (node->same_body)
-    {
-      struct cgraph_node *alias;
-      for (alias = node->same_body;
-          alias; alias = alias->next)
-       {
-         TREE_PUBLIC (alias->decl) = 1;
-         DECL_VISIBILITY (alias->decl) = VISIBILITY_HIDDEN;
-         DECL_VISIBILITY_SPECIFIED (alias->decl) = true;
-       }
-    }
   if (cgraph_dump_file)
     fprintf (cgraph_dump_file,
             "Promoting function as hidden: %s/%i\n",
@@ -1944,8 +1952,8 @@ lto_promote_cross_file_statics (void)
       set = part->cgraph_set;
       vset = part->varpool_set;
 
-      /* If node has either address taken (and we have no clue from where)
-        or it is called from other partition, it needs to be globalized.  */
+      /* If node called or referred to from other partition, it needs to be
+        globalized.  */
       for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
        {
          struct cgraph_node *node = csi_node (csi);
index ce0d8d0653d03f77d9acaebb3679fa9e2228fe1d..3544cafa20cb1ce57ebdf6ab8ffdf71fb08f050a 100644 (file)
@@ -6675,6 +6675,16 @@ gate_ipa_pta (void)
 struct pt_solution ipa_escaped_pt
   = { true, false, false, false, false, false, false, NULL };
 
+/* Associate node with varinfo DATA. Worker for
+   cgraph_for_node_and_aliases.  */
+static bool
+associate_varinfo_to_alias (struct cgraph_node *node, void *data)
+{
+  if (node->alias || node->thunk.thunk_p)
+    insert_vi_for_tree (node->decl, (varinfo_t)data);
+  return false;
+}
+
 /* Execute the driver for IPA PTA.  */
 static unsigned int
 ipa_pta_execute (void)
@@ -6690,22 +6700,17 @@ ipa_pta_execute (void)
   /* Build the constraints.  */
   for (node = cgraph_nodes; node; node = node->next)
     {
-      struct cgraph_node *alias;
       varinfo_t vi;
-
       /* Nodes without a body are not interesting.  Especially do not
          visit clones at this point for now - we get duplicate decls
         there for inline clones at least.  */
-      if (!gimple_has_body_p (node->decl)
+      if (!cgraph_function_with_gimple_body_p (node)
          || node->clone_of)
        continue;
 
       vi = create_function_info_for (node->decl,
-                                    alias_get_name (node->decl));
-
-      /* Associate the varinfo node with all aliases.  */
-      for (alias = node->same_body; alias; alias = alias->next)
-       insert_vi_for_tree (alias->decl, vi);
+                                    alias_get_name (node->decl));
+      cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true);
     }
 
   /* Create constraints for global variables and their initializers.  */
@@ -6737,7 +6742,7 @@ ipa_pta_execute (void)
       tree old_func_decl;
 
       /* Nodes without a body are not interesting.  */
-      if (!gimple_has_body_p (node->decl)
+      if (!cgraph_function_with_gimple_body_p (node)
          || node->clone_of)
        continue;
 
@@ -6846,7 +6851,7 @@ ipa_pta_execute (void)
       struct cgraph_edge *e;
 
       /* Nodes without a body are not interesting.  */
-      if (!gimple_has_body_p (node->decl)
+      if (!cgraph_function_with_gimple_body_p (node)
          || node->clone_of)
        continue;