re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / cgraphclones.c
index c04b5c819fd4f8b31e3555f42654c2ebaa7d0179..aad9b8176fed60957456505358893ffcc57edde8 100644 (file)
@@ -1,5 +1,5 @@
 /* Callgraph clones
-   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+   Copyright (C) 2003-2015 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -69,16 +69,20 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "stringpool.h"
+#include "hard-reg-set.h"
 #include "function.h"
 #include "emit-rtl.h"
+#include "predict.h"
 #include "basic-block.h"
 #include "tree-ssa-alias.h"
 #include "internal-fn.h"
 #include "tree-eh.h"
 #include "gimple-expr.h"
-#include "is-a.h"
 #include "gimple.h"
 #include "bitmap.h"
 #include "tree-cfg.h"
@@ -91,7 +95,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "params.h"
 #include "intl.h"
-#include "function.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
 #include "ipa-prop.h"
 #include "tree-iterator.h"
 #include "tree-dump.h"
@@ -102,69 +108,71 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "except.h"
 
-/* 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, unsigned stmt_uid, gcov_type count_scale,
-                  int freq_scale, bool update_original)
+/* Create clone of edge in the node N represented by CALL_EXPR
+   the callgraph.  */
+
+cgraph_edge *
+cgraph_edge::clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid,
+                   gcov_type count_scale, int freq_scale, bool update_original)
 {
-  struct cgraph_edge *new_edge;
-  gcov_type count = apply_probability (e->count, count_scale);
+  cgraph_edge *new_edge;
+  gcov_type gcov_count = apply_probability (count, count_scale);
   gcov_type freq;
 
   /* We do not want to ignore loop nest after frequency drops to 0.  */
   if (!freq_scale)
     freq_scale = 1;
-  freq = e->frequency * (gcov_type) freq_scale / CGRAPH_FREQ_BASE;
+  freq = frequency * (gcov_type) freq_scale / CGRAPH_FREQ_BASE;
   if (freq > CGRAPH_FREQ_MAX)
     freq = CGRAPH_FREQ_MAX;
 
-  if (e->indirect_unknown_callee)
+  if (indirect_unknown_callee)
     {
       tree decl;
 
       if (call_stmt && (decl = gimple_call_fndecl (call_stmt))
          /* When the call is speculative, we need to resolve it 
             via cgraph_resolve_speculation and not here.  */
-         && !e->speculative)
+         && !speculative)
        {
-         struct cgraph_node *callee = cgraph_node::get (decl);
+         cgraph_node *callee = cgraph_node::get (decl);
          gcc_checking_assert (callee);
-         new_edge = n->create_edge (callee, call_stmt, count, freq);
+         new_edge = n->create_edge (callee, call_stmt, gcov_count, freq);
        }
       else
        {
          new_edge = n->create_indirect_edge (call_stmt,
-                                             e->indirect_info->ecf_flags,
-                                             count, freq);
-         *new_edge->indirect_info = *e->indirect_info;
+                                             indirect_info->ecf_flags,
+                                             count, freq, false);
+         *new_edge->indirect_info = *indirect_info;
        }
     }
   else
     {
-      new_edge = n->create_edge (e->callee, call_stmt, count, freq);
-      if (e->indirect_info)
+      new_edge = n->create_edge (callee, call_stmt, gcov_count, freq);
+      if (indirect_info)
        {
          new_edge->indirect_info
            = ggc_cleared_alloc<cgraph_indirect_call_info> ();
-         *new_edge->indirect_info = *e->indirect_info;
+         *new_edge->indirect_info = *indirect_info;
        }
     }
 
-  new_edge->inline_failed = e->inline_failed;
-  new_edge->indirect_inlining_edge = e->indirect_inlining_edge;
+  new_edge->inline_failed = inline_failed;
+  new_edge->indirect_inlining_edge = indirect_inlining_edge;
   new_edge->lto_stmt_uid = stmt_uid;
   /* Clone flags that depend on call_stmt availability manually.  */
-  new_edge->can_throw_external = e->can_throw_external;
-  new_edge->call_stmt_cannot_inline_p = e->call_stmt_cannot_inline_p;
-  new_edge->speculative = e->speculative;
+  new_edge->can_throw_external = can_throw_external;
+  new_edge->call_stmt_cannot_inline_p = call_stmt_cannot_inline_p;
+  new_edge->speculative = speculative;
+  new_edge->in_polymorphic_cdtor = in_polymorphic_cdtor;
   if (update_original)
     {
-      e->count -= new_edge->count;
-      if (e->count < 0)
-       e->count = 0;
+      count -= new_edge->count;
+      if (count < 0)
+       count = 0;
     }
