Move clone_info to summary

Jan Hubicka hubicka@ucw.cz
Sat Oct 31 09:20:54 GMT 2020


Hi,
this patch moves clone_info to summary.
Bootstrapped/regtested x86_64-linux, comitted.

Honza

2020-10-31  Jan Hubicka  <hubicka@ucw.cz>

	* Makefile.in: (OBJS): Add symtab-clones.o
	(GTFILES): Add symtab-clones.h
	* cgraph.c: Include symtab-clones.h.
	(cgraph_edge::resolve_speculation): Fix formating
	(cgraph_edge::redirect_call_stmt_to_callee): Update.
	(cgraph_update_edges_for_call_stmt): Update
	(release_function_body): Fix formating.
	(cgraph_node::remove): Fix formating.
	(cgraph_node::dump): Fix formating.
	(cgraph_node::get_availability): Fix formating.
	(cgraph_node::call_for_symbol_thunks_and_aliases): Fix formating.
	(set_const_flag_1): Fix formating.
	(set_pure_flag_1): Fix formating.
	(cgraph_node::can_remove_if_no_direct_calls_p): Fix formating.
	(collect_callers_of_node_1): Fix formating.
	(clone_of_p): Update.
	(cgraph_node::verify_node): Update.
	(cgraph_c_finalize): Call clone_info::release ().
	* cgraph.h (struct cgraph_clone_info): Move to symtab-clones.h.
	(cgraph_node): Remove clone_info.
	(symbol_table): Add m_clones.
	* cgraphclones.c: Include symtab-clone.h.
	(duplicate_thunk_for_node): Update.
	(cgraph_node::create_clone): Update.
	(cgraph_node::create_virtual_clone): Update.
	(cgraph_node::find_replacement): Update.
	(cgraph_node::materialize_clone): Update.
	* gengtype.c (open_base_files): Include symtab-clones.h.
	* ipa-cp.c: Include symtab-clones.h.
	(initialize_node_lattices): Update.
	(want_remove_some_param_p): Update.
	(create_specialized_node): Update.
	* ipa-fnsummary.c: Include symtab-clones.h.
	(ipa_fn_summary_t::duplicate): Update.
	* ipa-modref.c: Include symtab-clones.h.
	(update_signature): Update.
	* ipa-param-manipulation.c: Include symtab-clones.h.
	(ipa_param_body_adjustments::common_initialization): Update.
	* ipa-prop.c: Include symtab-clones.h.
	(adjust_agg_replacement_values): Update.
	(ipcp_get_parm_bits): Update.
	(ipcp_update_bits): Update.
	(ipcp_update_vr): Update.
	* ipa-sra.c: Include symtab-clones.h.
	(process_isra_node_results): Update.
	(disable_unavailable_parameters): Update.
	* lto-cgraph.c: Include symtab-clone.h.
	(output_cgraph_opt_summary_p): Update.
	(output_node_opt_summary): Update.
	(input_node_opt_summary): Update.
	* symtab-clones.cc: New file.
	* symtab-clones.h: New file.
	* tree-inline.c (expand_call_inline): Update.
	(update_clone_info): Update.
	(tree_function_versioning): Update.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7fc03c8d946..7b94497b6f2 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1299,6 +1299,7 @@ OBJS = \
 	cfgrtl.o \
 	symtab.o \
 	symtab-thunks.o \
+	symtab-clones.o \
 	cgraph.o \
 	cgraphbuild.o \
 	cgraphunit.o \
@@ -2594,6 +2595,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/output.h $(srcdir)/cfgloop.h $(srcdir)/cfg.h $(srcdir)/profile-count.h \
   $(srcdir)/cselib.h $(srcdir)/basic-block.h  $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \
   $(srcdir)/symtab-thunks.h $(srcdir)/symtab-thunks.cc \
+  $(srcdir)/symtab-clones.h \
   $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \
   $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
   $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-utils.h \
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 9129bcf12d2..9f3a7284310 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-inline.h"
 #include "tree-nested.h"
 #include "symtab-thunks.h"
+#include "symtab-clones.h"
 
 /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  */
 #include "tree-pass.h"
@@ -1236,7 +1237,7 @@ cgraph_edge::resolve_speculation (cgraph_edge *edge, tree callee_decl)
     {
       cgraph_edge *tmp = edge;
       if (dump_file)
-        fprintf (dump_file, "Speculative call turned into direct call.\n");
+	fprintf (dump_file, "Speculative call turned into direct call.\n");
       edge = e2;
       e2 = tmp;
       /* FIXME:  If EDGE is inlined, we should scale up the frequencies
@@ -1488,38 +1489,43 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e)
 	  return e->call_stmt;
 	}
     }
-
   if (flag_checking && decl)
     {
       cgraph_node *node = cgraph_node::get (decl);
-      gcc_assert (!node || !node->clone.param_adjustments);
+      clone_info *info = clone_info::get (node);
+      gcc_assert (!node || !info || !info->param_adjustments);
     }
 
+  clone_info *callee_info = clone_info::get (e->callee);
+  clone_info *caller_info = clone_info::get (e->caller);
+
   if (symtab->dump_file)
     {
+
       fprintf (symtab->dump_file, "updating call of %s -> %s: ",
 	       e->caller->dump_name (), e->callee->dump_name ());
       print_gimple_stmt (symtab->dump_file, e->call_stmt, 0, dump_flags);
-      if (e->callee->clone.param_adjustments)
-	e->callee->clone.param_adjustments->dump (symtab->dump_file);
+      if (callee_info && callee_info->param_adjustments)
+	callee_info->param_adjustments->dump (symtab->dump_file);
       unsigned performed_len
-	= vec_safe_length (e->caller->clone.performed_splits);
+	= vec_safe_length (caller_info->performed_splits);
       if (performed_len > 0)
 	fprintf (symtab->dump_file, "Performed splits records:\n");
       for (unsigned i = 0; i < performed_len; i++)
 	{
 	  ipa_param_performed_split *sm
-	    = &(*e->caller->clone.performed_splits)[i];
+	    = &(*caller_info->performed_splits)[i];
 	  print_node_brief (symtab->dump_file, "  dummy_decl: ", sm->dummy_decl,
 			    TDF_UID);
 	  fprintf (symtab->dump_file, ", unit_offset: %u\n", sm->unit_offset);
 	}
     }
 
-  if (ipa_param_adjustments *padjs = e->callee->clone.param_adjustments)
+  if (ipa_param_adjustments *padjs
+	 = callee_info ? callee_info->param_adjustments : NULL)
     {
       /* We need to defer cleaning EH info on the new statement to
-         fixup-cfg.  We may not have dominator information at this point
+	 fixup-cfg.  We may not have dominator information at this point
 	 and thus would end up with unreachable blocks and have no way
 	 to communicate that we need to run CFG cleanup then.  */
       int lp_nr = lookup_stmt_eh_lp (e->call_stmt);
@@ -1528,7 +1534,8 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e)
 
       tree old_fntype = gimple_call_fntype (e->call_stmt);
       new_stmt = padjs->modify_call (e->call_stmt,
-				     e->caller->clone.performed_splits,
+				     caller_info
+				     ? caller_info->performed_splits : NULL,
 				     e->callee->decl, false);
       cgraph_node *origin = e->callee;
       while (origin->clone_of)
