OSDN Git Service

* cgraphbuild.c (compute_call_stmt_bb_frequency): Accept function argument;
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 May 2009 19:19:51 +0000 (19:19 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 May 2009 19:19:51 +0000 (19:19 +0000)
handle correctly when profile is absent.
(build_cgraph_edges): Update.
(rebuild_cgraph_edges): Update.
* cgraph.c: Do not include varrau.h
(cgraph_set_call_stmt_including_clones, cgraph_create_edge_including_clones):
New function
(cgraph_update_edges_for_call_stmt_node): New stati cfunction.
(cgraph_update_edges_for_call_stmt): Handle clones.
(cgraph_remove_node): Handle clone tree.
(cgraph_remove_node_and_inline_clones): New function.
(dump_cgraph_node): Dump clone tree.
(cgraph_clone_node): Handle clone tree.
(clone_function_name): Bring here from tree-inline.c
(cgraph_create_virtual_clone): New function.
* cgraph.h (ipa_replace_map): Move ehre from ipa.h
(cgraph_clone_info): New function
(strut cgraph_node): Add clone_info and new clone tree pointers.
(cgraph_remove_node_and_inline_clones, cgraph_set_call_stmt_including_clones,
cgraph_create_edge_including_clones, cgraph_create_virtual_clone): Declare.
(cgraph_function_versioning): Use VEC argument.
(compute_call_stmt_bb_frequency): Update prototype.
(cgraph_materialize_all_clones): New function.
* ipa-cp.c (ipcp_update_cloned_node): Remove.
(ipcp_create_replace_map): Update to VECtors.
(ipcp_update_callgraph): Use virtual clones.
(ipcp_update_bb_counts, ipcp_update_edges_counts): Remove.
(ipcp_update_profiling): Do not update local profiling.
(ipcp_insert_stage): Use VECtors and virtual clones.
* cgraphunit.c (verify_cgraph_node): Verify clone tree.
(clone_of_p): New function.
(cgraph_preserve_function_body_p): Use clone tree.
(cgraph_optimize): Materialize clones.
(cgraph_function_versioning): Update for VECtors.
(save_inline_function_body): Use clone tree.
(cgraph_materialize_clone, cgraph_materialize_all_clones): New functions.
* ipa-inline.c (cgraph_default_inline_p): Use analyzed flags.
* ipa.c: Include gimple.h.
(cgraph_remove_unreachable_nodes): Use clone tree.
* ipa-prop.c (ipa_note_param_call): Update call of compute_call_stmt_bb_frequency.
* ipa-prop.h (ipa_replace_map): Move to cgraph.h.
* tree-inline.c: Do not include varray.h; do not include gt-tree-inline.h
(copy_bb): Handle updating of clone tree; add new edge when new call
appears.
(expand_call_inline): Be strict about every call having edge.
(clone_fn_id_num, clone_function_name): Move to cgraph.c.
(delete_unreachable_blocks_update_callgraph): New function.
(tree_function_versioning): Use VECtors; always remove unreachable blocks
and fold conditionals.
* tree-inline.h: Do not include varray.h
(tree_function_versioning): Remove.
* Makefile.in (GTFILES): Remove tree-inline.c
* passes.c (do_per_function): Do only functions having body.
* ipa-struct-reorg.c (do_reorg_1, collect_data_accesses): Handle cone tree.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@147294 138bc75d-0d04-0410-961f-82ee72b054a4

16 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphbuild.c
gcc/cgraphunit.c
gcc/ipa-cp.c
gcc/ipa-inline.c
gcc/ipa-prop.c
gcc/ipa-prop.h
gcc/ipa-struct-reorg.c
gcc/ipa.c
gcc/passes.c
gcc/tree-cfg.c
gcc/tree-inline.c
gcc/tree-inline.h

index ae61006..508436b 100644 (file)
@@ -1,3 +1,60 @@
+2009-05-08  Jan Hubicka  <jh@suse.cz>
+
+       * cgraphbuild.c (compute_call_stmt_bb_frequency): Accept function argument;
+       handle correctly when profile is absent.
+       (build_cgraph_edges): Update.
+       (rebuild_cgraph_edges): Update.
+       * cgraph.c: Do not include varrau.h 
+       (cgraph_set_call_stmt_including_clones, cgraph_create_edge_including_clones):
+       New function
+       (cgraph_update_edges_for_call_stmt_node): New stati cfunction.
+       (cgraph_update_edges_for_call_stmt): Handle clones.
+       (cgraph_remove_node): Handle clone tree.
+       (cgraph_remove_node_and_inline_clones): New function.
+       (dump_cgraph_node): Dump clone tree.
+       (cgraph_clone_node): Handle clone tree.
+       (clone_function_name): Bring here from tree-inline.c
+       (cgraph_create_virtual_clone): New function.
+       * cgraph.h (ipa_replace_map): Move ehre from ipa.h
+       (cgraph_clone_info): New function
+       (strut cgraph_node): Add clone_info and new clone tree pointers.
+       (cgraph_remove_node_and_inline_clones, cgraph_set_call_stmt_including_clones,
+       cgraph_create_edge_including_clones, cgraph_create_virtual_clone): Declare.
+       (cgraph_function_versioning): Use VEC argument.
+       (compute_call_stmt_bb_frequency): Update prototype.
+       (cgraph_materialize_all_clones): New function.
+       * ipa-cp.c (ipcp_update_cloned_node): Remove.
+       (ipcp_create_replace_map): Update to VECtors.
+       (ipcp_update_callgraph): Use virtual clones.
+       (ipcp_update_bb_counts, ipcp_update_edges_counts): Remove.
+       (ipcp_update_profiling): Do not update local profiling.
+       (ipcp_insert_stage): Use VECtors and virtual clones.
+       * cgraphunit.c (verify_cgraph_node): Verify clone tree.
+       (clone_of_p): New function.
+       (cgraph_preserve_function_body_p): Use clone tree.
+       (cgraph_optimize): Materialize clones.
+       (cgraph_function_versioning): Update for VECtors.
+       (save_inline_function_body): Use clone tree.
+       (cgraph_materialize_clone, cgraph_materialize_all_clones): New functions.
+       * ipa-inline.c (cgraph_default_inline_p): Use analyzed flags.
+       * ipa.c: Include gimple.h.
+       (cgraph_remove_unreachable_nodes): Use clone tree.
+       * ipa-prop.c (ipa_note_param_call): Update call of compute_call_stmt_bb_frequency.
+       * ipa-prop.h (ipa_replace_map): Move to cgraph.h.
+       * tree-inline.c: Do not include varray.h; do not include gt-tree-inline.h
+       (copy_bb): Handle updating of clone tree; add new edge when new call
+       appears.
+       (expand_call_inline): Be strict about every call having edge.
+       (clone_fn_id_num, clone_function_name): Move to cgraph.c.
+       (delete_unreachable_blocks_update_callgraph): New function.
+       (tree_function_versioning): Use VECtors; always remove unreachable blocks
+       and fold conditionals.
+       * tree-inline.h: Do not include varray.h
+       (tree_function_versioning): Remove.
+       * Makefile.in (GTFILES): Remove tree-inline.c
+       * passes.c (do_per_function): Do only functions having body.
+       * ipa-struct-reorg.c (do_reorg_1, collect_data_accesses): Handle cone tree.
+
 2009-05-08  H.J. Lu  <hongjiu.lu@intel.com>
            Andrew Morrow  <acm@google.com>
 
index 4cd07f7..9a4d62b 100644 (file)
@@ -3342,7 +3342,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/tree-ssa-propagate.c \
   $(srcdir)/tree-phinodes.c \
   $(srcdir)/ipa-reference.c \
-  $(srcdir)/tree-ssa-structalias.c $(srcdir)/tree-inline.c \
+  $(srcdir)/tree-ssa-structalias.c \
   $(srcdir)/tree-ssa-alias.h \
   @all_gtfiles@
 
index ce696e2..2f68d94 100644 (file)
@@ -78,7 +78,6 @@ The callgraph:
 #include "target.h"
 #include "basic-block.h"
 #include "cgraph.h"
-#include "varray.h"
 #include "output.h"
 #include "intl.h"
 #include "gimple.h"
@@ -628,7 +627,7 @@ cgraph_edge (struct cgraph_node *node, gimple call_stmt)
 }
 
 
-/* Change field call_smt of edge E to NEW_STMT.  */
+/* Change field call_stmt of edge E to NEW_STMT.  */
 
 void
 cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt)
