diff mbox

[2/6] Introduce new edge_summary class and replace ipa_edge_args_sum.

Message ID 7267a56ab77ff35fa4d77ea6d4eba9d924187be1.1436438929.git.mliska@suse.cz
State New
Headers show

Commit Message

Martin Liška July 9, 2015, 9:13 a.m. UTC
gcc/ChangeLog:

2015-07-03  Martin Liska  <mliska@suse.cz>

	* cgraph.c (symbol_table::create_edge): Introduce summary_uid
	for cgraph_edge.
	* cgraph.h (struct GTY): Likewise.
	* ipa-inline-analysis.c (estimate_function_body_sizes): Use
	new data structure.
	* ipa-profile.c (ipa_profile): Likewise.
	* ipa-prop.c (ipa_print_node_jump_functions):
	(ipa_propagate_indirect_call_infos): Likewise.
	(ipa_free_edge_args_substructures): Likewise.
	(ipa_free_all_edge_args): Likewise.
	(ipa_edge_args_t::remove): Likewise.
	(ipa_edge_removal_hook): Likewise.
	(ipa_edge_args_t::duplicate): Likewise.
	(ipa_register_cgraph_hooks): Likewise.
	(ipa_unregister_cgraph_hooks): Likewise.
	* ipa-prop.h (ipa_check_create_edge_args): Likewise.
	(ipa_edge_args_info_available_for_edge_p): Likewise.
	* symbol-summary.h (gt_ggc_mx): Indent properly.
	(gt_pch_nx): Likewise.
	(edge_summary): New class.
---
 gcc/cgraph.c              |   2 +
 gcc/cgraph.h              |   5 +-
 gcc/ipa-inline-analysis.c |   2 +-
 gcc/ipa-profile.c         |   2 +-
 gcc/ipa-prop.c            |  71 +++-------------
 gcc/ipa-prop.h            |  44 ++++++----
 gcc/symbol-summary.h      | 208 +++++++++++++++++++++++++++++++++++++++++++++-
 7 files changed, 252 insertions(+), 82 deletions(-)

Comments

Jeff Law July 9, 2015, 5:15 p.m. UTC | #1
On 07/09/2015 03:13 AM, mliska wrote:
> gcc/ChangeLog:
>
> 2015-07-03  Martin Liska  <mliska@suse.cz>
>
> 	* cgraph.c (symbol_table::create_edge): Introduce summary_uid
> 	for cgraph_edge.
> 	* cgraph.h (struct GTY): Likewise.
> 	* ipa-inline-analysis.c (estimate_function_body_sizes): Use
> 	new data structure.
> 	* ipa-profile.c (ipa_profile): Likewise.
> 	* ipa-prop.c (ipa_print_node_jump_functions):
> 	(ipa_propagate_indirect_call_infos): Likewise.
> 	(ipa_free_edge_args_substructures): Likewise.
> 	(ipa_free_all_edge_args): Likewise.
> 	(ipa_edge_args_t::remove): Likewise.
> 	(ipa_edge_removal_hook): Likewise.
> 	(ipa_edge_args_t::duplicate): Likewise.
> 	(ipa_register_cgraph_hooks): Likewise.
> 	(ipa_unregister_cgraph_hooks): Likewise.
> 	* ipa-prop.h (ipa_check_create_edge_args): Likewise.
> 	(ipa_edge_args_info_available_for_edge_p): Likewise.
> 	* symbol-summary.h (gt_ggc_mx): Indent properly.
> 	(gt_pch_nx): Likewise.
> 	(edge_summary): New class.
> ---
>   gcc/cgraph.c              |   2 +
>   gcc/cgraph.h              |   5 +-
>   gcc/ipa-inline-analysis.c |   2 +-
>   gcc/ipa-profile.c         |   2 +-
>   gcc/ipa-prop.c            |  71 +++-------------
>   gcc/ipa-prop.h            |  44 ++++++----
>   gcc/symbol-summary.h      | 208 +++++++++++++++++++++++++++++++++++++++++++++-
>   7 files changed, 252 insertions(+), 82 deletions(-)
>
>
}
> +
> +  /* Destruction method that can be called for GGT purpose.  */
GGT stands for?


OK for the trunk.

Thanks,
Jeff
Martin Jambor July 10, 2015, 1:31 p.m. UTC | #2
Hi,

thanks for working on this and sorry for a tad late review:

On Thu, Jul 09, 2015 at 11:13:52AM +0200, Martin Liska wrote:
> gcc/ChangeLog:
> 
> 2015-07-03  Martin Liska  <mliska@suse.cz>
> 
> 	* cgraph.c (symbol_table::create_edge): Introduce summary_uid
> 	for cgraph_edge.
> 	* cgraph.h (struct GTY): Likewise.

struct GTY does not look right :-)

> 	* ipa-inline-analysis.c (estimate_function_body_sizes): Use
> 	new data structure.
> 	* ipa-profile.c (ipa_profile): Likewise.
> 	* ipa-prop.c (ipa_print_node_jump_functions):

                                                      Likewise.

> 	(ipa_propagate_indirect_call_infos): Likewise.
> 	(ipa_free_edge_args_substructures): Likewise.
> 	(ipa_free_all_edge_args): Likewise.
> 	(ipa_edge_args_t::remove): Likewise.
> 	(ipa_edge_removal_hook): Likewise.
> 	(ipa_edge_args_t::duplicate): Likewise.
> 	(ipa_register_cgraph_hooks): Likewise.
> 	(ipa_unregister_cgraph_hooks): Likewise.
> 	* ipa-prop.h (ipa_check_create_edge_args): Likewise.
> 	(ipa_edge_args_info_available_for_edge_p): Likewise.

Definition of ipa_edge_args_t is missing here.

> 	* symbol-summary.h (gt_ggc_mx): Indent properly.
> 	(gt_pch_nx): Likewise.
> 	(edge_summary): New class.
> ---
>  gcc/cgraph.c              |   2 +
>  gcc/cgraph.h              |   5 +-
>  gcc/ipa-inline-analysis.c |   2 +-
>  gcc/ipa-profile.c         |   2 +-
>  gcc/ipa-prop.c            |  71 +++-------------
>  gcc/ipa-prop.h            |  44 ++++++----
>  gcc/symbol-summary.h      | 208 +++++++++++++++++++++++++++++++++++++++++++++-
>  7 files changed, 252 insertions(+), 82 deletions(-)
> 

...

> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
> index e6725aa..f0af9b2 100644
> --- a/gcc/ipa-prop.h
> +++ b/gcc/ipa-prop.h
> @@ -493,13 +493,36 @@ public:
>  extern ipa_node_params_t *ipa_node_params_sum;
>  /* Vector of IPA-CP transformation data for each clone.  */
>  extern GTY(()) vec<ipcp_transformation_summary, va_gc> *ipcp_transformations;
> -/* Vector where the parameter infos are actually stored. */
> -extern GTY(()) vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
> +
> +/* Function summary for ipa_node_params.  */
> +class GTY((user)) ipa_edge_args_t: public edge_summary <ipa_edge_args *>
> +{
> +public:
> +  ipa_edge_args_t (symbol_table *symtab):
> +    edge_summary <ipa_edge_args*> (symtab, true) { }
> +
> +  static ipa_edge_args_t *create_ggc (symbol_table *symtab)
> +  {

Please move the body of this function to where the bodies of the rest
of the member functions are.

> +    ipa_edge_args_t *summary = new (ggc_cleared_alloc <ipa_edge_args_t> ())
> +      ipa_edge_args_t (symtab);
> +    return summary;
> +  }
> +
> +  /* Hook that is called by summary when a node is duplicated.  */
> +  virtual void duplicate (cgraph_edge *edge,
> +			  cgraph_edge *edge2,
> +			  ipa_edge_args *data,
> +			  ipa_edge_args *data2);
> +
> +  virtual void remove (cgraph_edge *edge, ipa_edge_args *data);
> +};
> +
> +extern GTY(()) edge_summary <ipa_edge_args *> *ipa_edge_args_sum;
>  
>  /* Return the associated parameter/argument info corresponding to the given
>     node/edge.  */
>  #define IPA_NODE_REF(NODE) (ipa_node_params_sum->get (NODE))
> -#define IPA_EDGE_REF(EDGE) (&(*ipa_edge_args_vector)[(EDGE)->uid])
> +#define IPA_EDGE_REF(EDGE) (ipa_edge_args_sum->get (EDGE))
>  /* This macro checks validity of index returned by
>     ipa_get_param_decl_index function.  */
>  #define IS_VALID_JUMP_FUNC_INDEX(I) ((I) != -1)
> @@ -532,19 +555,8 @@ ipa_check_create_node_params (void)
>  static inline void
>  ipa_check_create_edge_args (void)
>  {
> -  if (vec_safe_length (ipa_edge_args_vector)
> -      <= (unsigned) symtab->edges_max_uid)
> -    vec_safe_grow_cleared (ipa_edge_args_vector, symtab->edges_max_uid + 1);
> -}
> -
> -/* Returns true if the array of edge infos is large enough to accommodate an
> -   info for EDGE.  The main purpose of this function is that debug dumping
> -   function can check info availability without causing reallocations.  */
> -
> -static inline bool
> -ipa_edge_args_info_available_for_edge_p (struct cgraph_edge *edge)
> -{
> -  return ((unsigned) edge->uid < vec_safe_length (ipa_edge_args_vector));
> +  if (ipa_edge_args_sum == NULL)
> +    ipa_edge_args_sum = ipa_edge_args_t::create_ggc (symtab);
>  }
>  
>  static inline ipcp_transformation_summary *
> diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
> index eefbfd9..5799443 100644
> --- a/gcc/symbol-summary.h
> +++ b/gcc/symbol-summary.h
> @@ -108,7 +108,7 @@ public:
>    /* Allocates new data that are stored within map.  */
>    T* allocate_new ()
>    {
> -    return m_ggc ? new (ggc_alloc <T> ()) T() : new T () ;
> +    return m_ggc ? new (ggc_alloc <T> ()) T () : new T () ;
>    }
>  
>    /* Release an item that is stored within map.  */
> @@ -234,7 +234,7 @@ private:
>  
>  template <typename T>
>  void
> -gt_ggc_mx(function_summary<T *>* const &summary)
> +gt_ggc_mx (function_summary<T *>* const &summary)
>  {
>    gcc_checking_assert (summary->m_ggc);
>    gt_ggc_mx (&summary->m_map);
> @@ -242,7 +242,7 @@ gt_ggc_mx(function_summary<T *>* const &summary)
>  
>  template <typename T>
>  void
> -gt_pch_nx(function_summary<T *>* const &summary)
> +gt_pch_nx (function_summary<T *>* const &summary)
>  {
>    gcc_checking_assert (summary->m_ggc);
>    gt_pch_nx (&summary->m_map);
> @@ -250,11 +250,211 @@ gt_pch_nx(function_summary<T *>* const &summary)
>  
>  template <typename T>
>  void
> -gt_pch_nx(function_summary<T *>* const& summary, gt_pointer_operator op,
> +gt_pch_nx (function_summary<T *>* const& summary, gt_pointer_operator op,
>  	  void *cookie)
>  {
>    gcc_checking_assert (summary->m_ggc);
>    gt_pch_nx (&summary->m_map, op, cookie);
>  }
>  
> +/* We want to pass just pointer types as argument for edge_summary
> +   template class.  */
> +
> +template <class T>
> +class edge_summary
> +{
> +private:
> +  edge_summary ();
> +};
> +

Two general remarks about both summary classes.  First, they both
certainly need some descriptive comment.  I assume this can be added
as a followup.

Second, I'm afraid that having (non-trivial) function definitions
inside the class definition violates our coding conventions
(https://gcc.gnu.org/codingconventions.html#Member_Form).  I
understand that, many other classes throughout gcc also have them, but
it seems there is consensus to eradicate it
(https://gcc.gnu.org/ml/gcc/2015-06/msg00241.html) so we at least
should not be adding new cases.

(And I also think that comments need to be separated by a blank line
from the stuff they describe, but that is probably a minor issue, at
least for me.)

> +template <class T>
> +class GTY((user)) edge_summary <T *>
> +{
> +public:
> +  /* Default construction takes SYMTAB as an argument.  */
> +  edge_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc),
> +    m_map (13, ggc), m_symtab (symtab)
> +  {
> +#ifdef ENABLE_CHECKING
> +    cgraph_node *node;
> +
> +    FOR_EACH_FUNCTION (node)
> +    {

I'm quite sure you want to verify edges, not nodes, here.

> +      gcc_checking_assert (node->summary_uid > 0);
> +    }
> +#endif
> +
> +    m_symtab_removal_hook =
> +      symtab->add_edge_removal_hook
> +      (edge_summary::symtab_removal, this);
> +    m_symtab_duplication_hook =
> +      symtab->add_edge_duplication_hook
> +      (edge_summary::symtab_duplication, this);
> +  }
> +
> +  /* Destructor.  */
> +  virtual ~edge_summary ()
> +  {
> +    release ();
> +  }
> +
> +  /* Destruction method that can be called for GGT purpose.  */
> +  void release ()
> +  {
> +    if (m_symtab_removal_hook)
> +      m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
> +
> +    if (m_symtab_duplication_hook)
> +      m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
> +
> +    m_symtab_removal_hook = NULL;
> +    m_symtab_duplication_hook = NULL;
> +
> +    /* Release all summaries.  */
> +    typedef typename hash_map <map_hash, T *>::iterator map_iterator;
> +    for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
> +      release ((*it).second);
> +  }
> +
> +  /* Traverses all summarys with a function F called with
> +     ARG as argument.  */
> +  template<typename Arg, bool (*f)(const T &, Arg)>
> +  void traverse (Arg a) const
> +  {
> +    m_map.traverse <f> (a);
> +  }
> +
> +  /* Initializer is called after we allocate a new node.  */

We don't allocate a node but an edge.

> +  virtual void initialize (cgraph_edge *, T *) {}
> +
> +  /* Basic implementation of removal operation.  */
> +  virtual void remove (cgraph_edge *, T *) {}
> +
> +  /* Basic implementation of duplication operation.  */
> +  virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}

Perhaps this should actually be implemented by a simple assignment for
very basic summary types?

> +
> +  /* Allocates new data that are stored within map.  */
> +  T* allocate_new (cgraph_edge *edge)
> +  {
> +    T *v = m_ggc ? new (ggc_alloc <T> ()) T () : new T () ;
> +    initialize (edge, v);
> +
> +    return v;
> +  }
> +
> +  /* Release an item that is stored within map.  */
> +  void release (T *item)
> +  {
> +    if (m_ggc)
> +      {
> +	item->~T ();
> +	ggc_free (item);
> +      }
> +    else
> +      delete item;
> +  }
> +
> +  /* Getter for summary edge node pointer.  */

I'd suggest "Getter of edge summary" instead

> +  T* get (cgraph_edge *edge)
> +  {
> +    bool existed;
> +    T **v = &m_map.get_or_insert (edge->summary_uid, &existed);
> +    if (!existed)
> +      *v = allocate_new (edge);
> +
> +    return *v;
> +  }
> +
> +  /* Return number of elements handled by data structure.  */
> +  size_t elements ()
> +  {
> +    return m_map.elements ();
> +  }
> +
> +  /* Symbol removal hook that is registered to symbol table.  */
> +  static void symtab_removal (cgraph_edge *node, void *data)

Please call the first parameter "edge"

> +  {
> +    gcc_checking_assert (node->summary_uid);
> +    edge_summary *summary = (edge_summary <T *> *) (data);
> +
> +    int summary_uid = node->summary_uid;
> +    T **v = summary->m_map.get (summary_uid);
> +
> +    if (v)
> +      {
> +	summary->remove (node, *v);
> +
> +	if (!summary->m_ggc)
> +	  delete (*v);
> +
> +	summary->m_map.remove (summary_uid);
> +      }
> +  }
> +
> +  /* Symbol duplication hook that is registered to symbol table.  */
> +  static void symtab_duplication (cgraph_edge *edge, cgraph_edge *edge2,
> +				  void *data)
> +  {
> +    edge_summary *summary = (edge_summary <T *> *) (data);
> +    T *s = summary->get (edge);
> +
> +    gcc_checking_assert (s);
> +    gcc_checking_assert (edge2->summary_uid > 0);
> +
> +    /* This load is necessary, because we insert a new value!  */

What load?

Apart from the above, I'll be very glad to have this class.

Thanks,

Martin
diff mbox

Patch

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index d13bcd3..d7b6257 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -851,6 +851,8 @@  symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee,
       edge->uid = edges_max_uid++;
     }
 
+  edge->summary_uid = edge_max_summary_uid++;
+
   edges_count++;
 
   edge->aux = NULL;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 0fe58e1..ef71958 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1593,6 +1593,8 @@  struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
   int frequency;
   /* Unique id of the edge.  */
   int uid;
+  /* Not recycled unique id of the node.  */
+  int summary_uid;
   /* Whether this edge was made direct by indirect inlining.  */
   unsigned int indirect_inlining_edge : 1;
   /* Whether this edge describes an indirect call with an undetermined
@@ -1874,7 +1876,7 @@  public:
   friend class cgraph_node;
   friend class cgraph_edge;
 
-  symbol_table (): cgraph_max_summary_uid (1)
+  symbol_table (): cgraph_max_summary_uid (1), edge_max_summary_uid (1)
   {
   }
 
@@ -2078,6 +2080,7 @@  public:
 
   int edges_count;
   int edges_max_uid;
+  int edge_max_summary_uid;
 
   symtab_node* GTY(()) nodes;
   asm_node* GTY(()) asmnodes;
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index d5dbfbd..c11dc9c 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -2852,7 +2852,7 @@  estimate_function_body_sizes (struct cgraph_node *node, bool early)
     {
       if (!early)
         loop_optimizer_finalize ();
-      else if (!ipa_edge_args_vector)
+      else if (!ipa_edge_args_sum)
 	ipa_free_all_node_params ();
       free_dominance_info (CDI_DOMINATORS);
     }
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index 698729b..6d6afb3 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -627,7 +627,7 @@  ipa_profile (void)
 				 "Not speculating: target is overwritable "
 				 "and can be discarded.\n");
 		    }
-		  else if (ipa_node_params_sum && ipa_edge_args_vector
+		  else if (ipa_node_params_sum && ipa_edge_args_sum
 			   && !IPA_NODE_REF (n2)->descriptors.is_empty ()
 			   && ipa_get_param_count (IPA_NODE_REF (n2))
 			      != ipa_get_cs_argument_count (IPA_EDGE_REF (e))
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 6074194..9750a26 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -125,12 +125,10 @@  struct func_body_info
 ipa_node_params_t *ipa_node_params_sum = NULL;
 /* Vector of IPA-CP transformation data for each clone.  */
 vec<ipcp_transformation_summary, va_gc> *ipcp_transformations;
-/* Vector where the parameter infos are actually stored. */
-vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
+
+edge_summary <ipa_edge_args *> *ipa_edge_args_sum;
 
 /* Holders of ipa cgraph hooks: */
-static struct cgraph_edge_hook_list *edge_removal_hook_holder;
-static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
 static struct cgraph_node_hook_list *function_insertion_hook_holder;
 
 /* Description of a reference to an IPA constant.  */
@@ -386,9 +384,6 @@  ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
 	   node->order);
   for (cs = node->callees; cs; cs = cs->next_callee)
     {
-      if (!ipa_edge_args_info_available_for_edge_p (cs))
-	continue;
-
       fprintf (f, "    callsite  %s/%i -> %s/%i : \n",
 	       xstrdup_for_dump (node->name ()), node->order,
 	       xstrdup_for_dump (cs->callee->name ()),
@@ -399,8 +394,6 @@  ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
     {
       struct cgraph_indirect_call_info *ii;
-      if (!ipa_edge_args_info_available_for_edge_p (cs))
-	continue;
 
       ii = cs->indirect_info;
       if (ii->agg_contents)
@@ -3330,7 +3323,7 @@  ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
      (i.e. during early inlining).  */
   if (!ipa_node_params_sum)
     return false;
-  gcc_assert (ipa_edge_args_vector);
+  gcc_assert (ipa_edge_args_sum);
 
   propagate_controlled_uses (cs);
   changed = propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
@@ -3338,16 +3331,6 @@  ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
   return changed;
 }
 
-/* Frees all dynamically allocated structures that the argument info points
-   to.  */
-
-void
-ipa_free_edge_args_substructures (struct ipa_edge_args *args)
-{
-  vec_free (args->jump_functions);
-  memset (args, 0, sizeof (*args));
-}
-
 /* Free all ipa_edge structures.  */
 
 void
@@ -3356,13 +3339,11 @@  ipa_free_all_edge_args (void)
   int i;
   struct ipa_edge_args *args;
 
-  if (!ipa_edge_args_vector)
+  if (!ipa_edge_args_sum)
     return;
 
-  FOR_EACH_VEC_ELT (*ipa_edge_args_vector, i, args)
-    ipa_free_edge_args_substructures (args);
-
-  vec_free (ipa_edge_args_vector);
+  ipa_edge_args_sum->release ();
+  ipa_edge_args_sum = NULL;
 }
 
 /* Frees all dynamically allocated structures that the param info points
@@ -3414,18 +3395,9 @@  ipa_set_node_agg_value_chain (struct cgraph_node *node,
   (*ipcp_transformations)[node->uid].agg_values = aggvals;
 }
 
-/* Hook that is called by cgraph.c when an edge is removed.  */
-
-static void
-ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED)
+void
+ipa_edge_args_t::remove (cgraph_edge *edge, ipa_edge_args *args)
 {
-  struct ipa_edge_args *args;
-
-  /* During IPA-CP updating we can be called on not-yet analyzed clones.  */
-  if (vec_safe_length (ipa_edge_args_vector) <= (unsigned)cs->uid)
-    return;
-
-  args = IPA_EDGE_REF (cs);
   if (args->jump_functions)
     {
       struct ipa_jump_func *jf;
@@ -3436,28 +3408,19 @@  ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED)
 	  try_decrement_rdesc_refcount (jf);
 	  if (jf->type == IPA_JF_CONST
 	      && (rdesc = ipa_get_jf_constant_rdesc (jf))
-	      && rdesc->cs == cs)
+	      && rdesc->cs == edge)
 	    rdesc->cs = NULL;
 	}
     }
-
-  ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
 }
 