@@ -1577,7 +1584,7 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e)
 	  var = get_or_create_ssa_default_def
 		  (DECL_STRUCT_FUNCTION (e->caller->decl), var);
 	  gimple *set_stmt = gimple_build_assign (lhs, var);
-          gsi = gsi_for_stmt (new_stmt);
+	  gsi = gsi_for_stmt (new_stmt);
 	  gsi_insert_before_without_update (&gsi, set_stmt, GSI_SAME_STMT);
 	  update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), set_stmt);
 	}
@@ -1703,7 +1710,8 @@ cgraph_update_edges_for_call_stmt (gimple *old_stmt, tree old_decl,
   if (orig->clones)
     for (node = orig->clones; node != orig;)
       {
-        cgraph_update_edges_for_call_stmt_node (node, old_stmt, old_decl, new_stmt);
+	cgraph_update_edges_for_call_stmt_node (node, old_stmt, old_decl,
+						new_stmt);
 	if (node->clones)
 	  node = node->clones;
 	else if (node->next_sibling_clone)
@@ -1809,7 +1817,7 @@ release_function_body (tree decl)
 	free_histograms (fn);
       gimple_set_body (decl, NULL);
       /* Struct function hangs a lot of data that would leak if we didn't
-         removed all pointers to it.   */
+	 removed all pointers to it.   */
       ggc_free (fn);
       DECL_STRUCT_FUNCTION (decl) = NULL;
     }
@@ -1880,7 +1888,7 @@ cgraph_node::remove (void)
       cgraph_node *n, *next;
 
       if (clone_of)
-        {
+	{
 	  for (n = clones; n->next_sibling_clone; n = n->next_sibling_clone)
 	    n->clone_of = clone_of;
 	  n->clone_of = clone_of;
@@ -1890,7 +1898,7 @@ cgraph_node::remove (void)
 	  clone_of->clones = clones;
 	}
       else
-        {
+	{
 	  /* We are removing node with clones.  This makes clones inconsistent,
 	     but assume they will be removed subsequently and just keep clone
 	     tree intact.  This can happen in unreachable function removal since
@@ -2248,12 +2256,12 @@ cgraph_node::dump (FILE *f)
     {
       if (edge->indirect_info->polymorphic)
 	{
-          fprintf (f, "   Polymorphic indirect call of type ");
+	  fprintf (f, "   Polymorphic indirect call of type ");
 	  print_generic_expr (f, edge->indirect_info->otr_type, TDF_SLIM);
 	  fprintf (f, " token:%i", (int) edge->indirect_info->otr_token);
 	}
       else
-        fprintf (f, "   Indirect call");
+	fprintf (f, "   Indirect call");
       edge->dump_edge_flags (f);
       if (edge->indirect_info->param_index != -1)
 	{
@@ -2350,8 +2358,8 @@ cgraph_node::get_availability (symtab_node *ref)
 
      Also comdat groups are always resolved in groups.  */
   else if ((this == ref && !has_aliases_p ())
-           || (ref && get_comdat_group ()
-               && get_comdat_group () == ref->get_comdat_group ()))
+	   || (ref && get_comdat_group ()
+	       && get_comdat_group () == ref->get_comdat_group ()))
     avail = AVAIL_AVAILABLE;
   /* Inline functions are safe to be analyzed even if their symbol can
      be overwritten at runtime.  It is not meaningful to enforce any sane
@@ -2419,7 +2427,7 @@ cgraph_node::call_for_symbol_thunks_and_aliases (bool (*callback)
       || (avail = get_availability ()) > AVAIL_INTERPOSABLE)
     {
       if (callback (this, data))
-        return true;
+	return true;
     }
   FOR_EACH_ALIAS (this, ref)
     {
@@ -2614,8 +2622,8 @@ set_const_flag_1 (cgraph_node *node, bool set_const, bool looping,
     {
       if (TREE_READONLY (node->decl))
 	{
-          TREE_READONLY (node->decl) = 0;
-          DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
+	  TREE_READONLY (node->decl) = 0;
+	  DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
 	  *changed = true;
 	}
     }
@@ -2642,14 +2650,14 @@ set_const_flag_1 (cgraph_node *node, bool set_const, bool looping,
 	{
 	  if (!looping && DECL_LOOPING_CONST_OR_PURE_P (node->decl))
 	    {
-              DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
+	      DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
 	      *changed = true;
 	    }
 	}
       else if (node->binds_to_current_def_p ())
 	{
 	  TREE_READONLY (node->decl) = true;
-          DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
+	  DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
 	  DECL_PURE_P (node->decl) = false;
 	  *changed = true;
 	}
@@ -2661,12 +2669,12 @@ set_const_flag_1 (cgraph_node *node, bool set_const, bool looping,
 	  if (!DECL_PURE_P (node->decl))
 	    {
 	      DECL_PURE_P (node->decl) = true;
-              DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
+	      DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
 	      *changed = true;
 	    }
 	  else if (!looping && DECL_LOOPING_CONST_OR_PURE_P (node->decl))
 	    {
-              DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
+	      DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
 	      *changed = true;
 	    }
 	}
@@ -2685,9 +2693,9 @@ set_const_flag_1 (cgraph_node *node, bool set_const, bool looping,
       {
 	/* Virtual thunks access virtual offset in the vtable, so they can
 	   only be pure, never const.  */
-        if (set_const
+	if (set_const
 	    && (thunk_info::get (e->caller)->virtual_offset_p
-	        || !node->binds_to_current_def_p (e->caller)))
+		|| !node->binds_to_current_def_p (e->caller)))
 	  *changed |= e->caller->set_pure_flag (true, looping);
 	else
 	  set_const_flag_1 (e->caller, set_const, looping, changed);
@@ -2757,14 +2765,14 @@ set_pure_flag_1 (cgraph_node *node, void *data)
     {
       if (!DECL_PURE_P (node->decl) && !TREE_READONLY (node->decl))
 	{
-          DECL_PURE_P (node->decl) = true;
-          DECL_LOOPING_CONST_OR_PURE_P (node->decl) = info->looping;
+	  DECL_PURE_P (node->decl) = true;
+	  DECL_LOOPING_CONST_OR_PURE_P (node->decl) = info->looping;
 	  info->changed = true;
 	}
       else if (DECL_LOOPING_CONST_OR_PURE_P (node->decl)
 	       && !info->looping)
 	{
-          DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
+	  DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
 	  info->changed = true;
 	}
     }
@@ -2772,8 +2780,8 @@ set_pure_flag_1 (cgraph_node *node, void *data)
     {
       if (DECL_PURE_P (node->decl))
 	{
-          DECL_PURE_P (node->decl) = false;
-          DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
+	  DECL_PURE_P (node->decl) = false;
+	  DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
 	  info->changed = true;
 	}
     }
@@ -2927,7 +2935,7 @@ cgraph_node::can_remove_if_no_direct_calls_p (bool will_inline)
       /* If function is not being inlined, we care only about
 	 references outside of the comdat group.  */
       if (!will_inline)
-        for (int i = 0; next->iterate_referring (i, ref); i++)
+	for (int i = 0; next->iterate_referring (i, ref); i++)
 	  if (ref->referring->get_comdat_group () != get_comdat_group ())
 	    return false;
     }
@@ -3031,7 +3039,7 @@ collect_callers_of_node_1 (cgraph_node *node, void *data)
     for (cs = node->callers; cs != NULL; cs = cs->next_caller)
       if (!cs->indirect_inlining_edge
 	  && !cs->caller->thunk)
-        redirect_callers->safe_push (cs);
+	redirect_callers->safe_push (cs);
   return false;
 }
 