@@ -655,6 +654,79 @@ 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.  */
+
+void
+cgraph_set_call_stmt_including_clones (struct cgraph_node *orig,
+                                      gimple old_stmt, gimple new_stmt)
+{
+  struct cgraph_node *node;
+  struct cgraph_edge *edge = cgraph_edge (orig, old_stmt);
+
+  if (edge)
+    cgraph_set_call_stmt (edge, new_stmt);
+  if (orig->clones)
+    for (node = orig->clones; node != orig;)
+      {
+       struct cgraph_edge *edge = cgraph_edge (node, old_stmt);
+       if (edge)
+         cgraph_set_call_stmt (edge, new_stmt);
+       if (node->clones)
+         node = node->clones;
+       else if (node->next_sibling_clone)
+         node = node->next_sibling_clone;
+       else
+         {
+           while (node != orig && !node->next_sibling_clone)
+             node = node->clone_of;
+           if (node != orig)
+             node = node->next_sibling_clone;
+         }
+      }
+}
+
+/* Like cgraph_create_edge walk the clone tree and update all clones sharing
+   same function body.  
+   
+   TODO: COUNT and LOOP_DEPTH should be properly distributed based on relative
+   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_inline_failed_t reason)
+{
+  struct cgraph_node *node;
+
+  cgraph_create_edge (orig, callee, stmt, count, freq, loop_depth)->inline_failed =
+    reason;
+
+  if (orig->clones)
+    for (node = orig->clones; 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;
+
+       if (node->clones)
+         node = node->clones;
+       else if (node->next_sibling_clone)
+         node = node->next_sibling_clone;
+       else
+         {
+           while (node != orig && !node->next_sibling_clone)
+             node = node->clone_of;
+           if (node != orig)
+             node = node->next_sibling_clone;
+         }
+      }
+}
+
 /* Give initial reasons why inlining would fail on EDGE.  This gets either
    nullified or usually overwritten by more precise reasons later.  */
 
@@ -828,12 +900,12 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n)
 /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL
    OLD_STMT changed into NEW_STMT.  */
 
-void
-cgraph_update_edges_for_call_stmt (gimple old_stmt, gimple new_stmt)
+static void
+cgraph_update_edges_for_call_stmt_node (struct cgraph_node *node,
+                                       gimple old_stmt, gimple new_stmt)
 {
   tree new_call = (is_gimple_call (new_stmt)) ? gimple_call_fn (new_stmt) : 0;
   tree old_call = (is_gimple_call (old_stmt)) ? gimple_call_fn (old_stmt) : 0;
-  struct cgraph_node *node = cgraph_node (cfun->decl);
 
   if (old_call != new_call)
     {
@@ -870,6 +942,34 @@ cgraph_update_edges_for_call_stmt (gimple old_stmt, gimple new_stmt)
     }
 }
 
+/* Update or remove the corresponding cgraph edge if a GIMPLE_CALL
+   OLD_STMT changed into NEW_STMT.  */
+
+void
+cgraph_update_edges_for_call_stmt (gimple old_stmt, gimple new_stmt)
+{
+  struct cgraph_node *orig = cgraph_node (cfun->decl);
+  struct cgraph_node *node;
+
+  cgraph_update_edges_for_call_stmt_node (orig, old_stmt, new_stmt);
+  if (orig->clones)
+    for (node = orig->clones; node != orig;)
+      {
+        cgraph_update_edges_for_call_stmt_node (node, old_stmt, new_stmt);
+       if (node->clones)
+         node = node->clones;
+       else if (node->next_sibling_clone)
+         node = node->next_sibling_clone;
+       else
+         {
+           while (node != orig && !node->next_sibling_clone)
+             node = node->clone_of;
+           if (node != orig)
+             node = node->next_sibling_clone;
+         }
+      }
+}
+
 
 /* Remove all callees from the node.  */
 
@@ -998,24 +1098,100 @@ cgraph_remove_node (struct cgraph_node *node)
   slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
   if (*slot == node)
     {
-      if (node->next_clone)
-      {
-       struct cgraph_node *new_node = node->next_clone;
+      struct cgraph_node *next_inline_clone;
 
-       *slot = new_node;
-       node->next_clone->prev_clone = NULL;
-      }
+      for (next_inline_clone = node->clones;
+          next_inline_clone && next_inline_clone->decl != node->decl;
+          next_inline_clone = next_inline_clone->next_sibling_clone)
+       ;
+
+      /* If there is inline clone of the node being removed, we need
+         to put it into the position of removed node and reorganize all
+        other clones to be based on it.  */
+      if (next_inline_clone)
+       {
+         struct cgraph_node *n;
+         struct cgraph_node *new_clones;
+
+         *slot = next_inline_clone;
+
+         /* Unlink inline clone from the list of clones of removed node.  */
+         if (next_inline_clone->next_sibling_clone)
+           next_inline_clone->next_sibling_clone->prev_sibling_clone
+             = next_inline_clone->prev_sibling_clone;
+         if (next_inline_clone->prev_sibling_clone)
+           {
+             next_inline_clone->prev_sibling_clone->next_sibling_clone
+               = next_inline_clone->next_sibling_clone;
+           }
+         else
+          node->clones = next_inline_clone->next_sibling_clone;
+
+         new_clones = node->clones;
+         node->clones = NULL;
+
+         /* Copy clone info.  */
+         next_inline_clone->clone = node->clone;
+
+         /* Now place it into clone tree at same level at NODE.  */
+         next_inline_clone->clone_of = node->clone_of;
+         next_inline_clone->prev_sibling_clone = NULL;
+         next_inline_clone->next_sibling_clone = NULL;
+         if (node->clone_of)
+           {
+             next_inline_clone->next_sibling_clone = node->clone_of->clones;
+             node->clone_of->clones = next_inline_clone;
+           }
+
+         /* Merge the clone list.  */
+         if (new_clones)
+           {
+             if (!next_inline_clone->clones)
+               next_inline_clone->clones = new_clones;
+             else
+               {
+                 n = next_inline_clone->clones;
+                 while (n->next_sibling_clone)
+                   n =  n->next_sibling_clone;
+                 n->next_sibling_clone = new_clones;
+                 new_clones->prev_sibling_clone = n;
+               }
+           }
+
+         /* Update clone_of pointers.  */
+         n = new_clones;
+         while (n)
+           {
+             n->clone_of = next_inline_clone;
+             n = n->next_sibling_clone;
+           }
+       }
       else
        {
          htab_clear_slot (cgraph_hash, slot);
          kill_body = true;
        }
+
     }
   else
+    gcc_assert (node->clone_of);
+  if (node->prev_sibling_clone)
+    node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
+  else if (node->clone_of)
+    node->clone_of->clones = node->next_sibling_clone;
+  if (node->next_sibling_clone)
+    node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
+  if (node->clones)
     {
-      node->prev_clone->next_clone = node->next_clone;
-      if (node->next_clone)
-       node->next_clone->prev_clone = node->prev_clone;
+      struct cgraph_node *n;
+
+      for (n = node->clones; n->next_sibling_clone; n = n->next_sibling_clone)
+       n->clone_of = node->clone_of;
+      n->clone_of = node->clone_of;
+      n->next_sibling_clone = node->clone_of->clones;
+      if (node->clone_of->clones)
+       node->clone_of->clones->prev_sibling_clone = n;
+      node->clone_of->clones = node->clones;
     }
 
   /* While all the clones are removed after being proceeded, the function
@@ -1025,7 +1201,7 @@ cgraph_remove_node (struct cgraph_node *node)
   if (!kill_body && *slot)
     {
       struct cgraph_node *n = (struct cgraph_node *) *slot;
-      if (!n->next_clone && !n->global.inlined_to
+      if (!n->clones && !n->clone_of && !n->global.inlined_to
          && (cgraph_global_info_ready
              && (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl))))
        kill_body = true;
@@ -1059,6 +1235,21 @@ cgraph_remove_node (struct cgraph_node *node)
   free_nodes = node;
 }
 
+/* Remove the node from cgraph.  */
+
+void
+cgraph_remove_node_and_inline_clones (struct cgraph_node *node)
+{
+  struct cgraph_edge *e, *next;
+  for (e = node->callees; e; e = next)
+    {
+      next = e->next_callee;
+      if (!e->inline_failed)
+        cgraph_remove_node_and_inline_clones (e->callee);
+    }
+  cgraph_remove_node (node);
+}
+
 /* Notify finalize_compilation_unit that given node is reachable.  */
 
 void