-  cgraph_call_edge_duplication_hooks (e, new_edge);
+  symtab->call_edge_duplication_hooks (this, new_edge);
   return new_edge;
 }
 
@@ -176,7 +184,7 @@ build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
                               bool skip_return)
 {
   tree new_type = NULL;
-  tree args, new_args = NULL, t;
+  tree args, new_args = NULL;
   tree new_reversed;
   int i = 0;
 
@@ -217,22 +225,6 @@ build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
   if (skip_return)
     TREE_TYPE (new_type) = void_type_node;
 
-  /* This is a new type, not a copy of an old type.  Need to reassociate
-     variants.  We can handle everything except the main variant lazily.  */
-  t = TYPE_MAIN_VARIANT (orig_type);
-  if (t != orig_type)
-    {
-      t = build_function_type_skip_args (t, args_to_skip, skip_return);
-      TYPE_MAIN_VARIANT (new_type) = t;
-      TYPE_NEXT_VARIANT (new_type) = TYPE_NEXT_VARIANT (t);
-      TYPE_NEXT_VARIANT (t) = new_type;
-    }
-  else
-    {
-      TYPE_MAIN_VARIANT (new_type) = new_type;
-      TYPE_NEXT_VARIANT (new_type) = NULL;
-    }
-
   return new_type;
 }
 
@@ -309,7 +301,10 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
   if (thunk_of->thunk.thunk_p)
     node = duplicate_thunk_for_node (thunk_of, node);
 
-  struct cgraph_edge *cs;
+  if (!DECL_ARGUMENTS (thunk->decl))
+    thunk->get_untransformed_body ();
+
+  cgraph_edge *cs;
   for (cs = node->callers; cs; cs = cs->next_caller)
     if (cs->caller->thunk.thunk_p
        && cs->caller->thunk.this_adjusting == thunk->thunk.this_adjusting
@@ -333,6 +328,22 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
                                                node->clone.args_to_skip,
                                                false);
     }
+
+  tree *link = &DECL_ARGUMENTS (new_decl);
+  int i = 0;
+  for (tree pd = DECL_ARGUMENTS (thunk->decl); pd; pd = DECL_CHAIN (pd), i++)
+    {
+      if (!node->clone.args_to_skip
+         || !bitmap_bit_p (node->clone.args_to_skip, i))
+       {
+         tree nd = copy_node (pd);
+         DECL_CONTEXT (nd) = new_decl;
+         *link = nd;
+         link = &DECL_CHAIN (nd);
+       }
+    }
+  *link = NULL_TREE;
+
   gcc_checking_assert (!DECL_STRUCT_FUNCTION (new_decl));
   gcc_checking_assert (!DECL_INITIAL (new_decl));
   gcc_checking_assert (!DECL_RESULT (new_decl));
@@ -350,28 +361,51 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
   new_thunk->clone.args_to_skip = node->clone.args_to_skip;
   new_thunk->clone.combined_args_to_skip = node->clone.combined_args_to_skip;
 
-  struct cgraph_edge *e = new_thunk->create_edge (node, NULL, 0,
+  cgraph_edge *e = new_thunk->create_edge (node, NULL, 0,
                                                  CGRAPH_FREQ_BASE);
   e->call_stmt_cannot_inline_p = true;
-  cgraph_call_edge_duplication_hooks (thunk->callees, e);
-  if (!new_thunk->expand_thunk (false, false))
-    new_thunk->analyzed = true;
-  thunk->call_duplication_hooks (new_thunk);
+  symtab->call_edge_duplication_hooks (thunk->callees, e);
+  symtab->call_cgraph_duplication_hooks (thunk, new_thunk);
   return new_thunk;
 }
 
 /* If E does not lead to a thunk, simply redirect it to N.  Otherwise create
    one or more equivalent thunks for N and redirect E to the first in the
-   chain.  */
+   chain.  Note that it is then necessary to call
+   n->expand_all_artificial_thunks once all callers are redirected.  */
 
 void
