OSDN Git Service

* cgraph.c (cgraph_release_function_body): Update use of
[pf3gnuchains/gcc-fork.git] / gcc / cgraph.c
index 5eb0f18..840cf29 100644 (file)
@@ -84,6 +84,7 @@ The callgraph:
 #include "tree-dump.h"
 #include "tree-flow.h"
 #include "value-prof.h"
+#include "except.h"
 
 static void cgraph_node_remove_callers (struct cgraph_node *node);
 static inline void cgraph_edge_remove_caller (struct cgraph_edge *e);
@@ -404,6 +405,33 @@ hash_node (const void *p)
   return (hashval_t) DECL_UID (n->decl);
 }
 
+
+/* 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
@@ -493,6 +521,29 @@ cgraph_node (tree decl)
   return node;
 }
 
+/* Returns the cgraph node assigned to DECL or NULL if no cgraph node
+   is assigned.  */
+
+struct cgraph_node *
+cgraph_get_node (tree decl)
+{
+  struct cgraph_node key, *node = NULL, **slot;
+
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+
+  if (!cgraph_hash)
+    cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL);
+
+  key.decl = decl;
+
+  slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key,
+                                                NO_INSERT);
+
+  if (slot && *slot)
+    node = *slot;
+  return node;
+}
+
 /* Insert already constructed node into hashtable.  */
 
 void
@@ -654,8 +705,8 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt)
     }
 }
 