@@ -1166,6 +1357,10 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
     fprintf (f, " (inline copy in %s/%i)",
             cgraph_node_name (node->global.inlined_to),
             node->global.inlined_to->uid);
+  if (node->clone_of)
+    fprintf (f, " (clone of %s/%i)",
+            cgraph_node_name (node->clone_of),
+            node->clone_of->uid);
   if (cgraph_function_flags_ready)
     fprintf (f, " availability:%s",
             cgraph_availability_names [cgraph_function_body_availability (node)]);
@@ -1382,6 +1577,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
   new_node->global = n->global;
   new_node->rtl = n->rtl;
   new_node->count = count;
+  new_node->clone = n->clone;
   if (n->count)
     {
       if (new_node->count > n->count)
@@ -1402,16 +1598,117 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
     cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest,
                       update_original);
 
-  new_node->next_clone = n->next_clone;
-  new_node->prev_clone = n;
-  n->next_clone = new_node;
-  if (new_node->next_clone)
-    new_node->next_clone->prev_clone = new_node;
+  new_node->next_sibling_clone = n->clones;
+  if (n->clones)
+    n->clones->prev_sibling_clone = new_node;
+  n->clones = new_node;
+  new_node->clone_of = n;
 
   cgraph_call_node_duplication_hooks (n, new_node);
   return new_node;
 }
 
+/* Create a new name for omp child function.  Returns an identifier.  */
+
+static GTY(()) unsigned int clone_fn_id_num;
+
+static tree
+clone_function_name (tree decl)
+{
+  tree name = DECL_ASSEMBLER_NAME (decl);
+  size_t len = IDENTIFIER_LENGTH (name);
+  char *tmp_name, *prefix;
+
+  prefix = XALLOCAVEC (char, len + strlen ("_clone") + 1);
+  memcpy (prefix, IDENTIFIER_POINTER (name), len);
+  strcpy (prefix + len, "_clone");
+#ifndef NO_DOT_IN_LABEL
+  prefix[len] = '.';
+#elif !defined NO_DOLLAR_IN_LABEL
+  prefix[len] = '$';
+#endif
+  ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++);
+  return get_identifier (tmp_name);
+}
+
+/* Create callgraph node clone with new declaration.  The actual body will
+   be copied later at compilation stage.  
+
+   TODO: after merging in ipa-sra use function call notes instead of args_to_skip
+   bitmap interface.
+   */
+struct cgraph_node *
+cgraph_create_virtual_clone (struct cgraph_node *old_node,
+                            VEC(cgraph_edge_p,heap) *redirect_callers,
+                            VEC(ipa_replace_map_p,gc) *tree_map,
+                            bitmap args_to_skip)
+{
+  tree old_decl = old_node->decl;
+  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));
+
+  /* Make a new FUNCTION_DECL tree node */
+  if (!args_to_skip)
+    new_decl = copy_node (old_decl);
+  else
+    new_decl = build_function_decl_skip_args (old_decl, args_to_skip);
+  DECL_STRUCT_FUNCTION (new_decl) = NULL;
+
+  /* Generate a new name for the new version. */
+  DECL_NAME (new_decl) = clone_function_name (old_decl);
+  SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
+  SET_DECL_RTL (new_decl, NULL);
+
+  new_node = cgraph_clone_node (old_node, old_node->count,
+                               CGRAPH_FREQ_BASE, 0, false);
+  new_node->decl = new_decl;
+  /* Update the properties.
+     Make clone visible only within this translation unit.  Make sure
+     that is not weak also.
+     ??? We cannot use COMDAT linkage because there is no
+     ABI support for this.  */
+  DECL_EXTERNAL (new_node->decl) = 0;
+  DECL_ONE_ONLY (new_node->decl) = 0;
+  TREE_PUBLIC (new_node->decl) = 0;
+  DECL_COMDAT (new_node->decl) = 0;
+  DECL_WEAK (new_node->decl) = 0;
+  new_node->clone.tree_map = tree_map;
+  new_node->clone.args_to_skip = args_to_skip;
+  new_node->local.externally_visible = 0;
+  new_node->local.local = 1;
+  new_node->lowered = true;
+  new_node->reachable = true;
+
+  key.decl = new_decl;
+  slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
+  gcc_assert (!*slot);
+  *slot = new_node;
+  if (assembler_name_hash)
+    {
+      void **aslot;
+      tree name = DECL_ASSEMBLER_NAME (new_decl);
+
+      aslot = htab_find_slot_with_hash (assembler_name_hash, name,
+                                       decl_assembler_name_hash (name),
+                                       INSERT);
+      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;
+}
+
 /* NODE is no longer nested function; update cgraph accordingly.  */
 void
 cgraph_unnest_node (struct cgraph_node *node)
index b100fa6..b94fcff 100644 (file)
@@ -119,6 +119,29 @@ struct GTY(()) cgraph_rtl_info {
    unsigned int preferred_incoming_stack_boundary;
 };
 
+/* Represent which DECL tree (or reference to such tree)
+   will be replaced by another tree while versioning.  */
+struct GTY(()) ipa_replace_map
+{
+  /* The tree that will be replaced.  */
+  tree old_tree;
+  /* The new (replacing) tree.  */
+  tree new_tree;
+  /* True when a substitution should be done, false otherwise.  */
+  bool replace_p;
+  /* True when we replace a reference to old_tree.  */
+  bool ref_p;
+};
+typedef struct ipa_replace_map *ipa_replace_map_p;
+DEF_VEC_P(ipa_replace_map_p);
+DEF_VEC_ALLOC_P(ipa_replace_map_p,gc);
+
+struct GTY(()) cgraph_clone_info
+{
+  VEC(ipa_replace_map_p,gc)* tree_map;
+  bitmap args_to_skip;
+};
+
 /* The cgraph data structure.
    Each function decl has assigned cgraph_node listing callees and callers.  */
 
@@ -137,8 +160,10 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   /* Pointer to the next function in cgraph_nodes_queue.  */
   struct cgraph_node *next_needed;
   /* Pointer to the next clone.  */
-  struct cgraph_node *next_clone;
-  struct cgraph_node *prev_clone;
+  struct cgraph_node *next_sibling_clone;
+  struct cgraph_node *prev_sibling_clone;
+  struct cgraph_node *clones;
+  struct cgraph_node *clone_of;
   /* For functions with many calls sites it holds map from call expression
      to the edge to speed up cgraph_edge function.  */
   htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
@@ -148,6 +173,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   struct cgraph_local_info local;
   struct cgraph_global_info global;
   struct cgraph_rtl_info rtl;
+  struct cgraph_clone_info clone;
 
   /* Expected number of executions: calculated in profile.c.  */
   gcov_type count;
@@ -344,6 +370,7 @@ void debug_cgraph_node (struct cgraph_node *);
 void cgraph_insert_node_to_hashtable (struct cgraph_node *node);
 void cgraph_remove_edge (struct cgraph_edge *);
 void cgraph_remove_node (struct cgraph_node *);
+void cgraph_remove_node_and_inline_clones (struct cgraph_node *);
 void cgraph_release_function_body (struct cgraph_node *);
 void cgraph_node_remove_callees (struct cgraph_node *node);
 struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
@@ -353,6 +380,11 @@ struct cgraph_node *cgraph_node (tree);
 struct cgraph_node *cgraph_node_for_asm (tree asmname);
 struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
 void cgraph_set_call_stmt (struct cgraph_edge *, gimple);
+void cgraph_set_call_stmt_including_clones (struct cgraph_node *, gimple, gimple);
+void cgraph_create_edge_including_clones (struct cgraph_node *,
+                                         struct cgraph_node *,
+                                         gimple, gcov_type, int, int,
+                                         cgraph_inline_failed_t);
 void cgraph_update_edges_for_call_stmt (gimple, gimple);
 struct cgraph_local_info *cgraph_local_info (tree);
 struct cgraph_global_info *cgraph_global_info (tree);
@@ -374,6 +406,10 @@ void cgraph_unnest_node (struct cgraph_node *);
 enum availability cgraph_function_body_availability (struct cgraph_node *);
 void cgraph_add_new_function (tree, bool);
 const char* cgraph_inline_failed_string (cgraph_inline_failed_t);
+struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node *old_node,
+                                                 VEC(cgraph_edge_p,heap)*,
+                                                 VEC(ipa_replace_map_p,gc)* tree_map,
+                                                 bitmap args_to_skip);
 
 /* In cgraphunit.c  */
 void cgraph_finalize_function (tree, bool);
@@ -391,8 +427,9 @@ void cgraph_reset_static_var_maps (void);
 void init_cgraph (void);
 struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
                                                VEC(cgraph_edge_p,heap)*,
