OSDN Git Service

ABM intrinsics file.
[pf3gnuchains/gcc-fork.git] / gcc / cgraph.c
index 391882e..651618c 100644 (file)
@@ -85,6 +85,7 @@ The callgraph:
 #include "tree-flow.h"
 #include "value-prof.h"
 #include "except.h"
+#include "diagnostic.h"
 
 static void cgraph_node_remove_callers (struct cgraph_node *node);
 static inline void cgraph_edge_remove_caller (struct cgraph_edge *e);
@@ -406,32 +407,6 @@ hash_node (const void *p)
 }
 
 
-/* Return the cgraph node associated with function DECL.  If none
-   exists, return NULL.  */
-
-struct cgraph_node *
-cgraph_node_for_decl (tree decl)
-{
-  struct cgraph_node *node;
-  void **slot;
-
-  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
-
-  node = NULL;
-  if (cgraph_hash)
-    {
-      struct cgraph_node key;
-
-      key.decl = decl;
-      slot = htab_find_slot (cgraph_hash, &key, NO_INSERT);
-      if (slot && *slot)
-       node = (struct cgraph_node *) *slot;
-    }
-
-  return node;
-}
-
-
 /* Returns nonzero if P1 and P2 are equal.  */
 
 static int
@@ -442,10 +417,10 @@ eq_node (const void *p1, const void *p2)
   return DECL_UID (n1->decl) == DECL_UID (n2->decl);
 }
 
-/* Allocate new callgraph node and insert it into basic data structures.  */
+/* Allocate new callgraph node.  */
 
-static struct cgraph_node *
-cgraph_create_node (void)
+static inline struct cgraph_node *
+cgraph_allocate_node (void)
 {
   struct cgraph_node *node;
 
@@ -460,6 +435,16 @@ cgraph_create_node (void)
       node->uid = cgraph_max_uid++;
     }
 
+  return node;
+}
+
+/* Allocate new callgraph node and insert it into basic data structures.  */
+
+static struct cgraph_node *
+cgraph_create_node (void)
+{
+  struct cgraph_node *node = cgraph_allocate_node ();
+
   node->next = cgraph_nodes;
   node->pid = -1;
   node->order = cgraph_order++;
@@ -491,6 +476,8 @@ cgraph_node (tree decl)
   if (*slot)
     {
       node = *slot;
+      if (node->same_body_alias)
+       node = node->same_body;
       return node;
     }
 
@@ -521,6 +508,85 @@ cgraph_node (tree decl)
   return node;
 }
 
+/* Mark ALIAS as an alias to DECL.  */
+
+static struct cgraph_node *
+cgraph_same_body_alias_1 (tree alias, tree decl)
+{
+  struct cgraph_node key, *alias_node, *decl_node, **slot;
+
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
+  decl_node = cgraph_node (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->thunk.alias = decl;
+  decl_node->same_body = alias_node;
+  *slot = alias_node;
+  return alias_node;
+}
+
+/* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
+   Same body aliases are output whenever the body of DECL is output,
+   and cgraph_node (ALIAS) transparently returns cgraph_node (DECL).   */
+
+bool
+cgraph_same_body_alias (tree alias, tree decl)
+{
+#ifndef ASM_OUTPUT_DEF
+  /* If aliases aren't supported by the assembler, fail.  */
+  return false;
+#endif
+
+  /*gcc_assert (!assembler_name_hash);*/
+
+  return cgraph_same_body_alias_1 (alias, decl) != NULL;
+}
+
+void
+cgraph_add_thunk (tree alias, tree decl, bool this_adjusting,
+                 HOST_WIDE_INT fixed_offset, HOST_WIDE_INT virtual_value,
+                 tree virtual_offset,
+                 tree real_alias)
+{
+  struct cgraph_node *node = cgraph_get_node (alias);
+
+  if (node)
+    {
+      gcc_assert (node->local.finalized);
+      gcc_assert (!node->same_body);
+      cgraph_remove_node (node);
+    }
+  
+  node = cgraph_same_body_alias_1 (alias, decl);
+  gcc_assert (node);
+#ifdef ENABLE_CHECKING
+  gcc_assert (!virtual_offset
+             || tree_int_cst_equal (virtual_offset, size_int (virtual_value)));
+#endif
+  node->thunk.fixed_offset = fixed_offset;
+  node->thunk.this_adjusting = this_adjusting;
+  node->thunk.virtual_value = virtual_value;
+  node->thunk.virtual_offset_p = virtual_offset != NULL;
+  node->thunk.alias = real_alias;
+  node->thunk.thunk_p = true;
+}
+
 /* Returns the cgraph node assigned to DECL or NULL if no cgraph node
    is assigned.  */
 
@@ -532,7 +598,7 @@ cgraph_get_node (tree decl)
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
 
   if (!cgraph_hash)
-    cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL);
+    return NULL;
 
   key.decl = decl;
 