-redirect_edge_duplicating_thunks (struct cgraph_edge *e, struct cgraph_node *n)
+cgraph_edge::redirect_callee_duplicating_thunks (cgraph_node *n)
 {
-  cgraph_node *orig_to = e->callee->ultimate_alias_target ();
+  cgraph_node *orig_to = callee->ultimate_alias_target ();
   if (orig_to->thunk.thunk_p)
     n = duplicate_thunk_for_node (orig_to, n);
 
-  cgraph_redirect_edge_callee (e, n);
+  redirect_callee (n);
+}
+
+/* Call expand_thunk on all callers that are thunks and if analyze those nodes
+   that were expanded.  */
+
+void
+cgraph_node::expand_all_artificial_thunks ()
+{
+  cgraph_edge *e;
+  for (e = callers; e;)
+    if (e->caller->thunk.thunk_p)
+      {
+       cgraph_node *thunk = e->caller;
+
+       e = e->next_caller;
+       if (thunk->expand_thunk (false, false))
+         {
+           thunk->thunk.thunk_p = false;
+           thunk->analyze ();
+         }
+       thunk->expand_all_artificial_thunks ();
+      }
+    else
+      e = e->next_caller;
 }
 
 /* Create node representing clone of N executed COUNT times.  Decrease
@@ -391,19 +425,19 @@ redirect_edge_duplicating_thunks (struct cgraph_edge *e, struct cgraph_node *n)
    node is not inlined.  */
 
 cgraph_node *
-cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
+cgraph_node::create_clone (tree new_decl, gcov_type gcov_count, int freq,
                           bool update_original,
                           vec<cgraph_edge *> redirect_callers,
                           bool call_duplication_hook,
-                          struct cgraph_node *new_inlined_to,
+                          cgraph_node *new_inlined_to,
                           bitmap args_to_skip)
 {
-  struct cgraph_node *new_node = cgraph_node::create_empty ();
-  struct cgraph_edge *e;
+  cgraph_node *new_node = symtab->create_empty ();
+  cgraph_edge *e;
   gcov_type count_scale;
   unsigned i;
 
-  new_node->decl = decl;
+  new_node->decl = new_decl;
   new_node->register_symbol ();
   new_node->origin = origin;
   new_node->lto_file_data = lto_file_data;
@@ -416,6 +450,7 @@ cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
   new_node->definition = definition;
   new_node->local = local;
   new_node->externally_visible = false;
+  new_node->no_reorder = no_reorder;
   new_node->local.local = true;
   new_node->global = global;
   new_node->global.inlined_to = new_inlined_to;
@@ -424,9 +459,12 @@ cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
   new_node->frequency = frequency;
   new_node->tp_first_run = tp_first_run;
   new_node->tm_clone = tm_clone;
+  new_node->icf_merged = icf_merged;
+  new_node->merged = merged;
 
   new_node->clone.tree_map = NULL;
   new_node->clone.args_to_skip = args_to_skip;
+  new_node->split_part = split_part;
   if (!args_to_skip)
     new_node->clone.combined_args_to_skip = clone.combined_args_to_skip;
   else if (clone.combined_args_to_skip)
@@ -462,16 +500,17 @@ cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
       if (!e->callee
          || DECL_BUILT_IN_CLASS (e->callee->decl) != BUILT_IN_NORMAL
          || DECL_FUNCTION_CODE (e->callee->decl) != BUILT_IN_UNREACHABLE)
-        redirect_edge_duplicating_thunks (e, new_node);
+        e->redirect_callee_duplicating_thunks (new_node);
     }
+  new_node->expand_all_artificial_thunks ();
 
   for (e = callees;e; e=e->next_callee)
-    cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid,
-                      count_scale, freq, update_original);
+    e->clone (new_node, e->call_stmt, e->lto_stmt_uid, count_scale,
+             freq, update_original);
 
   for (e = indirect_calls; e; e = e->next_callee)
-    cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid,
-                      count_scale, freq, update_original);
+    e->clone (new_node, e->call_stmt, e->lto_stmt_uid,
+             count_scale, freq, update_original);
   new_node->clone_references (this);
 
   new_node->next_sibling_clone = clones;
@@ -481,23 +520,23 @@ cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
   new_node->clone_of = this;
 
   if (call_duplication_hook)
-    call_duplication_hooks (new_node);
+    symtab->call_cgraph_duplication_hooks (this, new_node);
   return new_node;
 }
 