-                                               varray_type,
+                                               VEC(ipa_replace_map_p,gc)*,
                                                bitmap);
+void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bitmap);
 void cgraph_analyze_function (struct cgraph_node *);
 struct cgraph_node *save_inline_function_body (struct cgraph_node *);
 void record_references_in_initializer (tree);
@@ -421,10 +458,11 @@ struct cgraph_2edge_hook_list *cgraph_add_edge_duplication_hook (cgraph_2edge_ho
 void cgraph_remove_edge_duplication_hook (struct cgraph_2edge_hook_list *);
 struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook (cgraph_2node_hook, void *);
 void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *);
+void cgraph_materialize_all_clones (void);
 
 /* In cgraphbuild.c  */
 unsigned int rebuild_cgraph_edges (void);
-int compute_call_stmt_bb_frequency (basic_block bb);
+int compute_call_stmt_bb_frequency (tree, basic_block bb);
 
 /* In ipa.c  */
 bool cgraph_remove_unreachable_nodes (bool, FILE *);
index f244a1e..fb56ce5 100644 (file)
@@ -81,11 +81,14 @@ record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 /* Computes the frequency of the call statement so that it can be stored in
    cgraph_edge.  BB is the basic block of the call statement.  */
 int
-compute_call_stmt_bb_frequency (basic_block bb)
+compute_call_stmt_bb_frequency (tree decl, basic_block bb)
 {
   int entry_freq = ENTRY_BLOCK_PTR->frequency;
   int freq = bb->frequency;
 
+  if (profile_status_for_function (DECL_STRUCT_FUNCTION (decl)) == PROFILE_ABSENT)
+    return CGRAPH_FREQ_BASE;
+
   if (!entry_freq)
     entry_freq = 1, freq++;
 
@@ -121,7 +124,7 @@ build_cgraph_edges (void)
            size_t i;
            size_t n = gimple_call_num_args (stmt);
            cgraph_create_edge (node, cgraph_node (decl), stmt,
-                               bb->count, compute_call_stmt_bb_frequency (bb),
+                               bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb),
                                bb->loop_depth);
            for (i = 0; i < n; i++)
              walk_tree (gimple_call_arg_ptr (stmt, i), record_reference,
@@ -224,7 +227,9 @@ rebuild_cgraph_edges (void)
 
        if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
          cgraph_create_edge (node, cgraph_node (decl), stmt,
-                             bb->count, compute_call_stmt_bb_frequency (bb),
+                             bb->count,
+                             compute_call_stmt_bb_frequency
+                               (current_function_decl, bb),
                              bb->loop_depth);
 
       }
index 9b7ca8c..9366ebe 100644 (file)
@@ -548,12 +548,20 @@ cgraph_mark_if_needed (tree decl)
     cgraph_mark_needed_node (node);
 }
 
+/* Return TRUE if NODE2 is equivalent to NODE or its clone.  */
+static bool
+clone_of_p (struct cgraph_node *node, struct cgraph_node *node2)
+{
+  while (node != node2 && node2)
+    node2 = node2->clone_of;
+  return node2 != NULL;
+}
+
 /* Verify cgraph nodes of given cgraph node.  */
 void
 verify_cgraph_node (struct cgraph_node *node)
 {
   struct cgraph_edge *e;
-  struct cgraph_node *main_clone;
   struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl);
   struct function *saved_cfun = cfun;
   basic_block this_block;
@@ -629,17 +637,53 @@ verify_cgraph_node (struct cgraph_node *node)
       error_found = true;
     }
 
-  for (main_clone = cgraph_node (node->decl); main_clone;
-       main_clone = main_clone->next_clone)
-    if (main_clone == node)
-      break;
   if (!cgraph_node (node->decl))
     {
       error ("node not found in cgraph_hash");
       error_found = true;
     }
 