-/* Like cgraph_set_call_stmt but walk the clone tree and update all clones sharing
-   same function body.  */
+/* Like cgraph_set_call_stmt but walk the clone tree and update all
+   clones sharing the same function body.  */
 
 void
 cgraph_set_call_stmt_including_clones (struct cgraph_node *orig,
@@ -666,8 +717,10 @@ cgraph_set_call_stmt_including_clones (struct cgraph_node *orig,
 
   if (edge)
     cgraph_set_call_stmt (edge, new_stmt);
-  if (orig->clones)
-    for (node = orig->clones; node != orig;)
+
+  node = orig->clones;
+  if (node)
+    while (node != orig)
       {
        struct cgraph_edge *edge = cgraph_edge (node, old_stmt);
        if (edge)
@@ -690,29 +743,36 @@ cgraph_set_call_stmt_including_clones (struct cgraph_node *orig,
    same function body.  
    
    TODO: COUNT and LOOP_DEPTH should be properly distributed based on relative
-   frequencies of the clones.
-   */
+   frequencies of the clones.  */
 
 void
-cgraph_create_edge_including_clones (struct cgraph_node *orig, struct cgraph_node *callee,
-                                    gimple stmt, gcov_type count, int freq,
-                                    int loop_depth,
+cgraph_create_edge_including_clones (struct cgraph_node *orig,
+                                    struct cgraph_node *callee,
+                                    gimple stmt, gcov_type count,
+                                    int freq, int loop_depth,
                                     cgraph_inline_failed_t reason)
 {
   struct cgraph_node *node;
+  struct cgraph_edge *edge;
 
   if (!cgraph_edge (orig, stmt))
-     cgraph_create_edge (orig, callee, stmt,
-                        count, freq, loop_depth)->inline_failed = reason;
+    {
+      edge = cgraph_create_edge (orig, callee, stmt, count, freq, loop_depth);
+      edge->inline_failed = reason;
+    }
 
-  if (orig->clones)
-    for (node = orig->clones; node != orig;)
+  node = orig->clones;
+  if (node)
+    while (node != orig)
       {
         /* It is possible that we already constant propagated into the clone
           and turned indirect call into dirrect call.  */
         if (!cgraph_edge (node, stmt))
-         cgraph_create_edge (node, callee, stmt, count, freq,
-                             loop_depth)->inline_failed = reason;
+         {
+           edge = cgraph_create_edge (node, callee, stmt, count,
+                                      freq, loop_depth);
+           edge->inline_failed = reason;
+         }
 
        if (node->clones)
          node = node->clones;
@@ -742,7 +802,7 @@ initialize_inline_failed (struct cgraph_edge *e)
     e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
   else if (!callee->local.inlinable)
     e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
-  else if (gimple_call_cannot_inline_p (e->call_stmt))
+  else if (e->call_stmt && gimple_call_cannot_inline_p (e->call_stmt))
     e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
   else
     e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
@@ -756,13 +816,19 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
 {
   struct cgraph_edge *edge;
 
+
+  /* LTO does not actually have access to the call_stmt since these
+     have not been loaded yet.  */
+  if (call_stmt)
+    {
 #ifdef ENABLE_CHECKING
-  /* This is rather pricely check possibly trigerring construction of call stmt
-     hashtable.  */
-  gcc_assert (!cgraph_edge (caller, call_stmt));
+      /* This is rather pricely check possibly trigerring construction of
+        call stmt hashtable.  */
+      gcc_assert (!cgraph_edge (caller, call_stmt));
 #endif
 
-  gcc_assert (is_gimple_call (call_stmt));
+      gcc_assert (is_gimple_call (call_stmt));
+    }
 
   if (free_edges)
     {
@@ -781,7 +847,8 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
   edge->callee = callee;
   edge->call_stmt = call_stmt;
   push_cfun (DECL_STRUCT_FUNCTION (caller->decl));
-  edge->can_throw_external = stmt_can_throw_external (call_stmt);
+  edge->can_throw_external
+    = call_stmt ? stmt_can_throw_external (call_stmt) : false;
   pop_cfun ();
   edge->prev_caller = NULL;
   edge->next_caller = callee->callers;
@@ -800,7 +867,9 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
   gcc_assert (freq <= CGRAPH_FREQ_MAX);
   edge->loop_nest = nest;
   edge->indirect_call = 0;
-  if (caller->call_site_hash)
+  edge->call_stmt_cannot_inline_p =
+    (call_stmt ? gimple_call_cannot_inline_p (call_stmt) : false);
+  if (call_stmt && caller->call_site_hash)
     {
       void **slot;
       slot = htab_find_slot_with_hash (caller->call_site_hash,
@@ -1063,7 +1132,7 @@ cgraph_release_function_body (struct cgraph_node *node)
       pop_cfun();
       gimple_set_body (node->decl, NULL);
       VEC_free (ipa_opt_pass, heap,
-               DECL_STRUCT_FUNCTION (node->decl)->ipa_transforms_to_apply);
+               node->ipa_transforms_to_apply);
       /* Struct function hangs a lot of data that would leak if we didn't
          removed all pointers to it.   */
       ggc_free (DECL_STRUCT_FUNCTION (node->decl));
@@ -1090,6 +1159,8 @@ cgraph_remove_node (struct cgraph_node *node)
   cgraph_call_node_removal_hooks (node);
   cgraph_node_remove_callers (node);
   cgraph_node_remove_callees (node);
+  VEC_free (ipa_opt_pass, heap,
+            node->ipa_transforms_to_apply);
 
   /* Incremental inlining access removed nodes stored in the postorder list.
      */
@@ -1291,6 +1362,7 @@ void
 cgraph_mark_needed_node (struct cgraph_node *node)
 {
   node->needed = 1;
+  gcc_assert (!node->global.inlined_to);
   cgraph_mark_reachable_node (node);
 }
 
@@ -1564,8 +1636,8 @@ cgraph_function_possibly_inlined_p (tree decl)
 /* Create clone of E in the node N represented by CALL_EXPR the callgraph.  */
 struct cgraph_edge *
 cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
-                  gimple call_stmt, gcov_type count_scale, int freq_scale,
-                  int loop_nest, bool update_original)
+                  gimple call_stmt, unsigned stmt_uid, gcov_type count_scale,
+                  int freq_scale, int loop_nest, bool update_original)
 {
   struct cgraph_edge *new_edge;
   gcov_type count = e->count * count_scale / REG_BR_PROB_BASE;
@@ -1578,6 +1650,7 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
 
   new_edge->inline_failed = e->inline_failed;
   new_edge->indirect_call = e->indirect_call;
+  new_edge->lto_stmt_uid = stmt_uid;
   if (update_original)
     {
       e->count -= new_edge->count;
@@ -1596,11 +1669,13 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
    by node.  */
 struct cgraph_node *
 cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
-                  int loop_nest, bool update_original)
+                  int loop_nest, bool update_original,
+                  VEC(cgraph_edge_p,heap) *redirect_callers)
 {
   struct cgraph_node *new_node = cgraph_create_node ();
   struct cgraph_edge *e;
   gcov_type count_scale;
+  unsigned i;
 
   new_node->decl = n->decl;
   new_node->origin = n->origin;
@@ -1611,6 +1686,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
     }
   new_node->analyzed = n->analyzed;
   new_node->local = n->local;
+  new_node->local.externally_visible = false;
   new_node->global = n->global;
   new_node->rtl = n->rtl;
   new_node->count = count;
@@ -1631,9 +1707,17 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
        n->count = 0;
     }
 
+  for (i = 0; VEC_iterate (cgraph_edge_p, redirect_callers, i, e); i++)
+    {
+      /* Redirect calls to the old version node to point to its new
+        version.  */
+      cgraph_redirect_edge_callee (e, new_node);
+    }
+
+
   for (e = n->callees;e; e=e->next_callee)
-    cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest,
-                      update_original);
+    cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid,
+                      count_scale, freq, loop_nest, update_original);
 
   new_node->next_sibling_clone = n->clones;
   if (n->clones)
@@ -1684,8 +1768,6 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
   struct cgraph_node *new_node = NULL;
   tree new_decl;
   struct cgraph_node key, **slot;
-  unsigned i;
-  struct cgraph_edge *e;
 
   gcc_assert  (tree_versionable_function_p (old_decl));
 
@@ -1702,7 +1784,8 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
   SET_DECL_RTL (new_decl, NULL);
 
   new_node = cgraph_clone_node (old_node, old_node->count,
-                               CGRAPH_FREQ_BASE, 0, false);
+                               CGRAPH_FREQ_BASE, 0, false,
+                               redirect_callers);
   new_node->decl = new_decl;
   /* Update the properties.
      Make clone visible only within this translation unit.  Make sure
@@ -1716,6 +1799,31 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
   DECL_WEAK (new_node->decl) = 0;
   new_node->clone.tree_map = tree_map;
   new_node->clone.args_to_skip = args_to_skip;
+  if (!args_to_skip)
+    new_node->clone.combined_args_to_skip = old_node->clone.combined_args_to_skip;
+  else if (old_node->clone.combined_args_to_skip)
+    {
+      int newi = 0, oldi = 0;
+      tree arg;
+      bitmap new_args_to_skip = BITMAP_GGC_ALLOC ();
+      struct cgraph_node *orig_node;
+      for (orig_node = old_node; orig_node->clone_of; orig_node = orig_node->clone_of)
+        ;
+      for (arg = DECL_ARGUMENTS (orig_node->decl); arg; arg = TREE_CHAIN (arg), oldi++)
+       {
+         if (bitmap_bit_p (old_node->clone.combined_args_to_skip, oldi))
+           {
+             bitmap_set_bit (new_args_to_skip, oldi);
+             continue;
+           }
+         if (bitmap_bit_p (args_to_skip, newi))
+           bitmap_set_bit (new_args_to_skip, oldi);
+         newi++;
+       }
+      new_node->clone.combined_args_to_skip = new_args_to_skip;
+    }
+  else
+    new_node->clone.combined_args_to_skip = args_to_skip;
   new_node->local.externally_visible = 0;
   new_node->local.local = 1;
   new_node->lowered = true;
@@ -1736,13 +1844,7 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
       gcc_assert (!*aslot);
       *aslot = new_node;
     }
-   for (i = 0; VEC_iterate (cgraph_edge_p, redirect_callers, i, e); i++)
-     {
-       /* Redirect calls to the old version node to point to its new
-         version.  */
-       cgraph_redirect_edge_callee (e, new_node);
-     }
-  
+
   return new_node;
 }
 
@@ -1869,6 +1971,12 @@ cgraph_add_new_function (tree fndecl, bool lowered)
        current_function_decl = NULL;
        break;
     }
+
+  /* Set a personality if required and we already passed EH lowering.  */
+  if (lowered
+      && (function_needs_eh_personality (DECL_STRUCT_FUNCTION (fndecl))
+         == eh_personality_lang))
+    DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality ();
 }
 
 /* Return true if NODE can be made local for API change.
@@ -1878,7 +1986,8 @@ cgraph_add_new_function (tree fndecl, bool lowered)
 bool
 cgraph_node_can_be_local_p (struct cgraph_node *node)
 {
-  return !node->needed;
+  return (!node->needed
+         && (DECL_COMDAT (node->decl) || !node->local.externally_visible));
 }
 
 /* Bring NODE local.  */
@@ -1889,7 +1998,7 @@ cgraph_make_node_local (struct cgraph_node *node)
   if (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
     {
       DECL_COMDAT (node->decl) = 0;
-      DECL_ONE_ONLY (node->decl) = 0;
+      DECL_COMDAT_GROUP (node->decl) = 0;
       TREE_PUBLIC (node->decl) = 0;
       DECL_WEAK (node->decl) = 0;
       DECL_EXTERNAL (node->decl) = 0;