-/* Hook that is called by cgraph.c when an edge is duplicated.  */
-
-static void
-ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
-			   void *)
+void
+ipa_edge_args_t::duplicate (cgraph_edge *src, cgraph_edge *dst,
+			  ipa_edge_args *old_args, ipa_edge_args *new_args)
 {
-  struct ipa_edge_args *old_args, *new_args;
   unsigned int i;
-
   ipa_check_create_edge_args ();
 
-  old_args = IPA_EDGE_REF (src);
-  new_args = IPA_EDGE_REF (dst);
-
   new_args->jump_functions = vec_safe_copy (old_args->jump_functions);
   if (old_args->polymorphic_call_contexts)
     new_args->polymorphic_call_contexts
@@ -3607,12 +3570,6 @@  ipa_register_cgraph_hooks (void)
 {
   ipa_check_create_node_params ();
 
-  if (!edge_removal_hook_holder)
-    edge_removal_hook_holder =
-      symtab->add_edge_removal_hook (&ipa_edge_removal_hook, NULL);
-  if (!edge_duplication_hook_holder)
-    edge_duplication_hook_holder =
-      symtab->add_edge_duplication_hook (&ipa_edge_duplication_hook, NULL);
   function_insertion_hook_holder =
       symtab->add_cgraph_insertion_hook (&ipa_add_new_function, NULL);
 }
@@ -3622,10 +3579,6 @@  ipa_register_cgraph_hooks (void)
 static void
 ipa_unregister_cgraph_hooks (void)
 {
-  symtab->remove_edge_removal_hook (edge_removal_hook_holder);
-  edge_removal_hook_holder = NULL;
-  symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
-  edge_duplication_hook_holder = NULL;
   symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
   function_insertion_hook_holder = NULL;
 }
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index e6725aa..f0af9b2 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -493,13 +493,36 @@  public:
 extern ipa_node_params_t *ipa_node_params_sum;
 /* Vector of IPA-CP transformation data for each clone.  */
 extern GTY(()) vec<ipcp_transformation_summary, va_gc> *ipcp_transformations;
-/* Vector where the parameter infos are actually stored. */
-extern GTY(()) vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
+
+/* Function summary for ipa_node_params.  */
+class GTY((user)) ipa_edge_args_t: public edge_summary <ipa_edge_args *>
+{
+public:
+  ipa_edge_args_t (symbol_table *symtab):
+    edge_summary <ipa_edge_args*> (symtab, true) { }
+
+  static ipa_edge_args_t *create_ggc (symbol_table *symtab)
+  {
+    ipa_edge_args_t *summary = new (ggc_cleared_alloc <ipa_edge_args_t> ())
+      ipa_edge_args_t (symtab);
+    return summary;
+  }
+
+  /* Hook that is called by summary when a node is duplicated.  */
+  virtual void duplicate (cgraph_edge *edge,
+			  cgraph_edge *edge2,
+			  ipa_edge_args *data,
+			  ipa_edge_args *data2);
+
+  virtual void remove (cgraph_edge *edge, ipa_edge_args *data);
+};
+
+extern GTY(()) edge_summary <ipa_edge_args *> *ipa_edge_args_sum;
 
 /* Return the associated parameter/argument info corresponding to the given
    node/edge.  */
 #define IPA_NODE_REF(NODE) (ipa_node_params_sum->get (NODE))
-#define IPA_EDGE_REF(EDGE) (&(*ipa_edge_args_vector)[(EDGE)->uid])
+#define IPA_EDGE_REF(EDGE) (ipa_edge_args_sum->get (EDGE))
 /* This macro checks validity of index returned by
    ipa_get_param_decl_index function.  */
 #define IS_VALID_JUMP_FUNC_INDEX(I) ((I) != -1)
@@ -532,19 +555,8 @@  ipa_check_create_node_params (void)
 static inline void
 ipa_check_create_edge_args (void)
 {
-  if (vec_safe_length (ipa_edge_args_vector)
-      <= (unsigned) symtab->edges_max_uid)
-    vec_safe_grow_cleared (ipa_edge_args_vector, symtab->edges_max_uid + 1);
-}
-
-/* Returns true if the array of edge infos is large enough to accommodate an
-   info for EDGE.  The main purpose of this function is that debug dumping
-   function can check info availability without causing reallocations.  */
-
-static inline bool
-ipa_edge_args_info_available_for_edge_p (struct cgraph_edge *edge)
-{
-  return ((unsigned) edge->uid < vec_safe_length (ipa_edge_args_vector));
+  if (ipa_edge_args_sum == NULL)
+    ipa_edge_args_sum = ipa_edge_args_t::create_ggc (symtab);
 }
 
 static inline ipcp_transformation_summary *
diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
index eefbfd9..5799443 100644
--- a/gcc/symbol-summary.h
+++ b/gcc/symbol-summary.h
@@ -108,7 +108,7 @@  public:
   /* Allocates new data that are stored within map.  */
   T* allocate_new ()
   {
-    return m_ggc ? new (ggc_alloc <T> ()) T() : new T () ;
+    return m_ggc ? new (ggc_alloc <T> ()) T () : new T () ;
   }
 
   /* Release an item that is stored within map.  */
@@ -234,7 +234,7 @@  private:
 
 template <typename T>
 void
-gt_ggc_mx(function_summary<T *>* const &summary)
+gt_ggc_mx (function_summary<T *>* const &summary)
 {
   gcc_checking_assert (summary->m_ggc);
   gt_ggc_mx (&summary->m_map);
@@ -242,7 +242,7 @@  gt_ggc_mx(function_summary<T *>* const &summary)
 
 template <typename T>
 void
-gt_pch_nx(function_summary<T *>* const &summary)
+gt_pch_nx (function_summary<T *>* const &summary)
 {
   gcc_checking_assert (summary->m_ggc);
   gt_pch_nx (&summary->m_map);
@@ -250,11 +250,211 @@  gt_pch_nx(function_summary<T *>* const &summary)
 
 template <typename T>
 void
-gt_pch_nx(function_summary<T *>* const& summary, gt_pointer_operator op,
+gt_pch_nx (function_summary<T *>* const& summary, gt_pointer_operator op,
 	  void *cookie)
 {
   gcc_checking_assert (summary->m_ggc);
   gt_pch_nx (&summary->m_map, op, cookie);
 }
 
+/* We want to pass just pointer types as argument for edge_summary
+   template class.  */
+
+template <class T>
+class edge_summary
+{
+private:
+  edge_summary ();
+};
+
+template <class T>
+class GTY((user)) edge_summary <T *>
+{
+public:
+  /* Default construction takes SYMTAB as an argument.  */
+  edge_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc),
+    m_map (13, ggc), m_symtab (symtab)
+  {
+#ifdef ENABLE_CHECKING
+    cgraph_node *node;
+
+    FOR_EACH_FUNCTION (node)
+    {
+      gcc_checking_assert (node->summary_uid > 0);
+    }
+#endif
+
+    m_symtab_removal_hook =
+      symtab->add_edge_removal_hook
+      (edge_summary::symtab_removal, this);
+    m_symtab_duplication_hook =
+      symtab->add_edge_duplication_hook
+      (edge_summary::symtab_duplication, this);
+  }
+
+  /* Destructor.  */
+  virtual ~edge_summary ()
+  {
+    release ();
+  }
+
+  /* Destruction method that can be called for GGT purpose.  */
+  void release ()
+  {
+    if (m_symtab_removal_hook)
+      m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
+
+    if (m_symtab_duplication_hook)
+      m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
+
+    m_symtab_removal_hook = NULL;
+    m_symtab_duplication_hook = NULL;
+
+    /* Release all summaries.  */
+    typedef typename hash_map <map_hash, T *>::iterator map_iterator;
+    for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
+      release ((*it).second);
+  }
+
+  /* Traverses all summarys with a function F called with
+     ARG as argument.  */
+  template<typename Arg, bool (*f)(const T &, Arg)>
+  void traverse (Arg a) const
+  {
+    m_map.traverse <f> (a);
+  }
+
+  /* Initializer is called after we allocate a new node.  */
+  virtual void initialize (cgraph_edge *, T *) {}
+
+  /* Basic implementation of removal operation.  */
+  virtual void remove (cgraph_edge *, T *) {}
+
+  /* Basic implementation of duplication operation.  */
+  virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
+
+  /* Allocates new data that are stored within map.  */
+  T* allocate_new (cgraph_edge *edge)
+  {
+    T *v = m_ggc ? new (ggc_alloc <T> ()) T () : new T () ;
+    initialize (edge, v);
+
+    return v;
+  }
+
+  /* Release an item that is stored within map.  */
+  void release (T *item)
+  {
+    if (m_ggc)
+      {
+	item->~T ();
+	ggc_free (item);
+      }
+    else
+      delete item;
+  }
+
+  /* Getter for summary edge node pointer.  */
+  T* get (cgraph_edge *edge)
+  {
+    bool existed;
+    T **v = &m_map.get_or_insert (edge->summary_uid, &existed);
+    if (!existed)
+      *v = allocate_new (edge);
+
+    return *v;
+  }
+
+  /* Return number of elements handled by data structure.  */
+  size_t elements ()
+  {
+    return m_map.elements ();
+  }
+
+  /* Symbol removal hook that is registered to symbol table.  */
+  static void symtab_removal (cgraph_edge *node, void *data)
+  {
+    gcc_checking_assert (node->summary_uid);
+    edge_summary *summary = (edge_summary <T *> *) (data);
+
+    int summary_uid = node->summary_uid;
+    T **v = summary->m_map.get (summary_uid);
+
+    if (v)
+      {
+	summary->remove (node, *v);
+
+	if (!summary->m_ggc)
+	  delete (*v);
+
+	summary->m_map.remove (summary_uid);
+      }
+  }
+
+  /* Symbol duplication hook that is registered to symbol table.  */
+  static void symtab_duplication (cgraph_edge *edge, cgraph_edge *edge2,
+				  void *data)
+  {
+    edge_summary *summary = (edge_summary <T *> *) (data);
+    T *s = summary->get (edge);
+
+    gcc_checking_assert (s);
+    gcc_checking_assert (edge2->summary_uid > 0);
+
+    /* This load is necessary, because we insert a new value!  */
+    T *duplicate = summary->allocate_new (edge2);
+    summary->m_map.put (edge2->summary_uid, duplicate);
+    summary->duplicate (edge, edge2, s, duplicate);
+  }
+
+protected:
+  /* Indication if we use ggc summary.  */
+  bool m_ggc;
+
+private:
+  typedef int_hash <int, 0, -1> map_hash;
+
+  /* Main summary store, where summary ID is used as key.  */
+  hash_map <map_hash, T *> m_map;
+  /* Internal summary insertion hook pointer.  */
+  cgraph_edge_hook_list *m_symtab_insertion_hook;
+  /* Internal summary removal hook pointer.  */
+  cgraph_edge_hook_list *m_symtab_removal_hook;
+  /* Internal summary duplication hook pointer.  */
+  cgraph_2edge_hook_list *m_symtab_duplication_hook;
+  /* Symbol table the summary is registered to.  */
+  symbol_table *m_symtab;
+
+  template <typename U> friend void gt_ggc_mx (edge_summary <U *> * const &);
+  template <typename U> friend void gt_pch_nx (edge_summary <U *> * const &);
+  template <typename U> friend void gt_pch_nx (edge_summary <U *> * const &,
+      gt_pointer_operator, void *);
+};
+
+template <typename T>
+void
+gt_ggc_mx (edge_summary<T *>* const &summary)
+{
+  gcc_checking_assert (summary->m_ggc);
+  gt_ggc_mx (&summary->m_map);
+}
+
+template <typename T>
+void
+gt_pch_nx (edge_summary<T *>* const &summary)
+{
+  gcc_checking_assert (summary->m_ggc);
+  gt_pch_nx (&summary->m_map);
+}
+
+template <typename T>
+void
+gt_pch_nx (edge_summary<T *>* const& summary, gt_pointer_operator op,
+	  void *cookie)
+{
+  gcc_checking_assert (summary->m_ggc);
+  gt_pch_nx (&summary->m_map, op, cookie);
+}
+
+
 #endif  /* GCC_SYMBOL_SUMMARY_H  */