-  if (node->analyzed
+  if (node->clone_of)
+    {
+      struct cgraph_node *n;
+      for (n = node->clone_of->clones; n; n = n->next_sibling_clone)
+        if (n == node)
+         break;
+      if (!n)
+       {
+         error ("node has wrong clone_of");
+         error_found = true;
+       }
+    }
+  if (node->clones)
+    {
+      struct cgraph_node *n;
+      for (n = node->clones; n; n = n->next_sibling_clone)
+        if (n->clone_of != node)
+         break;
+      if (n)
+       {
+         error ("node has wrong clone list");
+         error_found = true;
+       }
+    }
+  if ((node->prev_sibling_clone || node->next_sibling_clone) && !node->clone_of)
+    {
+       error ("node is in clone list but it is not clone");
+       error_found = true;
+    }
+  if (!node->prev_sibling_clone && node->clone_of && node->clone_of->clones != node)
+    {
+      error ("node has wrong prev_clone pointer");
+      error_found = true;
+    }
+  if (node->prev_sibling_clone && node->prev_sibling_clone->next_sibling_clone != node)
+    {
+      error ("double linked list of clones corrupted");
+      error_found = true;
+    }
+
+  if (node->analyzed && gimple_has_body_p (node->decl)
       && !TREE_ASM_WRITTEN (node->decl)
       && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
     {
@@ -668,8 +712,8 @@ verify_cgraph_node (struct cgraph_node *node)
                            debug_gimple_stmt (stmt);
                            error_found = true;
                          }
-                       if (e->callee->decl != cgraph_node (decl)->decl
-                           && e->inline_failed)
+                       if (!clone_of_p (cgraph_node (decl), e->callee)
+                           && !e->callee->global.inlined_to)
                          {
                            error ("edge points to wrong declaration:");
                            debug_tree (e->callee->decl);
@@ -1227,9 +1271,9 @@ cgraph_preserve_function_body_p (tree decl)
 
   gcc_assert (cgraph_global_info_ready);
   /* Look if there is any clone around.  */
-  for (node = cgraph_node (decl); node; node = node->next_clone)
-    if (node->global.inlined_to)
-      return true;
+  node = cgraph_node (decl);
+  if (node->clones)
+    return true;
   return false;
 }
 
@@ -1312,6 +1356,7 @@ cgraph_optimize (void)
   verify_cgraph ();
 #endif
 
+  cgraph_materialize_all_clones ();
   cgraph_mark_functions_to_output ();
 
   cgraph_state = CGRAPH_STATE_EXPANSION;
@@ -1528,7 +1573,7 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
 struct cgraph_node *
 cgraph_function_versioning (struct cgraph_node *old_version_node,
                            VEC(cgraph_edge_p,heap) *redirect_callers,
-                           varray_type tree_map,
+                           VEC (ipa_replace_map_p,gc)* tree_map,
                            bitmap args_to_skip)
 {
   tree old_decl = old_version_node->decl;
@@ -1581,19 +1626,50 @@ cgraph_function_versioning (struct cgraph_node *old_version_node,
 struct cgraph_node *
 save_inline_function_body (struct cgraph_node *node)
 {
-  struct cgraph_node *first_clone;
+  struct cgraph_node *first_clone, *n;
 
   gcc_assert (node == cgraph_node (node->decl));
 
   cgraph_lower_function (node);
 
-  first_clone = node->next_clone;
+  first_clone = node->clones;
 
   first_clone->decl = copy_node (node->decl);
-  node->next_clone = NULL;
-  first_clone->prev_clone = NULL;
   cgraph_insert_node_to_hashtable (first_clone);
   gcc_assert (first_clone == cgraph_node (first_clone->decl));
+  if (first_clone->next_sibling_clone)
+    {
+      for (n = first_clone->next_sibling_clone; n->next_sibling_clone; n = n->next_sibling_clone)
+        n->clone_of = first_clone;
+      n->clone_of = first_clone;
+      n->next_sibling_clone = first_clone->clones;
+      if (first_clone->clones)
+        first_clone->clones->prev_sibling_clone = n;
+      first_clone->clones = first_clone->next_sibling_clone;
+      first_clone->next_sibling_clone->prev_sibling_clone = NULL;
+      first_clone->next_sibling_clone = NULL;
+      gcc_assert (!first_clone->prev_sibling_clone);
+    }
+  first_clone->clone_of = NULL;
+  node->clones = NULL;
+
+  if (first_clone->clones)
+    for (n = first_clone->clones; n != first_clone;)
+      {
+        gcc_assert (n->decl == node->decl);
+       n->decl = first_clone->decl;
+       if (n->clones)
+         n = n->clones;
+       else if (n->next_sibling_clone)
+         n = n->next_sibling_clone;
+       else
+         {
+           while (n != first_clone && !n->next_sibling_clone)
+             n = n->clone_of;
+           if (n != first_clone)
+             n = n->next_sibling_clone;
+         }
+      }
 
   /* Copy the OLD_VERSION_NODE function tree to the new version.  */
   tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL);
@@ -1603,12 +1679,136 @@ save_inline_function_body (struct cgraph_node *node)
   TREE_PUBLIC (first_clone->decl) = 0;
   DECL_COMDAT (first_clone->decl) = 0;
 
-  for (node = first_clone->next_clone; node; node = node->next_clone)
-    node->decl = first_clone->decl;
 #ifdef ENABLE_CHECKING
   verify_cgraph_node (first_clone);
 #endif
   return first_clone;
 }
 
+/* Given virtual clone, turn it into actual clone.  */
+static void
+cgraph_materialize_clone (struct cgraph_node *node)
+{
+  bitmap_obstack_initialize (NULL);
+  /* Copy the OLD_VERSION_NODE function tree to the new version.  */
+  tree_function_versioning (node->clone_of->decl, node->decl,
+                           node->clone.tree_map, true,
+                           node->clone.args_to_skip);
+
+  /* Function is no longer clone.  */
+  if (node->next_sibling_clone)
+    node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
+  if (node->prev_sibling_clone)
+    node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
+  else
+    node->clone_of->clones = node->next_sibling_clone;
+  node->next_sibling_clone = NULL;
+  node->prev_sibling_clone = NULL;
+  node->clone_of = NULL;
+  bitmap_obstack_release (NULL);
+}
+
+/* Once all functions from compilation unit are in memory, produce all clones
+   and update all calls.
+   We might also do this on demand if we don't want to bring all functions to
+   memory prior compilation, but current WHOPR implementation does that and it is
+   is bit easier to keep everything right in this order.  */
+void
+cgraph_materialize_all_clones (void)
+{
+  struct cgraph_node *node;
+  bool stabilized = false;
+
+  if (cgraph_dump_file)
+    fprintf (cgraph_dump_file, "Materializing clones\n");
+#ifdef ENABLE_CHECKING
+  verify_cgraph ();
+#endif
+
+  /* We can also do topological order, but number of iterations should be
+     bounded by number of IPA passes since single IPA pass is probably not
+     going to create clones of clones it created itself.  */
+  while (!stabilized)
+    {
+      stabilized = true;
+      for (node = cgraph_nodes; node; node = node->next)
+        {
+         if (node->clone_of && node->decl != node->clone_of->decl
+             && !gimple_has_body_p (node->decl))
+           {
+             if (gimple_has_body_p (node->clone_of->decl))
+               {
+                 if (cgraph_dump_file)
+                   fprintf (cgraph_dump_file, "  clonning %s to %s",
+                            cgraph_node_name (node->clone_of),
+                            cgraph_node_name (node));
+                 cgraph_materialize_clone (node);
+               }
+             else
+               stabilized = false;
+           }
+       }
+    }
+  if (cgraph_dump_file)
+    fprintf (cgraph_dump_file, "Updating call sites\n");
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->analyzed && gimple_has_body_p (node->decl)
+        && (!node->clone_of || node->clone_of->decl != node->decl))
+      {
+        struct cgraph_edge *e;
+
+       current_function_decl = node->decl;
+        push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+       for (e = node->callees; e; e = e->next_callee)
+         {
+           tree decl = gimple_call_fndecl (e->call_stmt);
+           if (decl != e->callee->decl)
+             {
+               gimple new_stmt;
+               gimple_stmt_iterator gsi;
+               
+               if (cgraph_dump_file)
+                 {
+                   fprintf (cgraph_dump_file, "updating call of %s in %s:",
+                            cgraph_node_name (node),
+                            cgraph_node_name (e->callee));
+                   print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
+                 }
+
+               if (e->callee->clone.args_to_skip)
+                 new_stmt = gimple_call_copy_skip_args (e->call_stmt,
+                                                        e->callee->clone.args_to_skip);
+               else
+                 new_stmt = e->call_stmt;
+               if (gimple_vdef (new_stmt)
+                   && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
+                 SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+                gimple_call_set_fndecl (new_stmt, e->callee->decl);
+
+               gsi = gsi_for_stmt (e->call_stmt);
+               gsi_replace (&gsi, new_stmt, true);
+
+               /* Update EH information too, just in case.  */
+               if (!stmt_could_throw_p (new_stmt)
+                   && lookup_stmt_eh_region (new_stmt))
+                 remove_stmt_from_eh_region (new_stmt);
+
+               cgraph_set_call_stmt_including_clones (node, e->call_stmt, new_stmt);
+
+               if (cgraph_dump_file)
+                 {
+                   fprintf (cgraph_dump_file, "  updated to:");
+                   print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
+                 }
+             }
+         }
+       pop_cfun ();
+       current_function_decl = NULL;
+#ifdef ENABLE_CHECKING
+        verify_cgraph_node (node);
+#endif
+      }
+  cgraph_remove_unreachable_nodes (false, cgraph_dump_file);
+}
+
 #include "gt-cgraphunit.h"
index 21dd887..d6390b0 100644 (file)
@@ -186,34 +186,6 @@ ipcp_analyze_node (struct cgraph_node *node)
   ipa_detect_param_modifications (node);
 }
 
-/* Recompute all local information since node might've got new
-   direct calls after cloning.  */
-static void
-ipcp_update_cloned_node (struct cgraph_node *new_node)
-{
-  /* We might've introduced new direct calls.  */
-  push_cfun (DECL_STRUCT_FUNCTION (new_node->decl));
-  current_function_decl = new_node->decl;
-  rebuild_cgraph_edges ();
-
-  /* Indirect inlinng rely on fact that we've already analyzed
-     the body..  */
-  if (flag_indirect_inlining)
-    {
-      struct cgraph_edge *cs;
-
-      ipcp_analyze_node (new_node);
-
-      for (cs = new_node->callees; cs; cs = cs->next_callee)
-       {
-         ipa_count_arguments (cs);
-         ipa_compute_jump_functions (cs);
-       }
-    }
-  pop_cfun ();
-  current_function_decl = NULL;
-}
-
 /* Return scale for NODE.  */
 static inline gcov_type
 ipcp_get_node_scale (struct cgraph_node *node)
@@ -756,98 +728,6 @@ ipcp_print_call_profile_counts (FILE * f)
     }
 }
 
-/* Print all counts and probabilities of cfg edges of all functions.  */
-static void
-ipcp_print_edge_profiles (FILE * f)
-{
-  struct cgraph_node *node;
-  basic_block bb;
-  edge_iterator ei;
-  edge e;
-
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      fprintf (f, "function %s: \n", cgraph_node_name (node));
-      if (node->analyzed)
-       {
-         bb =
-           ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
-         fprintf (f, "ENTRY: ");
-         fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                  " %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
-
-         if (bb->succs)
-           FOR_EACH_EDGE (e, ei, bb->succs)
-           {
-             if (e->dest ==
-                 EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
-                                              (node->decl)))
-               fprintf (f, "edge ENTRY -> EXIT,  Count");
-             else
-               fprintf (f, "edge ENTRY -> %d,  Count", e->dest->index);
-             fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                      " Prob %d\n", (HOST_WIDE_INT) e->count,
-                      e->probability);
-           }
-         FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-         {
-           fprintf (f, "bb[%d]: ", bb->index);
-           fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                    " %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
-           FOR_EACH_EDGE (e, ei, bb->succs)
-           {
-             if (e->dest ==
-                 EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
-                                              (node->decl)))
-               fprintf (f, "edge %d -> EXIT,  Count", e->src->index);
-             else
-               fprintf (f, "edge %d -> %d,  Count", e->src->index,
-                        e->dest->index);
-             fprintf (f, " " HOST_WIDE_INT_PRINT_DEC " Prob %d\n",
-                      (HOST_WIDE_INT) e->count, e->probability);
-           }
-         }
-       }
-    }
-}
-
-/* Print counts and frequencies for all basic blocks of all functions.  */
-static void
-ipcp_print_bb_profiles (FILE * f)
-{
-  basic_block bb;
-  struct cgraph_node *node;
-
-  for (node = cgraph_nodes; node; node = node->next)
-    {
-      fprintf (f, "function %s: \n", cgraph_node_name (node));
-      if (node->analyzed)
-       {
-         bb =
-           ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
-         fprintf (f, "ENTRY: Count");
-         fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                  " Frequency  %d\n", (HOST_WIDE_INT) bb->count,
-                  bb->frequency);
-
-         FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-         {
-           fprintf (f, "bb[%d]: Count", bb->index);
-           fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                    " Frequency %d\n", (HOST_WIDE_INT) bb->count,
-                    bb->frequency);
-         }
-         bb =
-           EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
-         fprintf (f, "EXIT: Count");
-         fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                  " Frequency %d\n", (HOST_WIDE_INT) bb->count,
-                  bb->frequency);
-
-       }
-    }
-}
-
 /* Print profile info for all functions.  */
 static void
 ipcp_print_profile_data (FILE * f)