@@ -3083,8 +3091,9 @@ clone_of_p (cgraph_node *node, cgraph_node *node2)
 	return true;
       node = node->callees->callee->ultimate_alias_target ();
 
-      if (!node2->clone.param_adjustments
-	  || node2->clone.param_adjustments->first_param_intact_p ())
+      clone_info *info = clone_info::get (node2);
+      if (!info || !info->param_adjustments
+	  || info->param_adjustments->first_param_intact_p ())
 	return false;
       if (node2->former_clone_of == node->decl
 	  || node2->former_clone_of == node->former_clone_of)
@@ -3615,7 +3624,7 @@ cgraph_node::verify_node (void)
       if (callees)
 	{
 	  error ("Alias has call edges");
-          error_found = true;
+	  error_found = true;
 	}
       for (i = 0; iterate_reference (i, ref); i++)
 	if (ref->use != IPA_REF_ALIAS)
@@ -3642,18 +3651,18 @@ cgraph_node::verify_node (void)
       if (!callees)
 	{
 	  error ("No edge out of thunk node");
-          error_found = true;
+	  error_found = true;
 	}
       else if (callees->next_callee)
 	{
 	  error ("More than one edge out of thunk node");
-          error_found = true;
+	  error_found = true;
 	}
       if (gimple_has_body_p (decl) && !inlined_to)