-/* Return a new assembler name for a clone of DECL with SUFFIX.  */
-
 static GTY(()) unsigned int clone_fn_id_num;
 
+/* Return a new assembler name for a clone with SUFFIX of a decl named
+   NAME.  */
+
 tree
-clone_function_name (tree decl, const char *suffix)
+clone_function_name_1 (const char *name, const char *suffix)
 {
-  tree name = DECL_ASSEMBLER_NAME (decl);
-  size_t len = IDENTIFIER_LENGTH (name);
+  size_t len = strlen (name);
   char *tmp_name, *prefix;
 
   prefix = XALLOCAVEC (char, len + strlen (suffix) + 2);
-  memcpy (prefix, IDENTIFIER_POINTER (name), len);
+  memcpy (prefix, name, len);
   strcpy (prefix + len + 1, suffix);
 #ifndef NO_DOT_IN_LABEL
   prefix[len] = '.';
@@ -510,26 +549,36 @@ clone_function_name (tree decl, const char *suffix)
   return get_identifier (tmp_name);
 }
 
+/* Return a new assembler name for a clone of DECL with SUFFIX.  */
+
+tree
+clone_function_name (tree decl, const char *suffix)
+{
+  tree name = DECL_ASSEMBLER_NAME (decl);
+  return clone_function_name_1 (IDENTIFIER_POINTER (name), suffix);
+}
+
+
 /* 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_node *
 cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
                                   vec<ipa_replace_map *, va_gc> *tree_map,
                                   bitmap args_to_skip, const char * suffix)
 {
   tree old_decl = decl;
-  struct cgraph_node *new_node = NULL;
+  cgraph_node *new_node = NULL;
   tree new_decl;
   size_t len, i;
-  struct ipa_replace_map *map;
+  ipa_replace_map *map;
   char *name;
 
   if (!in_lto_p)
-    gcc_checking_assert  (tree_versionable_function_p (old_decl));
+    gcc_checking_assert (tree_versionable_function_p (old_decl));
 
   gcc_assert (local.can_change_signature || !args_to_skip);
 
@@ -569,6 +618,8 @@ cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
      ABI support for this.  */
   set_new_clone_decl_and_node_flags (new_node);
   new_node->clone.tree_map = tree_map;
+  if (!implicit_section)
+    new_node->set_section (get_section ());
 
   /* Clones of global symbols or symbols with unique names are unique.  */
   if ((TREE_PUBLIC (old_decl)
@@ -578,13 +629,13 @@ cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
       || in_lto_p)
     new_node->unique_name = true;
   FOR_EACH_VEC_SAFE_ELT (tree_map, i, map)
-    new_node->maybe_add_reference (map->new_tree, IPA_REF_ADDR, NULL);
+    new_node->maybe_create_reference (map->new_tree, IPA_REF_ADDR, NULL);
 
   if (ipa_transforms_to_apply.exists ())
     new_node->ipa_transforms_to_apply
       = ipa_transforms_to_apply.copy ();
 
-  call_duplication_hooks (new_node);
+  symtab->call_cgraph_duplication_hooks (this, new_node);
 
   return new_node;
 }