@@ -856,10 +736,6 @@ ipcp_print_profile_data (FILE * f)
   ipcp_print_func_profile_counts (f);
   fprintf (f, "\nCS COUNTS stage:\n");
   ipcp_print_call_profile_counts (f);
-  fprintf (f, "\nBB COUNTS and FREQUENCIES :\n");
-  ipcp_print_bb_profiles (f);
-  fprintf (f, "\nCFG EDGES COUNTS and PROBABILITIES :\n");
-  ipcp_print_edge_profiles (f);
 }
 
 /* Build and initialize ipa_replace_map struct according to LAT. This struct is
@@ -872,7 +748,7 @@ ipcp_create_replace_map (tree parm_tree, struct ipcp_lattice *lat)
   struct ipa_replace_map *replace_map;
   tree const_val;
 
-  replace_map = XCNEW (struct ipa_replace_map);
+  replace_map = GGC_NEW (struct ipa_replace_map);
   const_val = build_const_val (lat, TREE_TYPE (parm_tree));
   if (dump_file)
     {
@@ -959,25 +835,7 @@ ipcp_update_callgraph (void)
        for (cs = node->callers; cs; cs = next)
          {
            next = cs->next_caller;
-           if (ipcp_node_is_clone (cs->caller) || !ipcp_need_redirect_p (cs))
-             {
-               gimple new_stmt;
-               gimple_stmt_iterator gsi;
-
-               current_function_decl = cs->caller->decl;
-               push_cfun (DECL_STRUCT_FUNCTION (cs->caller->decl));
-               
-               new_stmt = gimple_call_copy_skip_args (cs->call_stmt,
-                                                      args_to_skip);
-               if (gimple_vdef (new_stmt))
-                 SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
-               gsi = gsi_for_stmt (cs->call_stmt);
-               gsi_replace (&gsi, new_stmt, true);
-               cgraph_set_call_stmt (cs, new_stmt);
-               pop_cfun ();
-               current_function_decl = NULL;
-             }
-           else
+           if (!ipcp_node_is_clone (cs->caller) && ipcp_need_redirect_p (cs))
              {
                cgraph_redirect_edge_callee (cs, orig_node);
                gimple_call_set_fndecl (cs->call_stmt, orig_node->decl);
@@ -986,29 +844,6 @@ ipcp_update_callgraph (void)
       }
 }
 
-/* Update all cfg basic blocks in NODE according to SCALE.  */
-static void
-ipcp_update_bb_counts (struct cgraph_node *node, gcov_type scale)
-{
-  basic_block bb;
-
-  FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-    bb->count = bb->count * scale / REG_BR_PROB_BASE;
-}
-
-/* Update all cfg edges in NODE according to SCALE.  */
-static void
-ipcp_update_edges_counts (struct cgraph_node *node, gcov_type scale)
-{
-  basic_block bb;
-  edge_iterator ei;
-  edge e;
-
-  FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
-    FOR_EACH_EDGE (e, ei, bb->succs)
-    e->count = e->count * scale / REG_BR_PROB_BASE;
-}
-
 /* Update profiling info for versioned functions and the functions they were
    versioned from.  */
 static void
@@ -1032,10 +867,6 @@ ipcp_update_profiling (void)
            cs->count = cs->count * scale / REG_BR_PROB_BASE;
          for (cs = orig_node->callees; cs; cs = cs->next_callee)
            cs->count = cs->count * scale_complement / REG_BR_PROB_BASE;
-         ipcp_update_bb_counts (node, scale);
-         ipcp_update_bb_counts (orig_node, scale_complement);
-         ipcp_update_edges_counts (node, scale);
-         ipcp_update_edges_counts (orig_node, scale_complement);
        }
     }
 }
@@ -1160,13 +991,13 @@ ipcp_insert_stage (void)
   struct cgraph_node *node, *node1 = NULL;
   int i;
   VEC (cgraph_edge_p, heap) * redirect_callers;
-  varray_type replace_trees;
+  VEC (ipa_replace_map_p,gc)* replace_trees;
   int node_callers, count;
   tree parm_tree;
   struct ipa_replace_map *replace_param;
   fibheap_t heap;
-  long overall_insns = 0, new_insns = 0;
-  long max_new_insns;
+  long overall_size = 0, new_size = 0;
+  long max_new_size;
 
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
@@ -1180,13 +1011,13 @@ ipcp_insert_stage (void)
       {
        if (node->count > max_count)
          max_count = node->count;
-       overall_insns += node->local.inline_summary.self_insns;
+       overall_size += node->local.inline_summary.self_insns;
       }
 
-  max_new_insns = overall_insns;
-  if (max_new_insns < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
-    max_new_insns = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
-  max_new_insns = max_new_insns * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1;
+  max_new_size = overall_size;
+  if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
+    max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
+  max_new_size = max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1;
 
   /* First collect all functions we proved to have constant arguments to heap.  */
   heap = fibheap_new ();
@@ -1220,7 +1051,7 @@ ipcp_insert_stage (void)
 
       growth = ipcp_estimate_growth (node);
 
-      if (new_insns + growth > max_new_insns)
+      if (new_size + growth > max_new_size)
        break;
       if (growth
          && optimize_function_for_size_p (DECL_STRUCT_FUNCTION (node->decl)))
@@ -1230,7 +1061,7 @@ ipcp_insert_stage (void)
          continue;
        }
 
-      new_insns += growth;
+      new_size += growth;
 
       /* Look if original function becomes dead after clonning.  */
       for (cs = node->callers; cs != NULL; cs = cs->next_caller)
@@ -1242,9 +1073,8 @@ ipcp_insert_stage (void)
       info = IPA_NODE_REF (node);
       count = ipa_get_param_count (info);
 
-      VARRAY_GENERIC_PTR_INIT (replace_trees, ipcp_const_param_count (node),
-                               "replace_trees");
-      args_to_skip = BITMAP_ALLOC (NULL);
+      replace_trees = VEC_alloc (ipa_replace_map_p, gc, 1);
+      args_to_skip = BITMAP_GGC_ALLOC ();
       for (i = 0; i < count; i++)
        {
          struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
@@ -1263,7 +1093,7 @@ ipcp_insert_stage (void)
            {
              replace_param =
                ipcp_create_replace_map (parm_tree, lat);
-             VARRAY_PUSH_GENERIC_PTR (replace_trees, replace_param);
+             VEC_safe_push (ipa_replace_map_p, gc, replace_trees, replace_param);
              bitmap_set_bit (args_to_skip, i);
            }
        }
@@ -1279,20 +1109,20 @@ ipcp_insert_stage (void)
       /* Redirecting all the callers of the node to the
          new versioned node.  */
       node1 =
-       cgraph_function_versioning (node, redirect_callers, replace_trees,
-                                   args_to_skip);
-      BITMAP_FREE (args_to_skip);
+       cgraph_create_virtual_clone (node, redirect_callers, replace_trees,
+                                    args_to_skip);
+      args_to_skip = NULL;
       VEC_free (cgraph_edge_p, heap, redirect_callers);
-      VARRAY_CLEAR (replace_trees);
+      replace_trees = NULL;
+
       if (node1 == NULL)
        continue;
       if (dump_file)
        fprintf (dump_file, "versioned function %s with growth %i, overall %i\n",
-                cgraph_node_name (node), (int)growth, (int)new_insns);
+                cgraph_node_name (node), (int)growth, (int)new_size);
       ipcp_init_cloned_node (node, node1);
 
-      /* We've possibly introduced direct calls.  */
-      ipcp_update_cloned_node (node1);
+      /* TODO: We can use indirect inlning info to produce new calls.  */
 
       if (dump_file)
        dump_function_to_file (node1->decl, dump_file, dump_flags);
index 1561219..99640bf 100644 (file)
@@ -433,7 +433,7 @@ cgraph_default_inline_p (struct cgraph_node *n, cgraph_inline_failed_t *reason)
       return false;
     }
 