-        {
+	{
 	  error ("Thunk is not supposed to have body");
-          error_found = true;
-        }
+	  error_found = true;
+	}
     }
   else if (analyzed && gimple_has_body_p (decl)
 	   && !TREE_ASM_WRITTEN (decl)
@@ -3998,6 +4007,7 @@ cgraph_c_finalize (void)
 {
   nested_function_info::release ();
   thunk_info::release ();
+  clone_info::release ();
   symtab = NULL;
 
   x_cgraph_nodes_queue = NULL;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index fb3ad95e064..cf543705e13 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -691,27 +691,6 @@ struct GTY(()) ipa_replace_map
   int parm_num;
 };
 
-struct GTY(()) cgraph_clone_info
-{
-  /* Constants discovered by IPA-CP, i.e. which parameter should be replaced
-     with what.  */
-  vec<ipa_replace_map *, va_gc> *tree_map;
-  /* Parameter modification that IPA-SRA decided to perform.  */
-  ipa_param_adjustments *param_adjustments;
-  /* Lists of dummy-decl and offset pairs representing split formal parameters
-     in the caller.  Offsets of all new replacements are enumerated, those
-     coming from the same original parameter have the same dummy decl stored
-     along with them.
-
-     Dummy decls sit in call statement arguments followed by new parameter
-     decls (or their SSA names) in between (caller) clone materialization and
-     call redirection.  Redirection then recognizes the dummy variable and
-     together with the stored offsets can reconstruct what exactly the new
-     parameter decls represent and can leave in place only those that the
-     callee expects.  */
-  vec<ipa_param_performed_split, va_gc> *performed_splits;
-};
-
 enum cgraph_simd_clone_arg_type
 {
   SIMD_CLONE_ARG_TYPE_VECTOR,
@@ -879,7 +858,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
       next_sibling_clone (NULL), prev_sibling_clone (NULL), clones (NULL),
       clone_of (NULL), call_site_hash (NULL), former_clone_of (NULL),
       simdclone (NULL), simd_clones (NULL), ipa_transforms_to_apply (vNULL),
-      inlined_to (NULL), rtl (NULL), clone (),
+      inlined_to (NULL), rtl (NULL),
       count (profile_count::uninitialized ()),
       count_materialization_scale (REG_BR_PROB_BASE), profile_id (0),
       unit_id (0), tp_first_run (0), thunk (false),
@@ -1409,7 +1388,6 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
   cgraph_node *inlined_to;
 
   struct cgraph_rtl_info *rtl;
-  cgraph_clone_info clone;
 
   /* Expected number of executions: calculated in profile.c.  */
   profile_count count;
@@ -2190,10 +2168,16 @@ struct asmname_hasher : ggc_ptr_hash <symtab_node>
   static bool equal (symtab_node *n, const_tree t);
 };
 
+/* Core summaries maintained about symbols.  */
+
 struct thunk_info;
 template <class T> class function_summary;
 typedef function_summary <thunk_info *> thunk_summary;
 
+struct clone_info;
+template <class T> class function_summary;
+typedef function_summary <clone_info *> clone_summary;
+
 class GTY((tag ("SYMTAB"))) symbol_table
 {
 public:
@@ -2210,7 +2194,7 @@ public:
   function_flags_ready (false), cpp_implicit_aliases_done (false),
   section_hash (NULL), assembler_name_hash (NULL), init_priority_hash (NULL),
   dump_file (NULL), ipa_clones_dump_file (NULL), cloned_nodes (),
-  m_thunks (NULL),
+  m_thunks (NULL), m_clones (NULL),
   m_first_edge_removal_hook (NULL), m_first_cgraph_removal_hook (NULL),
   m_first_edge_duplicated_hook (NULL), m_first_cgraph_duplicated_hook (NULL),
   m_first_cgraph_insertion_hook (NULL), m_first_varpool_insertion_hook (NULL),
@@ -2495,6 +2479,9 @@ public:
   /* Thunk annotations.  */
   thunk_summary *m_thunks;
 
+  /* Virtual clone annotations.  */
+  clone_summary *m_clones;
+
 private:
   /* Allocate a cgraph_edge structure and fill it with data according to the
      parameters of which only CALLEE can be NULL (when creating an indirect
diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
index 0ed63078c91..b5793f90b64 100644
--- a/gcc/cgraphclones.c
+++ b/gcc/cgraphclones.c
@@ -86,6 +86,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "ipa-fnsummary.h"
 #include "symtab-thunks.h"
+#include "symtab-clones.h"
 
 /* Create clone of edge in the node N represented by CALL_EXPR
    the callgraph.  */
@@ -201,16 +202,17 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
       }
 
   tree new_decl;
-  if (node->clone.param_adjustments)
+  clone_info *info = clone_info::get (node);
+  if (info && info->param_adjustments)
     {
       /* We do not need to duplicate this_adjusting thunks if we have removed
 	 this.  */
       if (i->this_adjusting
-	  && !node->clone.param_adjustments->first_param_intact_p ())
+	  && !info->param_adjustments->first_param_intact_p ())
 	return node;
 
       new_decl = copy_node (thunk->decl);
-      ipa_param_body_adjustments body_adj (node->clone.param_adjustments,
+      ipa_param_body_adjustments body_adj (info->param_adjustments,
 					   new_decl);
       body_adj.modify_formal_parameters ();
     }
@@ -237,7 +239,9 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
   new_thunk->thunk = thunk->thunk;
   new_thunk->unique_name = in_lto_p;
   new_thunk->former_clone_of = thunk->decl;
-  new_thunk->clone.param_adjustments = node->clone.param_adjustments;
+  if (info->param_adjustments)
+    clone_info::get_create (new_thunk)->param_adjustments
+	   = info->param_adjustments;
   new_thunk->unit_id = thunk->unit_id;
   new_thunk->merged_comdat = thunk->merged_comdat;
   new_thunk->merged_extern_inline = thunk->merged_extern_inline;
@@ -403,13 +407,16 @@ cgraph_node::create_clone (tree new_decl, profile_count prof_count,
   new_node->unit_id = unit_id;
   new_node->merged_comdat = merged_comdat;
   new_node->merged_extern_inline = merged_extern_inline;
+  clone_info *info = clone_info::get (this);
 
   if (param_adjustments)
-    new_node->clone.param_adjustments = param_adjustments;
-  else
-    new_node->clone.param_adjustments = clone.param_adjustments;
-  new_node->clone.tree_map = NULL;
-  new_node->clone.performed_splits = vec_safe_copy (clone.performed_splits);
+    clone_info::get_create (new_node)->param_adjustments = param_adjustments;
+  else if (info && info->param_adjustments)
+    clone_info::get_create (new_node)->param_adjustments
+	 = info->param_adjustments;
+  if (info && info->performed_splits)
+    clone_info::get_create (new_node)->performed_splits
+	 = vec_safe_copy (info->performed_splits);
   new_node->split_part = split_part;
 
   FOR_EACH_VEC_ELT (redirect_callers, i, e)
@@ -616,7 +623,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->ipcp_clone = ipcp_clone;
-  new_node->clone.tree_map = tree_map;
+  if (tree_map)
+    clone_info::get_create (new_node)->tree_map = tree_map;
   if (!implicit_section)
     new_node->set_section (get_section ());
 
@@ -682,7 +690,9 @@ cgraph_node::find_replacement (void)
       clones = NULL;
 
       /* Copy clone info.  */
-      next_inline_clone->clone = clone;
+      clone_info *info = clone_info::get (this);
+      if (info)
+	*clone_info::get_create (next_inline_clone) = *info;
 
       /* Now place it into clone tree at same level at NODE.  */
       next_inline_clone->clone_of = clone_of;
@@ -1087,6 +1097,7 @@ void cgraph_node::remove_from_clone_tree ()
 void
 cgraph_node::materialize_clone ()
 {
+  clone_info *info = clone_info::get (this);
   clone_of->get_untransformed_body ();
   former_clone_of = clone_of->decl;
   if (clone_of->former_clone_of)
@@ -1096,15 +1107,15 @@ cgraph_node::materialize_clone ()
       fprintf (symtab->dump_file, "cloning %s to %s\n",
 	       clone_of->dump_name (),
 	       dump_name ());
-      if (clone.tree_map)
+      if (info->tree_map)
         {
 	  fprintf (symtab->dump_file, "    replace map:");
 	  for (unsigned int i = 0;
-	       i < vec_safe_length (clone.tree_map);
+	       i < vec_safe_length (info->tree_map);
 	       i++)
 	    {
 	      ipa_replace_map *replace_info;
-	      replace_info = (*clone.tree_map)[i];
+	      replace_info = (*info->tree_map)[i];
 	      fprintf (symtab->dump_file, "%s %i -> ",
 		       i ? "," : "", replace_info->parm_num);
 	      print_generic_expr (symtab->dump_file,
@@ -1112,13 +1123,14 @@ cgraph_node::materialize_clone ()
 	    }
 	  fprintf (symtab->dump_file, "\n");
 	}
-      if (clone.param_adjustments)
-	clone.param_adjustments->dump (symtab->dump_file);
+      if (info->param_adjustments)
+	info->param_adjustments->dump (symtab->dump_file);
     }
   clear_stmts_in_references ();
   /* Copy the OLD_VERSION_NODE function tree to the new version.  */
   tree_function_versioning (clone_of->decl, decl,
-			    clone.tree_map, clone.param_adjustments,
+			    info ? info->tree_map : NULL,
+			    info ? info->param_adjustments : NULL,
 			    true, NULL, NULL);
   if (symtab->dump_file)
     {
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index dd21ade5795..a7cf5c25893 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -1727,6 +1727,7 @@ open_base_files (void)
       "target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h",
       "ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h", "omp-general.h",
       "omp-offload.h", "ipa-modref-tree.h", "ipa-modref.h", "symtab-thunks.h",
+      "symtab-clones.h",
       NULL
     };
     const char *const *ifp;
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 028480f6ce4..140515668a6 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -124,6 +124,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "dbgcnt.h"
+#include "symtab-clones.h"
 
 template <typename valtype> class ipcp_value;
 
@@ -1226,18 +1227,21 @@ initialize_node_lattices (struct cgraph_node *node)
 
   auto_vec<bool, 16> surviving_params;
   bool pre_modified = false;
-  if (!disable && node->clone.param_adjustments)
+
+  clone_info *cinfo = clone_info::get (node);
+
+  if (!disable && cinfo && cinfo->param_adjustments)
     {
       /* At the moment all IPA optimizations should use the number of
 	 parameters of the prevailing decl as the m_always_copy_start.
 	 Handling any other value would complicate the code below, so for the
 	 time bing let's only assert it is so.  */
-      gcc_assert ((node->clone.param_adjustments->m_always_copy_start
+      gcc_assert ((cinfo->param_adjustments->m_always_copy_start
 		   == ipa_get_param_count (info))
-		  || node->clone.param_adjustments->m_always_copy_start < 0);
+		  || cinfo->param_adjustments->m_always_copy_start < 0);
 
       pre_modified = true;
-      node->clone.param_adjustments->get_surviving_params (&surviving_params);
+      cinfo->param_adjustments->get_surviving_params (&surviving_params);
 
       if (dump_file && (dump_flags & TDF_DETAILS)
 	  && !node->alias && !node->thunk)
@@ -4456,9 +4460,10 @@ want_remove_some_param_p (cgraph_node *node, vec<tree> known_csts)
 
       if (!filled_vec)
        {
-         if (!node->clone.param_adjustments)
+	 clone_info *info = clone_info::get (node);
+	 if (!info || !info->param_adjustments)
            return true;
-         node->clone.param_adjustments->get_surviving_params (&surviving);
+	 info->param_adjustments->get_surviving_params (&surviving);
          filled_vec = true;
        }
       if (surviving.length() < (unsigned) i &&  surviving[i])
@@ -4484,7 +4489,9 @@ create_specialized_node (struct cgraph_node *node,
   struct ipa_agg_replacement_value *av;
   struct cgraph_node *new_node;
   int i, count = ipa_get_param_count (info);
-  ipa_param_adjustments *old_adjustments = node->clone.param_adjustments;
+  clone_info *cinfo = clone_info::get (node);
+  ipa_param_adjustments *old_adjustments = cinfo
+					   ? cinfo->param_adjustments : NULL;
   ipa_param_adjustments *new_adjustments;
   gcc_assert (!info->ipcp_orig_node);
   gcc_assert (node->can_change_signature
@@ -4538,7 +4545,7 @@ create_specialized_node (struct cgraph_node *node,
   else
     new_adjustments = NULL;
 
-  replace_trees = vec_safe_copy (node->clone.tree_map);
+  replace_trees = cinfo ? vec_safe_copy (cinfo->tree_map) : NULL;
   for (i = 0; i < count; i++)
     {
       tree t = known_csts[i];
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index ff05ab67238..0393f2cad11 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "tree-into-ssa.h"
+#include "symtab-clones.h"
 
 /* Summaries.  */
 fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
@@ -811,9 +812,10 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
      that are known to be false or true.  */
   info->conds = vec_safe_copy (info->conds);
 
+  clone_info *cinfo = clone_info::get (dst);
   /* When there are any replacements in the function body, see if we can figure
      out that something was optimized out.  */
-  if (ipa_node_params_sum && dst->clone.tree_map)
+  if (ipa_node_params_sum && cinfo && cinfo->tree_map)
     {
       vec<size_time_entry, va_gc> *entry = info->size_time_table;
       /* Use SRC parm info since it may not be copied yet.  */
@@ -834,7 +836,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
 	{
 	  struct ipa_replace_map *r;
 
-	  for (j = 0; vec_safe_iterate (dst->clone.tree_map, j, &r); j++)
+	  for (j = 0; vec_safe_iterate (cinfo->tree_map, j, &r); j++)
 	    {
 	      if (r->parm_num == i)
 		{
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 007cebaa3a2..b40f3da3ba2 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "ipa-fnsummary.h"
 #include "attr-fnspec.h"
+#include "symtab-clones.h"
 
 /* Class (from which there is one global instance) that holds modref summaries
    for all analyzed functions.  */
@@ -1606,7 +1607,8 @@ modref_read (void)
 static void
 update_signature (struct cgraph_node *node)
 {
-  if (!node->clone.param_adjustments)
+  clone_info *info = clone_info::get (node);
+  if (!info || !info->param_adjustments)
     return;
 
   modref_summary *r = optimization_summaries
@@ -1625,9 +1627,9 @@ update_signature (struct cgraph_node *node)
   size_t i, max = 0;
   ipa_adjusted_param *p;
 
-  FOR_EACH_VEC_SAFE_ELT (node->clone.param_adjustments->m_adj_params, i, p)
+  FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
     {
-      int idx = node->clone.param_adjustments->get_original_index (i);
+      int idx = info->param_adjustments->get_original_index (i);
       if (idx > (int)max)
 	max = idx;
     }
@@ -1637,9 +1639,9 @@ update_signature (struct cgraph_node *node)
   map.reserve (max + 1);
   for (i = 0; i <= max; i++)
     map.quick_push (-1);
-  FOR_EACH_VEC_SAFE_ELT (node->clone.param_adjustments->m_adj_params, i, p)
+  FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
     {
-      int idx = node->clone.param_adjustments->get_original_index (i);
+      int idx = info->param_adjustments->get_original_index (i);
       if (idx >= 0)
 	map[idx] = i;
     }
diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c
index 438f4bd5a68..2bbea21be2e 100644
--- a/gcc/ipa-param-manipulation.c
+++ b/gcc/ipa-param-manipulation.c
@@ -40,6 +40,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "tree-ssa.h"
 #include "tree-inline.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "symtab-clones.h"
 
 
 /* Actual prefixes of different newly synthetized parameters.  Keep in sync
@@ -1072,7 +1075,8 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl,
 		  ipa_param_performed_split ps;
 		  ps.dummy_decl = dummy_decl;
 		  ps.unit_offset = apm->unit_offset;
-		  vec_safe_push (m_id->dst_node->clone.performed_splits, ps);
+		  vec_safe_push (clone_info::get_create
+				   (m_id->dst_node)->performed_splits, ps);
 		}
 	      else
 		register_replacement (apm, new_parm);
@@ -1131,11 +1135,11 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl,
 	 when they were in fact replaced by a constant.  */
       auto_vec <int, 16> index_mapping;
       bool need_remap = false;
+      clone_info *info = clone_info::get (m_id->src_node);
 
-      if (m_id && m_id->src_node->clone.param_adjustments)
+      if (m_id && info && info->param_adjustments)
 	{
-	  ipa_param_adjustments *prev_adjustments
-	    = m_id->src_node->clone.param_adjustments;
+	  ipa_param_adjustments *prev_adjustments = info->param_adjustments;
 	  prev_adjustments->get_updated_indices (&index_mapping);
 	  need_remap = true;
 	}
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 6014766b418..d4ef6ff8a8e 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "tree-cfgcleanup.h"
 #include "options.h"
+#include "symtab-clones.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -5419,12 +5420,13 @@ adjust_agg_replacement_values (struct cgraph_node *node,
 			       struct ipa_agg_replacement_value *aggval)
 {
   struct ipa_agg_replacement_value *v;
+  clone_info *cinfo = clone_info::get (node);
 
-  if (!node->clone.param_adjustments)
+  if (!cinfo || !cinfo->param_adjustments)
     return;
 
   auto_vec<int, 16> new_indices;
-  node->clone.param_adjustments->get_updated_indices (&new_indices);
+  cinfo->param_adjustments->get_updated_indices (&new_indices);
   for (v = aggval; v; v = v->next)
     {
       gcc_checking_assert (v->index >= 0);
@@ -5577,9 +5579,10 @@ ipcp_get_parm_bits (tree parm, tree *value, widest_int *mask)
 	return false;
     }
 
-  if (cnode->clone.param_adjustments)
+  clone_info *cinfo = clone_info::get (cnode);
+  if (cinfo && cinfo->param_adjustments)
     {
-      i = cnode->clone.param_adjustments->get_original_index (i);
+      i = cinfo->param_adjustments->get_original_index (i);
       if (i < 0)
 	return false;
     }
@@ -5610,9 +5613,10 @@ ipcp_update_bits (struct cgraph_node *node)
 
   auto_vec<int, 16> new_indices;
   bool need_remapping = false;
-  if (node->clone.param_adjustments)
+  clone_info *cinfo = clone_info::get (node);
+  if (cinfo && cinfo->param_adjustments)
     {
-      node->clone.param_adjustments->get_updated_indices (&new_indices);
+      cinfo->param_adjustments->get_updated_indices (&new_indices);
       need_remapping = true;
     }
   auto_vec <tree, 16> parm_decls;
@@ -5731,9 +5735,10 @@ ipcp_update_vr (struct cgraph_node *node)
 
   auto_vec<int, 16> new_indices;
   bool need_remapping = false;
-  if (node->clone.param_adjustments)
+  clone_info *cinfo = clone_info::get (node);
+  if (cinfo && cinfo->param_adjustments)
     {
-      node->clone.param_adjustments->get_updated_indices (&new_indices);
+      cinfo->param_adjustments->get_updated_indices (&new_indices);
       need_remapping = true;
     }
   auto_vec <tree, 16> parm_decls;
diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c
index 07227c0bfec..82acc6a21cb 100644
--- a/gcc/ipa-sra.c
+++ b/gcc/ipa-sra.c
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfganal.h"
 #include "tree-streamer.h"
 #include "internal-fn.h"
+#include "symtab-clones.h"
 
 static void ipa_sra_summarize_function (cgraph_node *);
 
@@ -3686,10 +3687,11 @@ process_isra_node_results (cgraph_node *node,
 
   auto_vec<bool, 16> surviving_params;
   bool check_surviving = false;
-  if (node->clone.param_adjustments)
+  clone_info *cinfo = clone_info::get (node);
+  if (cinfo && cinfo->param_adjustments)
     {
       check_surviving = true;
-      node->clone.param_adjustments->get_surviving_params (&surviving_params);
+      cinfo->param_adjustments->get_surviving_params (&surviving_params);
     }
 
   unsigned param_count = vec_safe_length (ifs->m_parameters);
@@ -3723,7 +3725,8 @@ process_isra_node_results (cgraph_node *node,
     }
 
   vec<ipa_adjusted_param, va_gc> *new_params = NULL;
-  if (ipa_param_adjustments *old_adjustments = node->clone.param_adjustments)
+  if (ipa_param_adjustments *old_adjustments
+	 = cinfo ? cinfo->param_adjustments : NULL)
     {
       unsigned old_adj_len = vec_safe_length (old_adjustments->m_adj_params);
       for (unsigned i = 0; i < old_adj_len; i++)
@@ -3784,10 +3787,11 @@ disable_unavailable_parameters (cgraph_node *node, isra_func_summary *ifs)
 
   auto_vec<bool, 16> surviving_params;
   bool check_surviving = false;
-  if (node->clone.param_adjustments)
+  clone_info *cinfo = clone_info::get (node);
+  if (cinfo && cinfo->param_adjustments)
     {
       check_surviving = true;
-      node->clone.param_adjustments->get_surviving_params (&surviving_params);
+      cinfo->param_adjustments->get_surviving_params (&surviving_params);
     }
   bool dumped_first = false;
   for (unsigned i = 0; i < len; i++)
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index 91900a12fa2..8718678136d 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "symbol-summary.h"
 #include "symtab-thunks.h"
+#include "symtab-clones.h"
 
 /* True when asm nodes has been output.  */
 bool asm_nodes_output = false;
@@ -1823,9 +1824,10 @@ input_offload_tables (bool do_force_output)
 static int
 output_cgraph_opt_summary_p (struct cgraph_node *node)
 {
-  return ((node->clone_of || node->former_clone_of)
-	  && (node->clone.tree_map
-	      || node->clone.param_adjustments));
+  if (node->clone_of || node->former_clone_of)
+    return true;
+  clone_info *info = clone_info::get (node);
+  return info && (info->tree_map || info->param_adjustments);
 }
 
 /* Output optimization summary for EDGE to OB.  */
@@ -1849,9 +1851,12 @@ output_node_opt_summary (struct output_block *ob,
   /* TODO: Should this code be moved to ipa-param-manipulation?  */
   struct bitpack_d bp;
   bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, (node->clone.param_adjustments != NULL), 1);
+  clone_info *info = clone_info::get (node);
+  
+  bp_pack_value (&bp, (info && info->param_adjustments != NULL), 1);
   streamer_write_bitpack (&bp);
-  if (ipa_param_adjustments *adjustments = node->clone.param_adjustments)
+  if (ipa_param_adjustments *adjustments
+		 = info ? info->param_adjustments : NULL)
     {
       streamer_write_uhwi (ob, vec_safe_length (adjustments->m_adj_params));
       ipa_adjusted_param *adj;
@@ -1879,17 +1884,18 @@ output_node_opt_summary (struct output_block *ob,
 	}
       streamer_write_hwi (ob, adjustments->m_always_copy_start);
       bp = bitpack_create (ob->main_stream);
-      bp_pack_value (&bp, node->clone.param_adjustments->m_skip_return, 1);
+      bp_pack_value (&bp, info->param_adjustments->m_skip_return, 1);
       streamer_write_bitpack (&bp);
     }
 
-  streamer_write_uhwi (ob, vec_safe_length (node->clone.tree_map));
-  FOR_EACH_VEC_SAFE_ELT (node->clone.tree_map, i, map)
-    {
-      streamer_write_uhwi (ob, map->parm_num);
-      gcc_assert (EXPR_LOCATION (map->new_tree) == UNKNOWN_LOCATION);
-      stream_write_tree (ob, map->new_tree, true);
-    }
+  streamer_write_uhwi (ob, info ? vec_safe_length (info->tree_map) : 0);
+  if (info)
+    FOR_EACH_VEC_SAFE_ELT (info->tree_map, i, map)
+      {
+	streamer_write_uhwi (ob, map->parm_num);
+	gcc_assert (EXPR_LOCATION (map->new_tree) == UNKNOWN_LOCATION);
+	stream_write_tree (ob, map->new_tree, true);
+      }
 
   if (lto_symtab_encoder_in_partition_p (encoder, node))
     {
@@ -1959,6 +1965,8 @@ input_node_opt_summary (struct cgraph_node *node,
   struct bitpack_d bp;
   bp = streamer_read_bitpack (ib_main);
   bool have_adjustments = bp_unpack_value (&bp, 1);
+  clone_info *info = clone_info::get_create (node);
+
   if (have_adjustments)
     {
       count = streamer_read_uhwi (ib_main);
@@ -1991,7 +1999,7 @@ input_node_opt_summary (struct cgraph_node *node,
       int always_copy_start = streamer_read_hwi (ib_main);
       bp = streamer_read_bitpack (ib_main);
       bool skip_return = bp_unpack_value (&bp, 1);
-      node->clone.param_adjustments
+      info->param_adjustments
 	= (new (ggc_alloc <ipa_param_adjustments> ())
 	   ipa_param_adjustments (new_params, always_copy_start, skip_return));
     }
@@ -2001,7 +2009,7 @@ input_node_opt_summary (struct cgraph_node *node,
     {
       struct ipa_replace_map *map = ggc_alloc<ipa_replace_map> ();
 
-      vec_safe_push (node->clone.tree_map, map);
+      vec_safe_push (info->tree_map, map);
       map->parm_num = streamer_read_uhwi (ib_main);
       map->new_tree = stream_read_tree (ib_main, data_in);
     }
diff --git a/gcc/symtab-clones.cc b/gcc/symtab-clones.cc
new file mode 100644
index 00000000000..76b86c6496f
--- /dev/null
+++ b/gcc/symtab-clones.cc
@@ -0,0 +1,76 @@
+/* Support for virtual clones in symbol table.
+   Copyright (C) 2003-2020 Free Software Foundation, Inc.
+   Contributed by Jan Hubicka
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "predict.h"
+#include "target.h"
+#include "rtl.h"
+#include "alloc-pool.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
+#include "symtab-clones.h"
+#include "lto-streamer.h"
+#include "data-streamer.h"
+
+namespace {
+
+/* Function summary for clone_infos.  */
+class GTY((user)) clone_infos_t: public function_summary <clone_info *>
+{
+public:
+  clone_infos_t (symbol_table *table, bool ggc):
+    function_summary<clone_info *> (table, ggc) { }
+
+  /* Hook that is called by summary when a node is duplicated.  */
+  virtual void duplicate (cgraph_node *node,
+			  cgraph_node *node2,
+			  clone_info *data,
+			  clone_info *data2);
+};
+
+/* Duplication hook.  */
+void
+clone_infos_t::duplicate (cgraph_node *, cgraph_node *,
+			  clone_info *src, clone_info *dst)
+{
+  *dst = *src;
+}
+
+}  /* anon namespace  */
+
+/* Return thunk_info possibly creating new one.  */
+clone_info *
+clone_info::get_create (cgraph_node *node)
+{
+  if (!symtab->m_clones)
+    {
+      symtab->m_clones
+	 = new (ggc_alloc_no_dtor <clone_infos_t> ())
+	     clone_infos_t (symtab, true);
+      symtab->m_clones->disable_insertion_hook ();
+      symtab->m_clones->disable_duplication_hook ();
+    }
+  return symtab->m_clones->get_create (node);
+}
diff --git a/gcc/symtab-clones.h b/gcc/symtab-clones.h
new file mode 100644
index 00000000000..a34fe21412e
--- /dev/null
+++ b/gcc/symtab-clones.h
@@ -0,0 +1,90 @@
+/* Representation of adjustment made to virtual clones in the symbol table.
+   Copyright (C) 2003-2020 Free Software Foundation, Inc.
+   Contributed by Jan Hubicka
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_SYMTAB_CLONES_H
+#define GCC_SYMTAB_CLONES_H
+
+struct GTY(()) clone_info
+{
+  /* Constructor.  */
+  clone_info ()
+    : tree_map (NULL),
+      param_adjustments (NULL),
+      performed_splits (NULL)
+  {
+  }
+  /* Constants discovered by IPA-CP, i.e. which parameter should be replaced
+     with what.  */
+  vec<ipa_replace_map *, va_gc> *tree_map;
+  /* Parameter modification that IPA-SRA decided to perform.  */
+  ipa_param_adjustments *param_adjustments;
+  /* Lists of dummy-decl and offset pairs representing split formal parameters
+     in the caller.  Offsets of all new replacements are enumerated, those
+     coming from the same original parameter have the same dummy decl stored
+     along with them.
+
+     Dummy decls sit in call statement arguments followed by new parameter
+     decls (or their SSA names) in between (caller) clone materialization and
+     call redirection.  Redirection then recognizes the dummy variable and
+     together with the stored offsets can reconstruct what exactly the new
+     parameter decls represent and can leave in place only those that the
+     callee expects.  */
+  vec<ipa_param_performed_split, va_gc> *performed_splits;
+
+  /* Return clone_info, if available.  */
+  static clone_info *get (cgraph_node *node);
+
+  /* Return clone_info possibly creating new one.  */
+  static clone_info *get_create (cgraph_node *node);
+
+  /* Remove clone_info.  */
+  static void remove (cgraph_node *node);
+
+  /* Release all clone_infos.  */
+  static void release (void);
+};
+
+/* Return clone_info, if available.  */
+inline clone_info *
+clone_info::get (cgraph_node *node)
+{
+  if (!symtab->m_clones)
+    return NULL;
+  return symtab->m_clones->get (node);
+}
+
+
+/* Remove clone_info association for NODE.  */
+inline void
+clone_info::remove (cgraph_node *node)
+{
+  symtab->m_clones->remove (node);
+}
+
+/* Free clone info summaries.  */
+inline void
+clone_info::release ()
+{
+  if (symtab->m_clones)
+    delete (symtab->m_clones);
+  symtab->m_clones = NULL;
+}
+
+#endif  /* GCC_SYMTAB_CLONES_H  */
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 32fb3789f40..32424b169c7 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -64,6 +64,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "symbol-summary.h"
 #include "symtab-thunks.h"
+#include "symtab-clones.h"
 
 /* I'm not real happy about this, but we need to handle gimple and
    non-gimple trees.  */
@@ -4702,6 +4703,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
   use_operand_p use;
   gimple *simtenter_stmt = NULL;
   vec<tree> *simtvars_save;
+  clone_info *info;
 
   /* The gimplifier uses input_location in too many places, such as
      internal_get_tmp_var ().  */
@@ -5024,31 +5026,33 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
   /* Add local vars in this inlined callee to caller.  */
   add_local_variables (id->src_cfun, cfun, id);
 
-  if (id->src_node->clone.performed_splits)
+  info = clone_info::get (id->src_node);
+  if (info && info->performed_splits)
     {
+      clone_info *dst_info = clone_info::get_create (id->dst_node);
       /* Any calls from the inlined function will be turned into calls from the
 	 function we inline into.  We must preserve notes about how to split
 	 parameters such calls should be redirected/updated.  */
-      unsigned len = vec_safe_length (id->src_node->clone.performed_splits);
+      unsigned len = vec_safe_length (info->performed_splits);
       for (unsigned i = 0; i < len; i++)
 	{
 	  ipa_param_performed_split ps
-	    = (*id->src_node->clone.performed_splits)[i];
+	    = (*info->performed_splits)[i];
 	  ps.dummy_decl = remap_decl (ps.dummy_decl, id);
-	  vec_safe_push (id->dst_node->clone.performed_splits, ps);
+	  vec_safe_push (dst_info->performed_splits, ps);
 	}
 
       if (flag_checking)
 	{
-	  len = vec_safe_length (id->dst_node->clone.performed_splits);
+	  len = vec_safe_length (dst_info->performed_splits);
 	  for (unsigned i = 0; i < len; i++)
 	    {
 	      ipa_param_performed_split *ps1
-		= &(*id->dst_node->clone.performed_splits)[i];
+		= &(*dst_info->performed_splits)[i];
 	      for (unsigned j = i + 1; j < len; j++)
 		{
 		  ipa_param_performed_split *ps2
-		    = &(*id->dst_node->clone.performed_splits)[j];
+		    = &(*dst_info->performed_splits)[j];
 		  gcc_assert (ps1->dummy_decl != ps2->dummy_decl
 			      || ps1->unit_offset != ps2->unit_offset);
 		}
@@ -6074,8 +6078,9 @@ tree_versionable_function_p (tree fndecl)
 static void
 update_clone_info (copy_body_data * id)
 {
+  clone_info *dst_info = clone_info::get (id->dst_node);
   vec<ipa_param_performed_split, va_gc> *cur_performed_splits
-    = id->dst_node->clone.performed_splits;
+    = dst_info ? dst_info->performed_splits : NULL;
   if (cur_performed_splits)
     {
       unsigned len = cur_performed_splits->length ();
@@ -6092,23 +6097,24 @@ update_clone_info (copy_body_data * id)
   for (node = id->dst_node->clones; node != id->dst_node;)
     {
       /* First update replace maps to match the new body.  */
-      if (node->clone.tree_map)
-        {
+      clone_info *info = clone_info::get (node);
+      if (info && info->tree_map)
+	{
 	  unsigned int i;
-          for (i = 0; i < vec_safe_length (node->clone.tree_map); i++)
+	  for (i = 0; i < vec_safe_length (info->tree_map); i++)
 	    {
 	      struct ipa_replace_map *replace_info;
-	      replace_info = (*node->clone.tree_map)[i];
+	      replace_info = (*info->tree_map)[i];
 	      walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL);
 	    }
 	}
-      if (node->clone.performed_splits)
+      if (info && info->performed_splits)
 	{
-	  unsigned len = vec_safe_length (node->clone.performed_splits);
+	  unsigned len = vec_safe_length (info->performed_splits);
 	  for (unsigned i = 0; i < len; i++)
 	    {
 	      ipa_param_performed_split *ps
-		= &(*node->clone.performed_splits)[i];
+		= &(*info->performed_splits)[i];
 	      ps->dummy_decl = remap_decl (ps->dummy_decl, id);
 	    }
 	}
@@ -6118,10 +6124,12 @@ update_clone_info (copy_body_data * id)
 	     a copy of function body for later during inlining, that would just
 	     duplicate all entries.  So let's have a look whether anything
 	     referring to the first dummy_decl is present.  */
-	  unsigned dst_len = vec_safe_length (node->clone.performed_splits);
+	  if (!info)
+	    info = clone_info::get_create (node);
+	  unsigned dst_len = vec_safe_length (info->performed_splits);
 	  ipa_param_performed_split *first = &(*cur_performed_splits)[0];
 	  for (unsigned i = 0; i < dst_len; i++)
-	    if ((*node->clone.performed_splits)[i].dummy_decl
+	    if ((*info->performed_splits)[i].dummy_decl
 		== first->dummy_decl)
 	      {
 		len = 0;
@@ -6129,18 +6137,18 @@ update_clone_info (copy_body_data * id)
 	      }
 
 	  for (unsigned i = 0; i < len; i++)
-	    vec_safe_push (node->clone.performed_splits,
+	    vec_safe_push (info->performed_splits,
 			   (*cur_performed_splits)[i]);
 	  if (flag_checking)
 	    {
 	      for (unsigned i = 0; i < dst_len; i++)
 		{
 		  ipa_param_performed_split *ps1
-		    = &(*node->clone.performed_splits)[i];
+		    = &(*info->performed_splits)[i];
 		  for (unsigned j = i + 1; j < dst_len; j++)
 		    {
 		      ipa_param_performed_split *ps2
-			= &(*node->clone.performed_splits)[j];
+			= &(*info->performed_splits)[j];
 		      gcc_assert (ps1->dummy_decl != ps2->dummy_decl
 				  || ps1->unit_offset != ps2->unit_offset);
 		    }
@@ -6270,8 +6278,9 @@ tree_function_versioning (tree old_decl, tree new_decl,
       = copy_static_chain (p, &id);
 
   auto_vec<int, 16> new_param_indices;
+  clone_info *info = clone_info::get (old_version_node);
   ipa_param_adjustments *old_param_adjustments
-    = old_version_node->clone.param_adjustments;
+    = info ? info->param_adjustments : NULL;
   if (old_param_adjustments)
     old_param_adjustments->get_updated_indices (&new_param_indices);
 


More information about the Gcc-patches mailing list