@@ -594,7 +645,7 @@ cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
 cgraph_node *
 cgraph_node::find_replacement (void)
 {
-  struct cgraph_node *next_inline_clone, *replacement;
+  cgraph_node *next_inline_clone, *replacement;
 
   for (next_inline_clone = clones;
        next_inline_clone
@@ -607,8 +658,8 @@ cgraph_node::find_replacement (void)
      other clones to be based on it.  */
   if (next_inline_clone)
     {
-      struct cgraph_node *n;
-      struct cgraph_node *new_clones;
+      cgraph_node *n;
+      cgraph_node *new_clones;
 
       replacement = next_inline_clone;
 
@@ -681,33 +732,34 @@ cgraph_node::find_replacement (void)
    call.  */
 
 void
-cgraph_node::set_call_stmt_including_clones (gimple old_stmt, gimple new_stmt,
+cgraph_node::set_call_stmt_including_clones (gimple old_stmt,
+                                            gcall *new_stmt,
                                             bool update_speculative)
 {
-  struct cgraph_node *node;
-  struct cgraph_edge *edge = get_edge (old_stmt);
+  cgraph_node *node;
+  cgraph_edge *edge = get_edge (old_stmt);
 
   if (edge)
-    cgraph_set_call_stmt (edge, new_stmt, update_speculative);
+    edge->set_call_stmt (new_stmt, update_speculative);
 
   node = clones;
   if (node)
     while (node != this)
       {
-       struct cgraph_edge *edge = node->get_edge (old_stmt);
+       cgraph_edge *edge = node->get_edge (old_stmt);
        if (edge)
          {
-           cgraph_set_call_stmt (edge, new_stmt, update_speculative);
+           edge->set_call_stmt (new_stmt, update_speculative);
            /* If UPDATE_SPECULATIVE is false, it means that we are turning
               speculative call into a real code sequence.  Update the
               callgraph edges.  */
            if (edge->speculative && !update_speculative)
              {
-               struct cgraph_edge *direct, *indirect;
-               struct ipa_ref *ref;
+               cgraph_edge *direct, *indirect;
+               ipa_ref *ref;
 
                gcc_assert (!edge->indirect_unknown_callee);
-               cgraph_speculative_call_info (edge, direct, indirect, ref);
+               edge->speculative_call_info (direct, indirect, ref);
                direct->speculative = false;
                indirect->speculative = false;
                ref->speculative = false;
@@ -735,14 +787,14 @@ cgraph_node::set_call_stmt_including_clones (gimple old_stmt, gimple new_stmt,
    frequencies of the clones.  */
 
 void
-cgraph_node::create_edge_including_clones (struct cgraph_node *callee,
-                                          gimple old_stmt, gimple stmt,
+cgraph_node::create_edge_including_clones (cgraph_node *callee,
+                                          gimple old_stmt, gcall *stmt,
                                           gcov_type count,
                                           int freq,
                                           cgraph_inline_failed_t reason)
 {
-  struct cgraph_node *node;
-  struct cgraph_edge *edge;
+  cgraph_node *node;
+  cgraph_edge *edge;
 
   if (!get_edge (stmt))
     {
@@ -754,14 +806,14 @@ cgraph_node::create_edge_including_clones (struct cgraph_node *callee,
   if (node)
     while (node != this)
       {
-       struct cgraph_edge *edge = node->get_edge (old_stmt);
+       cgraph_edge *edge = node->get_edge (old_stmt);
 
         /* It is possible that clones already contain the edge while
           master didn't.  Either we promoted indirect call into direct
           call in the clone or we are processing clones of unreachable
           master where edges has been removed.  */
        if (edge)
-         cgraph_set_call_stmt (edge, stmt);
+         edge->set_call_stmt (stmt);
        else if (! node->get_edge (stmt))
          {
            edge = node->create_edge (callee, stmt, count, freq);
@@ -790,12 +842,12 @@ cgraph_node::create_edge_including_clones (struct cgraph_node *callee,
 bool
 cgraph_node::remove_symbol_and_inline_clones (cgraph_node *forbidden_node)
 {
-  struct cgraph_edge *e, *next;
+  cgraph_edge *e, *next;
   bool found = false;
 
   if (this == forbidden_node)
     {
-      cgraph_remove_edge (callers);
+      callers->remove ();
       return true;
     }
   for (e = callees; e; e = next)
@@ -813,16 +865,16 @@ cgraph_node::remove_symbol_and_inline_clones (cgraph_node *forbidden_node)
    respective tree code should be updated to call the NEW_VERSION.  */
 
 static void
-update_call_expr (struct cgraph_node *new_version)
+update_call_expr (cgraph_node *new_version)
 {
-  struct cgraph_edge *e;
+  cgraph_edge *e;
 
   gcc_assert (new_version);
 
   /* Update the call expr on the edges to call the new version.  */
   for (e = new_version->callers; e; e = e->next_caller)
     {
-      struct function *inner_function = DECL_STRUCT_FUNCTION (e->caller->decl);
+      function *inner_function = DECL_STRUCT_FUNCTION (e->caller->decl);
       gimple_call_set_fndecl (e->call_stmt, new_version->decl);
       maybe_clean_eh_stmt_fn (inner_function, e->call_stmt);
     }
@@ -845,8 +897,8 @@ cgraph_node::create_version_clone (tree new_decl,
                                  vec<cgraph_edge *> redirect_callers,
                                  bitmap bbs_to_copy)
  {
-   struct cgraph_node *new_version;
-   struct cgraph_edge *e;
+   cgraph_node *new_version;
+   cgraph_edge *e;
    unsigned i;
 
    new_version = cgraph_node::create (new_decl);
@@ -855,6 +907,7 @@ cgraph_node::create_version_clone (tree new_decl,
    new_version->definition = definition;
    new_version->local = local;
    new_version->externally_visible = false;
+   new_version->no_reorder = no_reorder;
    new_version->local.local = new_version->definition;
    new_version->global = global;
    new_version->rtl = rtl;
@@ -863,25 +916,25 @@ cgraph_node::create_version_clone (tree new_decl,
    for (e = callees; e; e=e->next_callee)
      if (!bbs_to_copy
         || bitmap_bit_p (bbs_to_copy, gimple_bb (e->call_stmt)->index))
-       cgraph_clone_edge (e, new_version, e->call_stmt,
-                         e->lto_stmt_uid, REG_BR_PROB_BASE,
-                         CGRAPH_FREQ_BASE,
-                         true);
+       e->clone (new_version, e->call_stmt,
+                e->lto_stmt_uid, REG_BR_PROB_BASE,
+                CGRAPH_FREQ_BASE,
+                true);
    for (e = indirect_calls; e; e=e->next_callee)
      if (!bbs_to_copy
         || bitmap_bit_p (bbs_to_copy, gimple_bb (e->call_stmt)->index))
-       cgraph_clone_edge (e, new_version, e->call_stmt,
-                         e->lto_stmt_uid, REG_BR_PROB_BASE,
-                         CGRAPH_FREQ_BASE,
-                         true);
+       e->clone (new_version, e->call_stmt,
+                e->lto_stmt_uid, REG_BR_PROB_BASE,
+                CGRAPH_FREQ_BASE,
+                true);
    FOR_EACH_VEC_ELT (redirect_callers, i, e)
      {
        /* Redirect calls to the old version node to point to its new
          version.  */
-       cgraph_redirect_edge_callee (e, new_version);
+       e->redirect_callee (new_version);
      }
 
-   call_duplication_hooks (new_version);
+   symtab->call_cgraph_duplication_hooks (this, new_version);
 
    return new_version;
  }
@@ -913,7 +966,7 @@ cgraph_node::create_version_clone_with_body
    const char *clone_name)
 {
   tree old_decl = decl;
-  struct cgraph_node *new_version_node = NULL;
+  cgraph_node *new_version_node = NULL;
   tree new_decl;
 
   if (!tree_versionable_function_p (old_decl))
@@ -959,6 +1012,8 @@ cgraph_node::create_version_clone_with_body
   new_version_node->externally_visible = 0;
   new_version_node->local.local = 1;
   new_version_node->lowered = true;
+  if (!implicit_section)
+    new_version_node->set_section (get_section ());
   /* Clones of global symbols or symbols with unique names are unique.  */
   if ((TREE_PUBLIC (old_decl)
        && !DECL_EXTERNAL (old_decl)
@@ -970,14 +1025,14 @@ cgraph_node::create_version_clone_with_body
   /* Update the call_expr on the edges to call the new version node. */
   update_call_expr (new_version_node);
 
-  new_version_node->call_function_insertion_hooks ();
+  symtab->call_cgraph_insertion_hooks (this);
   return new_version_node;
 }
 
 /* Given virtual clone, turn it into actual clone.  */
 
 static void
-cgraph_materialize_clone (struct cgraph_node *node)
+cgraph_materialize_clone (cgraph_node *node)
 {
   bitmap_obstack_initialize (NULL);
   node->former_clone_of = node->clone_of->decl;
@@ -988,10 +1043,11 @@ cgraph_materialize_clone (struct cgraph_node *node)
                            node->clone.tree_map, true,
                            node->clone.args_to_skip, false,
                            NULL, NULL);
-  if (cgraph_dump_file)
+  if (symtab->dump_file)
     {
-      dump_function_to_file (node->clone_of->decl, cgraph_dump_file, dump_flags);
-      dump_function_to_file (node->decl, cgraph_dump_file, dump_flags);
+      dump_function_to_file (node->clone_of->decl, symtab->dump_file,
+                            dump_flags);
+      dump_function_to_file (node->decl, symtab->dump_file, dump_flags);
     }
 
   /* Function is no longer clone.  */
@@ -1020,14 +1076,14 @@ cgraph_materialize_clone (struct cgraph_node *node)
    this order.  */
 
 void
-cgraph_materialize_all_clones (void)
+symbol_table::materialize_all_clones (void)
 {
-  struct cgraph_node *node;
+  cgraph_node *node;
   bool stabilized = false;
   
 
-  if (cgraph_dump_file)
-    fprintf (cgraph_dump_file, "Materializing clones\n");
+  if (symtab->dump_file)
+    fprintf (symtab->dump_file, "Materializing clones\n");
 #ifdef ENABLE_CHECKING
   cgraph_node::verify_cgraph_nodes ();
 #endif
@@ -1044,42 +1100,43 @@ cgraph_materialize_all_clones (void)
              && !gimple_has_body_p (node->decl))
            {
              if (!node->clone_of->clone_of)
-               node->clone_of->get_body ();
+               node->clone_of->get_untransformed_body ();
              if (gimple_has_body_p (node->clone_of->decl))
                {
-                 if (cgraph_dump_file)
+                 if (symtab->dump_file)
                    {
-                     fprintf (cgraph_dump_file, "cloning %s to %s\n",
-                              xstrdup (node->clone_of->name ()),
-                              xstrdup (node->name ()));
+                     fprintf (symtab->dump_file, "cloning %s to %s\n",
+                              xstrdup_for_dump (node->clone_of->name ()),
+                              xstrdup_for_dump (node->name ()));
                      if (node->clone.tree_map)
                        {
                          unsigned int i;
-                         fprintf (cgraph_dump_file, "   replace map: ");
+                         fprintf (symtab->dump_file, "   replace map: ");
                          for (i = 0;
                               i < vec_safe_length (node->clone.tree_map);
                               i++)
                            {
-                             struct ipa_replace_map *replace_info;
+                             ipa_replace_map *replace_info;
                              replace_info = (*node->clone.tree_map)[i];
-                             print_generic_expr (cgraph_dump_file, replace_info->old_tree, 0);
-                             fprintf (cgraph_dump_file, " -> ");
-                             print_generic_expr (cgraph_dump_file, replace_info->new_tree, 0);
-                             fprintf (cgraph_dump_file, "%s%s;",
+                             print_generic_expr (symtab->dump_file, replace_info->old_tree, 0);
+                             fprintf (symtab->dump_file, " -> ");
+                             print_generic_expr (symtab->dump_file, replace_info->new_tree, 0);
+                             fprintf (symtab->dump_file, "%s%s;",
                                       replace_info->replace_p ? "(replace)":"",
                                       replace_info->ref_p ? "(ref)":"");
                            }
-                         fprintf (cgraph_dump_file, "\n");
+                         fprintf (symtab->dump_file, "\n");
                        }
                      if (node->clone.args_to_skip)
                        {
-                         fprintf (cgraph_dump_file, "   args_to_skip: ");
-                         dump_bitmap (cgraph_dump_file, node->clone.args_to_skip);
+                         fprintf (symtab->dump_file, "   args_to_skip: ");
+                         dump_bitmap (symtab->dump_file,
+                                      node->clone.args_to_skip);
                        }
                      if (node->clone.args_to_skip)
                        {
-                         fprintf (cgraph_dump_file, "   combined_args_to_skip:");
-                         dump_bitmap (cgraph_dump_file, node->clone.combined_args_to_skip);
+                         fprintf (symtab->dump_file, "   combined_args_to_skip:");
+                         dump_bitmap (symtab->dump_file, node->clone.combined_args_to_skip);
                        }
                    }
                  cgraph_materialize_clone (node);
@@ -1096,12 +1153,12 @@ cgraph_materialize_all_clones (void)
       }
     else
       node->clear_stmts_in_references ();
-  if (cgraph_dump_file)
-    fprintf (cgraph_dump_file, "Materialization Call site updates done.\n");
+  if (symtab->dump_file)
+    fprintf (symtab->dump_file, "Materialization Call site updates done.\n");
 #ifdef ENABLE_CHECKING
   cgraph_node::verify_cgraph_nodes ();
 #endif
-  symtab_remove_unreachable_nodes (false, cgraph_dump_file);
+  symtab->remove_unreachable_nodes (symtab->dump_file);
 }
 
 #include "gt-cgraphclones.h"