-  if (!DECL_STRUCT_FUNCTION (decl)->cfg)
+  if (!n->analyzed)
     {
       if (reason)
        *reason = CIF_BODY_NOT_AVAILABLE;
index 88047e4..f4fa37d 100644 (file)
@@ -653,7 +653,7 @@ ipa_note_param_call (struct ipa_node_params *info, int formal_id,
   note->formal_id = formal_id;
   note->stmt = stmt;
   note->count = bb->count;
-  note->frequency = compute_call_stmt_bb_frequency (bb);
+  note->frequency = compute_call_stmt_bb_frequency (current_function_decl, bb);
 
   note->next = info->param_calls;
   info->param_calls = note;
index 5943a2a..c4c1ccc 100644 (file)
@@ -99,20 +99,6 @@ struct ipcp_lattice
   tree constant;
 };
 
-/* Represent which DECL tree (or reference to such tree)
-   will be replaced by another tree while versioning.  */
-struct ipa_replace_map
-{
-  /* The tree that will be replaced.  */
-  tree old_tree;
-  /* The new (replacing) tree.  */
-  tree new_tree;
-  /* True when a substitution should be done, false otherwise.  */
-  bool replace_p;
-  /* True when we replace a reference to old_tree.  */
-  bool ref_p;
-};
-
 /* Each instance of the following  structure describes a statement that calls a
    function parameter.  Those referring  to statements within the same function
    are linked in a list.  */
index 5b1670e..6468d77 100644 (file)
@@ -3641,7 +3641,7 @@ do_reorg_1 (void)
   bitmap_obstack_initialize (NULL);
 
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed && node->decl && !node->next_clone)
+    if (node->analyzed && node->decl)
       {
        push_cfun (DECL_STRUCT_FUNCTION (node->decl));
        current_function_decl = node->decl;
@@ -3809,8 +3809,7 @@ collect_data_accesses (void)
        {
          struct function *func = DECL_STRUCT_FUNCTION (c_node->decl);
 
-         if (!c_node->next_clone)
-           collect_accesses_in_func (func);
+         collect_accesses_in_func (func);
          exclude_alloc_and_field_accs (c_node);
        }
     }
index b486b93..686ca9e 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-pass.h"
 #include "timevar.h"
+#include "gimple.h"
 #include "ggc.h"
 
 /* Fill array order with all nodes with output flag set in the reverse
@@ -143,6 +144,12 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
            e->callee->aux = first;
            first = e->callee;
          }
+      while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
+        {
+         node = node->clone_of;
+         node->aux = first;
+         first = node;
+       }
     }
 
   /* Remove unreachable nodes.  Extern inline functions need special care;
@@ -168,25 +175,29 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
            {
              struct cgraph_edge *e;
 
+             /* See if there is reachable caller.  */
              for (e = node->callers; e; e = e->next_caller)
                if (e->caller->aux)
                  break;
+
+             /* If so, we need to keep node in the callgraph.  */
              if (e || node->needed)
                {
                  struct cgraph_node *clone;
 
-                 for (clone = node->next_clone; clone;
-                      clone = clone->next_clone)
+                 /* If there are still clones, we must keep body around.
+                    Otherwise we can just remove the body but keep the clone.  */
+                 for (clone = node->clones; clone;
+                      clone = clone->next_sibling_clone)
                    if (clone->aux)
                      break;
                  if (!clone)
                    {
                      cgraph_release_function_body (node);
+                     cgraph_node_remove_callees (node);
                      node->analyzed = false;
+                     node->local.inlinable = false;
                    }
-                 cgraph_node_remove_callees (node);
-                 node->analyzed = false;
-                 node->local.inlinable = false;
                }
              else
                cgraph_remove_node (node);
@@ -195,7 +206,18 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
        }
     }
   for (node = cgraph_nodes; node; node = node->next)
-    node->aux = NULL;
+    {
+      /* Inline clones might be kept around so their materializing allows further
+         cloning.  If the function the clone is inlined into is removed, we need
+         to turn it into normal cone.  */
+      if (node->global.inlined_to
+         && !node->callers)
+       {
+         gcc_assert (node->clones);
+         node->global.inlined_to = false;
+       }
+      node->aux = NULL;
+    }
 #ifdef ENABLE_CHECKING
   verify_cgraph ();
 #endif
index 312dfa9..7a39ac7 100644 (file)
@@ -846,7 +846,7 @@ do_per_function (void (*callback) (void *data), void *data)
     {
       struct cgraph_node *node;
       for (node = cgraph_nodes; node; node = node->next)
-       if (node->analyzed)
+       if (node->analyzed && gimple_has_body_p (node->decl))
          {
            push_cfun (DECL_STRUCT_FUNCTION (node->decl));
            current_function_decl = node->decl;
index b5c67cd..077f9d6 100644 (file)
@@ -7074,7 +7074,7 @@ struct gimple_opt_pass pass_split_crit_edges =
   PROP_no_crit_edges,            /* properties_provided */
   0,                             /* properties_destroyed */
   0,                             /* todo_flags_start */
-  TODO_dump_func                 /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_flow  /* todo_flags_finish */
  }
 };
 
index b134ae5..0a38376 100644 (file)
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 #include "input.h"
 #include "insn-config.h"
-#include "varray.h"
 #include "hashtab.h"
 #include "langhooks.h"
 #include "basic-block.h"