@@ -540,7 +606,11 @@ cgraph_get_node (tree decl)
                                                 NO_INSERT);
 
   if (slot && *slot)
-    node = *slot;
+    {
+      node = *slot;
+      if (node->same_body_alias)
+       node = node->same_body;
+    }
   return node;
 }
 
@@ -601,9 +671,23 @@ cgraph_node_for_asm (tree asmname)
               it is __builtin_strlen and strlen, for instance.  Do we need to
               record them all?  Original implementation marked just first one
               so lets hope for the best.  */
-           if (*slot)
-             continue;
-           *slot = node;
+           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;
+                 }
+             }
          }
     }
 
@@ -612,7 +696,12 @@ cgraph_node_for_asm (tree asmname)
                                   NO_INSERT);
 
   if (slot)
-    return (struct cgraph_node *) *slot;
+    {
+      node = (struct cgraph_node *) *slot;
+      if (node->same_body_alias)
+       node = node->same_body;
+      return node;
+    }
   return NULL;
 }
 
@@ -740,8 +829,8 @@ cgraph_set_call_stmt_including_clones (struct cgraph_node *orig,
 }
 
 /* Like cgraph_create_edge walk the clone tree and update all clones sharing
-   same function body.  
-   
+   same function body.
+
    TODO: COUNT and LOOP_DEPTH should be properly distributed based on relative
    frequencies of the clones.  */
 
@@ -1146,6 +1235,44 @@ 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
@@ -1283,6 +1410,9 @@ cgraph_remove_node (struct cgraph_node *node)
       node->clone_of->clones = node->clones;
     }
 
+  while (node->same_body)
+    cgraph_remove_same_body_alias (node->same_body);
+
   /* While all the clones are removed after being proceeded, the function
      itself is kept in the cgraph even after it is compiled.  Check whether
      we are done with this body and reclaim it proactively if this is the case.
@@ -1550,6 +1680,27 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
        fprintf(f, "(can throw external) ");
     }
   fprintf (f, "\n");
+
+  if (node->same_body)
+    {
+      struct cgraph_node *n;
+      fprintf (f, "  aliases & thunks:");
+      for (n = node->same_body; n; n = n->next)
+        {
+          fprintf (f, " %s/%i", cgraph_node_name (n), n->uid);
+         if (n->thunk.thunk_p)
+           {
+             fprintf (f, " (thunk of %s fixed ofset %i virtual value %i has "
+                      "virtual offset %i",
+                      lang_hooks.decl_printable_name (n->thunk.alias, 2),
+                      (int)n->thunk.fixed_offset,
+                      (int)n->thunk.virtual_value,
+                      (int)n->thunk.virtual_offset_p);
+             fprintf (f, ")");
+           }
+       }
+      fprintf (f, "\n");
+    }
 }
 
 
@@ -1757,7 +1908,7 @@ clone_function_name (tree decl)
 }
 
 /* Create callgraph node clone with new declaration.  The actual body will
-   be copied later at compilation stage.  
+   be copied later at compilation stage.
 
    TODO: after merging in ipa-sra use function call notes instead of args_to_skip
    bitmap interface.
@@ -1908,7 +2059,7 @@ cgraph_function_body_availability (struct cgraph_node *node)
    GIMPLE.
 
    The function is assumed to be reachable and have address taken (so no
-   API breaking optimizations are performed on it).  
+   API breaking optimizations are performed on it).
 
    Main work done by this function is to enqueue the function for later
    processing to avoid need the passes to be re-entrant.  */