@@ -1393,6 +1392,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
         need to process all of them.  */
       do
        {
+         tree fn;
+
          stmt = gsi_stmt (copy_gsi);
          if (is_gimple_call (stmt)
              && gimple_call_va_arg_pack_p (stmt)
@@ -1481,34 +1482,24 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
             callgraph edges and update or duplicate them.  */
          if (is_gimple_call (stmt))
            {
-             struct cgraph_node *node;
-             struct cgraph_edge *edge;
+             struct cgraph_edge *edge = cgraph_edge (id->src_node, orig_stmt);
              int flags;
 
              switch (id->transform_call_graph_edges)
                {
              case CB_CGE_DUPLICATE:
-               edge = cgraph_edge (id->src_node, orig_stmt);
-               if (edge)
+               if (edge)
                  cgraph_clone_edge (edge, id->dst_node, stmt,
                                           REG_BR_PROB_BASE, 1,
                                           edge->frequency, true);
                break;
 
              case CB_CGE_MOVE_CLONES:
-               for (node = id->dst_node->next_clone;
-                   node;
-                   node = node->next_clone)
-                 {
-                   edge = cgraph_edge (node, orig_stmt);
-                         if (edge)
-                           cgraph_set_call_stmt (edge, stmt);
-                 }
-               /* FALLTHRU */
+               cgraph_set_call_stmt_including_clones (id->dst_node, orig_stmt, stmt);
+               break;
 
              case CB_CGE_MOVE:
-               edge = cgraph_edge (id->dst_node, orig_stmt);
-               if (edge)
+               if (edge)
                  cgraph_set_call_stmt (edge, stmt);
                break;
 
@@ -1516,6 +1507,36 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                gcc_unreachable ();
                }
 
+           /* Constant propagation on argument done during inlining
+              may create new direct call.  Produce an edge for it.  */
+           if (!edge && is_gimple_call (stmt)
+               && (fn = gimple_call_fndecl (stmt)) != NULL
+               && !cgraph_edge (id->dst_node, stmt))
+             {
+               struct cgraph_node *dest = cgraph_node (fn);
+
+               /* We have missing edge in the callgraph.  This can happen in one case
+                  where previous inlining turned indirect call into direct call by
+                  constant propagating arguments.  In all other cases we hit a bug
+                  (incorrect node sharing is most common reason for missing edges.  */
+               gcc_assert (dest->needed || !dest->analyzed);
+               if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
+                 cgraph_create_edge_including_clones (id->dst_node, dest, stmt,
+                                                      bb->count, CGRAPH_FREQ_BASE,
+                                                      bb->loop_depth,
+                                                      CIF_ORIGINALLY_INDIRECT_CALL);
+               else
+                 cgraph_create_edge (id->dst_node, dest, stmt,
+                                     bb->count, CGRAPH_FREQ_BASE,
+                                     bb->loop_depth)->inline_failed
+                   = CIF_ORIGINALLY_INDIRECT_CALL;
+               if (dump_file)
+                 {
+                    fprintf (dump_file, "Created new direct edge to %s",
+                             cgraph_node_name (dest));
+                 }
+             }
+
              flags = gimple_call_flags (stmt);
 
              if (flags & ECF_MAY_BE_ALLOCA)
@@ -3221,29 +3242,6 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 
   cg_edge = cgraph_edge (id->dst_node, stmt);
 
-  /* Constant propagation on argument done during previous inlining
-     may create new direct call.  Produce an edge for it.  */
-  if (!cg_edge)
-    {
-      struct cgraph_node *dest = cgraph_node (fn);
-
-      /* We have missing edge in the callgraph.  This can happen in one case
-         where previous inlining turned indirect call into direct call by
-         constant propagating arguments.  In all other cases we hit a bug
-         (incorrect node sharing is most common reason for missing edges.  */
-      gcc_assert (dest->needed);
-      cgraph_create_edge (id->dst_node, dest, stmt,
-                         bb->count, CGRAPH_FREQ_BASE,
-                         bb->loop_depth)->inline_failed
-       = CIF_ORIGINALLY_INDIRECT_CALL;
-      if (dump_file)
-       {
-          fprintf (dump_file, "Created new direct edge to %s",
-                   cgraph_node_name (dest));
-       }
-      goto egress;
-    }
-
   /* Don't try to inline functions that are not well-suited to
      inlining.  */
   if (!cgraph_inline_p (cg_edge, &reason))
@@ -4281,27 +4279,98 @@ tree_versionable_function_p (tree fndecl)
   return true;
 }
 
-/* Create a new name for omp child function.  Returns an identifier.  */
-
-static GTY(()) unsigned int clone_fn_id_num;
+/* Delete all unreachable basic blocks and update callgraph.
+   Doing so is somewhat nontrivial because we need to update all clones and
+   remove inline function that become unreachable.  */
 
-static tree
-clone_function_name (tree decl)
+static bool
+delete_unreachable_blocks_update_callgraph (copy_body_data *id)
 {
-  tree name = DECL_ASSEMBLER_NAME (decl);
-  size_t len = IDENTIFIER_LENGTH (name);
-  char *tmp_name, *prefix;
-
-  prefix = XALLOCAVEC (char, len + strlen ("_clone") + 1);
-  memcpy (prefix, IDENTIFIER_POINTER (name), len);
-  strcpy (prefix + len, "_clone");
-#ifndef NO_DOT_IN_LABEL
-  prefix[len] = '.';
-#elif !defined NO_DOLLAR_IN_LABEL
-  prefix[len] = '$';
+  bool changed = false;
+  basic_block b, next_bb;
+
+  find_unreachable_blocks ();
+
+  /* Delete all unreachable basic blocks.  */
+
+  for (b = ENTRY_BLOCK_PTR->next_bb; b != EXIT_BLOCK_PTR; b = next_bb)
+    {
+      next_bb = b->next_bb;
+
+      if (!(b->flags & BB_REACHABLE))
+       {
+          gimple_stmt_iterator bsi;
+
+          for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next (&bsi))
+           if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL)
+             {
+               struct cgraph_edge *e;
+               struct cgraph_node *node;
+
+               if ((e = cgraph_edge (id->dst_node, gsi_stmt (bsi))) != NULL)
+                 {
+                   if (!e->inline_failed)
+                     cgraph_remove_node_and_inline_clones (e->callee);
+                   else
+                     cgraph_remove_edge (e);
+                 }
+               if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
+                   && id->dst_node->clones)
+                 for (node = id->dst_node->clones; node != id->dst_node;)
+                   {
+                     if ((e = cgraph_edge (node, gsi_stmt (bsi))) != NULL)
+                       {
+                         if (!e->inline_failed)
+                           cgraph_remove_node_and_inline_clones (e->callee);
+                         else
+                           cgraph_remove_edge (e);
+                       }
+                      
+                     if (node->clones)
+                       node = node->clones;
+                     else if (node->next_sibling_clone)
+                       node = node->next_sibling_clone;
+                     else
+                       {
+                         while (node != id->dst_node && !node->next_sibling_clone)
+                           node = node->clone_of;
+                         if (node != id->dst_node)
+                           node = node->next_sibling_clone;
+                       }
+                   }
+             }
+         delete_basic_block (b);
+         changed = true;
+       }
+    }
+
+  if (changed)
+    tidy_fallthru_edges ();
+#ifdef ENABLE_CHECKING0
+  verify_cgraph_node (id->dst_node);
+  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
+      && id->dst_node->clones)
+    {
+      struct cgraph_node *node;
+      for (node = id->dst_node->clones; node != id->dst_node;)
+       {
+         verify_cgraph_node (node);
+          
+         if (node->clones)
+           node = node->clones;
+         else if (node->next_sibling_clone)
+           node = node->next_sibling_clone;
+         else
+           {
+             while (node != id->dst_node && !node->next_sibling_clone)
+               node = node->clone_of;
+             if (node != id->dst_node)
+               node = node->next_sibling_clone;
+           }
+       }
+     }
 #endif
-  ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++);
-  return get_identifier (tmp_name);
+  return changed;
 }
 
 /* Create a copy of a function's tree.
@@ -4313,7 +4382,7 @@ clone_function_name (tree decl)
    trees. If UPDATE_CLONES is set, the call_stmt fields
    of edges of clones of the function will be updated.  */
 void
-tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
+tree_function_versioning (tree old_decl, tree new_decl, VEC(ipa_replace_map_p,gc)* tree_map,
                          bool update_clones, bitmap args_to_skip)
 {
   struct cgraph_node *old_version_node;
@@ -4349,13 +4418,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   memset (&id, 0, sizeof (id));
 
   /* Generate a new name for the new version. */
-  if (!update_clones)
-    {
-      DECL_NAME (new_decl) = clone_function_name (old_decl);
-      SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
-      SET_DECL_RTL (new_decl, NULL_RTX);
-      id.statements_to_fold = pointer_set_create ();
-    }
+  id.statements_to_fold = pointer_set_create ();
   
   id.decl_map = pointer_map_create ();
   id.src_fn = old_decl;
@@ -4388,11 +4451,10 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   
   /* If there's a tree_map, prepare for substitution.  */
   if (tree_map)
-    for (i = 0; i < VARRAY_ACTIVE_SIZE (tree_map); i++)
+    for (i = 0; i < VEC_length (ipa_replace_map_p, tree_map); i++)
       {
        gimple init;
-       replace_info
-         = (struct ipa_replace_map *) VARRAY_GENERIC_PTR (tree_map, i);
+       replace_info = VEC_index (ipa_replace_map_p, tree_map, i);
        if (replace_info->replace_p)
          {
            tree op = replace_info->new_tree;
@@ -4431,6 +4493,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   number_blocks (id.dst_fn);
   
   declare_inline_vars (DECL_INITIAL (new_decl), vars);
+
   if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
     /* Add local vars.  */
     for (t_step = DECL_STRUCT_FUNCTION (old_decl)->local_decls;
@@ -4469,14 +4532,15 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   pointer_map_destroy (id.decl_map);
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
-  if (!update_clones)
-    {
-      fold_marked_statements (0, id.statements_to_fold);
-      pointer_set_destroy (id.statements_to_fold);
-      fold_cond_expr_cond ();
-      delete_unreachable_blocks ();
-      update_ssa (TODO_update_ssa);
-    }
+
+  fold_marked_statements (0, id.statements_to_fold);
+  pointer_set_destroy (id.statements_to_fold);
+  fold_cond_expr_cond ();
+  delete_unreachable_blocks_update_callgraph (&id);
+  update_ssa (TODO_update_ssa);
+  free_dominance_info (CDI_DOMINATORS);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
   VEC_free (gimple, heap, init_stmts);
   pop_cfun ();
   current_function_decl = old_current_function_decl;
@@ -4544,5 +4608,3 @@ tree_can_inline_p (tree caller, tree callee)
   /* Allow the backend to decide if inlining is ok.  */
   return targetm.target_option.can_inline_p (caller, callee);
 }
-
-#include "gt-tree-inline.h"
index 2a4e38b..d55f84a 100644 (file)
@@ -21,7 +21,6 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_TREE_INLINE_H
 #define GCC_TREE_INLINE_H
 
-#include "varray.h"
 #include "pointer-set.h"
 
 
@@ -156,7 +155,6 @@ int estimate_num_insns (gimple, eni_weights *);
 int estimate_num_insns_fn (tree, eni_weights *);
 int count_insns_seq (gimple_seq, eni_weights *);
 bool tree_versionable_function_p (tree);
-void tree_function_versioning (tree, tree, varray_type, bool, bitmap);
 bool tree_can_inline_p (tree, tree);
 
 extern gimple_seq remap_gimple_seq (gimple_seq, copy_body_data *);