This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


On 07/10/2015 03:31 PM, Martin Jambor wrote:
> 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
> 

Hello.

This is v2 of the patch which reflects handy notes by Martin. I decided to separate method implementations
after their declarations. Apart from that, I decided to merge all changes in IPA inliner to a single patch.

Thanks,
Martin


>From ac97d6878c69ba89975ab19554e011d3427df194 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Thu, 9 Jul 2015 11:13:52 +0200
Subject: [PATCH 2/4] Introduce new edge_summary class and port IPA inliner.

gcc/ChangeLog:

2015-07-14  mliska  <mliska@suse.cz>

	* cgraph.c (symbol_table::create_edge): Fill up member of cgraph_edge.
	* cgraph.h (struct cgraph_edge): New member.
	* ipa-inline-analysis.c (redirect_to_unreachable): Use new function.
	(edge_set_predicate): Likewise.
	(evaluate_conditions_for_known_args): Likewise.
	(evaluate_properties_for_edge): Likewise.
	(inline_summary_alloc): Remove legacy symtab hooks holders.
	(reset_inline_edge_summary): Use new inline_edge_summary.
	(inline_summary_t::duplicate): Use newly added function.
	(inline_edge_summary_t::duplicate): Renamed from
	inline_edge_duplication_hook.
	(dump_inline_edge_summary): Fix coding style.
	(dump_inline_summary): Use new function get_or_insert.
	(compute_bb_predicates): Fix coding style.
	(estimate_function_body_sizes): Use newly added function.
	(compute_inline_parameters): Likewise.
	(estimate_edge_devirt_benefit): Likewise.
	(estimate_edge_size_and_time): Likewise.
	(estimate_calls_size_and_time): Likewise.
	(estimate_node_size_and_time): Likewise.
	(estimate_ipcp_clone_size_and_time): Likewise.
	(inline_update_callee_summaries): Fix coding style.
	(remap_edge_change_prob): Use newly added function.
	(remap_edge_summaries): Likewise.
	(inline_merge_summary): Likewise.
	(inline_update_overall_summary): Likewise.
	(simple_edge_hints): Likewise.
	(do_estimate_edge_time): Fix coding style.
	(estimate_time_after_inlining): Use newly added function.
	(estimate_size_after_inlining): Likewise.
	(estimate_growth): Likewise.
	(growth_likely_positive): Likewise.
	(inline_generate_summary): Fix coding style.
	(read_inline_edge_summary): Use newly added function.
	(inline_read_section): Likewise.
	(write_inline_edge_summary): Likewise.
	(inline_write_summary): Likewise.
	(inline_free_summary): Remove unused symtab hooks.
	* ipa-inline.c (caller_growth_limits): Use newly added function.
	(can_inline_edge_p): Likewise.
	(compute_uninlined_call_time): Likewise.
	(compute_inlined_call_time): Likewise.
	(big_speedup_p): Likewise.
	(want_inline_small_function_p): Likewise.
	(want_inline_self_recursive_call_p): Likewise.
	(edge_badness): Likewise.
	(update_caller_keys): Likewise.
	(update_callee_keys): Likewise.
	(recursive_inlining): Likewise.
	(inline_small_functions): Likewise.
	(inline_to_all_callers): Likewise.
	(dump_overall_stats): Likewise.
	(early_inline_small_functions): Likewise.
	(early_inliner): Likewise.
	* ipa-inline.h (get_inline_edge_summary): Likewise.
	(estimate_edge_growth): Likewise.
	* ipa-profile.c (ipa_propagate_frequency_1): Likewise.
	(ipa_profile): Likewise.
	* ipa-prop.c (ipa_print_node_jump_functions): Remove unused function.
	(ipa_make_edge_direct_to_target): Use newly added function.
	(ipa_propagate_indirect_call_infos): Change assert.
	(ipa_free_edge_args_substructures): Remove.
	(ipa_free_all_edge_args): Change to release newly added summary.
	(ipa_edge_args_t::create_ggc): New function.
	(ipa_edge_removal_hook): Remove.
	(ipa_edge_args_t::duplicate): New function.
	(ipa_register_cgraph_hooks): Remove usage of hooks.
	(ipa_unregister_cgraph_hooks): Likewise.
	* ipa-prop.h (ipa_check_create_edge_args): Use newly added summary.
	(ipa_edge_args_info_available_for_edge_p): Likewise.
	* ipa-split.c (execute_split_functions): Likewise.
	* ipa.c (symbol_table::remove_unreachable_nodes): Likewise.
	* symbol-summary.h (function_summary::function_summary): Move function
	implementation out of declaration.
	(function_summary::~function_summary): Likewise.
	(function_summary::release): Likewise.
	(function_summary::traverse): Likewise.
	(function_summary::allocate_new): Likewise.
	(function_summary::get): Likewise.
	(function_summary::get_or_insert): Likewise.
	(function_summary::elements): Likewise.
	(function_summary::enable_insertion_hook): Likewise.
	(function_summary::disable_insertion_hook): Likewise.
	(function_summary::symtab_insertion): Likewise.
	(function_summary::symtab_removal): Likewise.
	(function_summary::symtab_duplication): Likewise.
	(gt_ggc_mx): Likewise.
	(gt_pch_nx): Likewise.
	(edge_summary::edge_summary): New.
	(edge_summary::~edge_summary): Likewise.
	(edge_summary::release): Likewise.
	(edge_summary::traverse): Likewise.
	(edge_summary::allocate_new): Likewise.
	(edge_summary::get): Likewise.
	(edge_summary::get_or_insert): Likewise.
	(edge_summary::elements): Likewise.
	(edge_summary::symtab_removal): Likewise.
	(edge_summary::symtab_duplication): Likewise.
---
 gcc/cgraph.c              |   2 +
 gcc/cgraph.h              |   5 +-
 gcc/ipa-inline-analysis.c | 224 ++++++++--------
 gcc/ipa-inline.c          | 108 ++++----
 gcc/ipa-inline.h          |  28 +-
 gcc/ipa-profile.c         |   4 +-
 gcc/ipa-prop.c            |  84 ++----
 gcc/ipa-prop.h            |  41 +--
 gcc/ipa-split.c           |   3 +-
 gcc/ipa.c                 |   2 +-
 gcc/symbol-summary.h      | 631 ++++++++++++++++++++++++++++++++++++----------
 11 files changed, 736 insertions(+), 396 deletions(-)

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 22a9852..22cc5d9 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -852,6 +852,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 9476896..655f0f2 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..ed14661 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -129,17 +129,10 @@ enum predicate_conditions
    of executions even when they are not compile time constants.  */
 #define CHANGED IDENTIFIER_NODE
 
-/* Holders of ipa cgraph hooks: */
-static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
-static struct cgraph_edge_hook_list *edge_removal_hook_holder;
-static void inline_edge_removal_hook (struct cgraph_edge *, void *);
-static void inline_edge_duplication_hook (struct cgraph_edge *,
-					  struct cgraph_edge *, void *);
-
 /* VECtor holding inline summaries.  
    In GGC memory because conditions might point to constant trees.  */
 function_summary <inline_summary *> *inline_summaries;
-vec<inline_edge_summary_t> inline_edge_summary_vec;
+inline_edge_summary_t *inline_edge_summaries;
 
 /* Cached node/edge growths.  */
 vec<edge_growth_cache_entry> edge_growth_cache;
@@ -750,7 +743,7 @@ redirect_to_unreachable (struct cgraph_edge *e)
     e->make_direct (target);
   else
     e->redirect_callee (target);
-  struct inline_edge_summary *es = inline_edge_summary (e);
+  struct inline_edge_summary *es = get_inline_edge_summary (e);
   e->inline_failed = CIF_UNREACHABLE;
   e->frequency = 0;
   e->count = 0;
@@ -775,7 +768,7 @@ edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate)
       && (!e->speculative || e->callee))
     e = redirect_to_unreachable (e);
 
-  struct inline_edge_summary *es = inline_edge_summary (e);
+  struct inline_edge_summary *es = get_inline_edge_summary (e);
   if (predicate && !true_predicate_p (predicate))
     {
       if (!es->predicate)
@@ -825,7 +818,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
 				    known_aggs)
 {
   clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
-  struct inline_summary *info = inline_summaries->get (node);
+  struct inline_summary *info = inline_summaries->get_or_insert (node);
   int i;
   struct condition *c;
 
@@ -907,7 +900,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 			      vec<ipa_agg_jump_function_p> *known_aggs_ptr)
 {
   struct cgraph_node *callee = e->callee->ultimate_alias_target ();
-  struct inline_summary *info = inline_summaries->get (callee);
+  struct inline_summary *info = inline_summaries->get_or_insert (callee);
   vec<tree> known_vals = vNULL;
   vec<ipa_agg_jump_function_p> known_aggs = vNULL;
 
@@ -924,7 +917,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
     {
       struct ipa_node_params *parms_info;
       struct ipa_edge_args *args = IPA_EDGE_REF (e);
-      struct inline_edge_summary *es = inline_edge_summary (e);
+      struct inline_edge_summary *es = get_inline_edge_summary (e);
       int i, count = ipa_get_cs_argument_count (args);
 
       if (e->caller->global.inlined_to)
@@ -1007,18 +1000,11 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 static void
 inline_summary_alloc (void)
 {
-  if (!edge_removal_hook_holder)
-    edge_removal_hook_holder =
-      symtab->add_edge_removal_hook (&inline_edge_removal_hook, NULL);
-  if (!edge_duplication_hook_holder)
-    edge_duplication_hook_holder =
-      symtab->add_edge_duplication_hook (&inline_edge_duplication_hook, NULL);
+  if (!inline_edge_summaries)
+    inline_edge_summaries = new inline_edge_summary_t (symtab);
 
   if (!inline_summaries)
     inline_summaries = (inline_summary_t*) inline_summary_t::create_ggc (symtab);
-
-  if (inline_edge_summary_vec.length () <= (unsigned) symtab->edges_max_uid)
-    inline_edge_summary_vec.safe_grow_cleared (symtab->edges_max_uid + 1);
 }
 
 /* We are called multiple time for given function; clear
@@ -1027,9 +1013,9 @@ inline_summary_alloc (void)
 static void
 reset_inline_edge_summary (struct cgraph_edge *e)
 {
-  if (e->uid < (int) inline_edge_summary_vec.length ())
+  if (inline_edge_summaries)
     {
-      struct inline_edge_summary *es = inline_edge_summary (e);
+      struct inline_edge_summary *es = get_inline_edge_summary (e);
 
       es->call_stmt_size = es->call_stmt_time = 0;
       if (es->predicate)
@@ -1141,7 +1127,7 @@ inline_summary_t::duplicate (cgraph_node *src,
 			     inline_summary *info)
 {
   inline_summary_alloc ();
-  memcpy (info, inline_summaries->get (src), sizeof (inline_summary));
+  memcpy (info, inline_summaries->get_or_insert (src), sizeof (inline_summary));
   /* TODO: as an optimization, we may avoid copying conditions
      that are known to be false or true.  */
   info->conds = vec_safe_copy (info->conds);
@@ -1172,7 +1158,8 @@ inline_summary_t::duplicate (cgraph_node *src,
 	  for (j = 0; vec_safe_iterate (dst->clone.tree_map, j, &r); j++)
 	    {
 	      if (((!r->old_tree && r->parm_num == i)
-		   || (r->old_tree && r->old_tree == ipa_get_param (parms_info, i)))
+		   || (r->old_tree
+		       && r->old_tree == ipa_get_param (parms_info, i)))
 		   && r->replace_p && !r->ref_p)
 		{
 		  known_vals[i] = r->new_tree;
@@ -1209,7 +1196,7 @@ inline_summary_t::duplicate (cgraph_node *src,
       for (edge = dst->callees; edge; edge = next)
 	{
 	  struct predicate new_predicate;
-	  struct inline_edge_summary *es = inline_edge_summary (edge);
+	  struct inline_edge_summary *es = get_inline_edge_summary (edge);
 	  next = edge->next_callee;
 
 	  if (!edge->inline_failed)
@@ -1230,7 +1217,7 @@ inline_summary_t::duplicate (cgraph_node *src,
       for (edge = dst->indirect_calls; edge; edge = next)
 	{
 	  struct predicate new_predicate;
-	  struct inline_edge_summary *es = inline_edge_summary (edge);
+	  struct inline_edge_summary *es = get_inline_edge_summary (edge);
 	  next = edge->next_callee;
 
 	  gcc_checking_assert (edge->inline_failed);
@@ -1286,16 +1273,11 @@ inline_summary_t::duplicate (cgraph_node *src,
 
 /* Hook that is called by cgraph.c when a node is duplicated.  */
 
-static void
-inline_edge_duplication_hook (struct cgraph_edge *src,
-			      struct cgraph_edge *dst,
-			      ATTRIBUTE_UNUSED void *data)
+void
+inline_edge_summary_t::duplicate (cgraph_edge *src, cgraph_edge *dst,
+				  inline_edge_summary *srcinfo,
+				  inline_edge_summary *info)
 {
-  struct inline_edge_summary *info;
-  struct inline_edge_summary *srcinfo;
-  inline_summary_alloc ();
-  info = inline_edge_summary (dst);
-  srcinfo = inline_edge_summary (src);
   memcpy (info, srcinfo, sizeof (struct inline_edge_summary));
   info->predicate = NULL;
   edge_set_predicate (dst, srcinfo->predicate);
@@ -1312,9 +1294,9 @@ inline_edge_duplication_hook (struct cgraph_edge *src,
 
 /* Keep edge cache consistent across edge removal.  */
 
-static void
-inline_edge_removal_hook (struct cgraph_edge *edge,
-			  void *data ATTRIBUTE_UNUSED)
+void
+inline_edge_summary_t::remove (cgraph_edge *edge,
+			       inline_edge_summary *)
 {
   if (edge_growth_cache.exists ())
     reset_edge_growth_cache (edge);
@@ -1351,7 +1333,7 @@ dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node,
   struct cgraph_edge *edge;
   for (edge = node->callees; edge; edge = edge->next_callee)
     {
-      struct inline_edge_summary *es = inline_edge_summary (edge);
+      struct inline_edge_summary *es = get_inline_edge_summary (edge);
       struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
       int i;
 
@@ -1363,8 +1345,10 @@ dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node,
 	       ? "inlined" : cgraph_inline_failed_string (edge-> inline_failed),
 	       indent, "", es->loop_depth, edge->frequency,
 	       es->call_stmt_size, es->call_stmt_time,
-	       (int) inline_summaries->get (callee)->size / INLINE_SIZE_SCALE,
-	       (int) inline_summaries->get (callee)->estimated_stack_size);
+	       (int) inline_summaries->get_or_insert (callee)
+		 ->size / INLINE_SIZE_SCALE,
+	       (int) inline_summaries->get_or_insert (callee)
+		 ->estimated_stack_size);
 
       if (es->predicate)
 	{
@@ -1390,15 +1374,18 @@ dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node,
 	  fprintf (f, "%*sStack frame offset %i, callee self size %i,"
 		   " callee size %i\n",
 		   indent + 2, "",
-		   (int) inline_summaries->get (callee)->stack_frame_offset,
-		   (int) inline_summaries->get (callee)->estimated_self_stack_size,
-		   (int) inline_summaries->get (callee)->estimated_stack_size);
+		   (int) inline_summaries->get_or_insert (callee)
+		     ->stack_frame_offset,
+		   (int) inline_summaries->get_or_insert (callee)
+		     ->estimated_self_stack_size,
+		   (int) inline_summaries->get_or_insert (callee)
+		     ->estimated_stack_size);
 	  dump_inline_edge_summary (f, indent + 2, callee, info);
 	}
     }
   for (edge = node->indirect_calls; edge; edge = edge->next_callee)
     {
-      struct inline_edge_summary *es = inline_edge_summary (edge);
+      struct inline_edge_summary *es = get_inline_edge_summary (edge);
       fprintf (f, "%*sindirect call loop depth:%2i freq:%4i size:%2i"
 	       " time: %2i",
 	       indent, "",
@@ -1420,7 +1407,7 @@ dump_inline_summary (FILE *f, struct cgraph_node *node)
 {
   if (node->definition)
     {
-      struct inline_summary *s = inline_summaries->get (node);
+      struct inline_summary *s = inline_summaries->get_or_insert (node);
       size_time_entry *e;
       int i;
       fprintf (f, "Inline summary for %s/%i", node->name (),
@@ -1948,7 +1935,7 @@ compute_bb_predicates (struct cgraph_node *node,
 		  /* This OR operation is needed to ensure monotonous data flow
 		     in the case we hit the limit on number of clauses and the
 		     and/or operations above give approximate answers.  */
-		  p = or_predicates (summary->conds, &p, (struct predicate *)bb->aux);
+		  p = or_predicates (summary->conds, &p, (predicate *)bb->aux);
 	          if (!predicates_equal_p (&p, (struct predicate *) bb->aux))
 		    {
 		      done = false;
@@ -2321,7 +2308,8 @@ predicate_for_phi_result (struct inline_summary *summary, gphi *phi,
   nonconstant_names[SSA_NAME_VERSION (gimple_phi_result (phi))] = *p;
 }
 
-/* Return predicate specifying when array index in access OP becomes non-constant.  */
+/* Return predicate specifying when array index in access OP becomes
+   non-constant.  */
 
 static struct predicate
 array_index_predicate (inline_summary *info,
@@ -2479,7 +2467,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
   basic_block bb;
   struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
   int freq;
-  struct inline_summary *info = inline_summaries->get (node);
+  struct inline_summary *info = inline_summaries->get_or_insert (node);
   struct predicate bb_predicate;
   struct ipa_node_params *parms_info = NULL;
   vec<predicate_t> nonconstant_names = vNULL;
@@ -2644,7 +2632,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
 	      && !gimple_call_internal_p (stmt))
 	    {
 	      struct cgraph_edge *edge = node->get_edge (stmt);
-	      struct inline_edge_summary *es = inline_edge_summary (edge);
+	      struct inline_edge_summary *es = get_inline_edge_summary (edge);
 
 	      /* Special case: results of BUILT_IN_CONSTANT_P will be always
 	         resolved as constant.  We however don't want to optimize
@@ -2737,7 +2725,8 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
 	    }
 	}
     }
-  set_hint_predicate (&inline_summaries->get (node)->array_index, array_index);
+  set_hint_predicate (&inline_summaries->get_or_insert (node)->array_index,
+		      array_index);
   time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
   if (time > MAX_TIME)
     time = MAX_TIME;
@@ -2825,9 +2814,10 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
 	    }
 	  free (body);
 	}
-      set_hint_predicate (&inline_summaries->get (node)->loop_iterations,
-			  loop_iterations);
-      set_hint_predicate (&inline_summaries->get (node)->loop_stride, loop_stride);
+      set_hint_predicate (&inline_summaries->get_or_insert (node)
+			    ->loop_iterations, loop_iterations);
+      set_hint_predicate (&inline_summaries->get_or_insert (node)->loop_stride,
+			  loop_stride);
       scev_finalize ();
     }
   FOR_ALL_BB_FN (bb, my_function)
@@ -2845,14 +2835,14 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
 	  e->aux = NULL;
 	}
     }
-  inline_summaries->get (node)->self_time = time;
-  inline_summaries->get (node)->self_size = size;
+  inline_summaries->get_or_insert (node)->self_time = time;
+  inline_summaries->get_or_insert (node)->self_size = size;
   nonconstant_names.release ();
   if (opt_for_fn (node->decl, optimize))
     {
       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);
     }
@@ -2878,7 +2868,7 @@ compute_inline_parameters (struct cgraph_node *node, bool early)
 
   inline_summary_alloc ();
 
-  info = inline_summaries->get (node);
+  info = inline_summaries->get_or_insert (node);
   reset_inline_summary (node, info);
 
   /* FIXME: Thunks are inlinable, but tree-inline don't know how to do that.
@@ -2886,7 +2876,7 @@ compute_inline_parameters (struct cgraph_node *node, bool early)
      statement size.  */
   if (node->thunk.thunk_p)
     {
-      struct inline_edge_summary *es = inline_edge_summary (node->callees);
+      struct inline_edge_summary *es = get_inline_edge_summary (node->callees);
       struct predicate t = true_predicate ();
 
       info->inlinable = 0;
@@ -3049,7 +3039,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
   callee = callee->function_symbol (&avail);
   if (avail < AVAIL_AVAILABLE)
     return false;
-  isummary = inline_summaries->get (callee);
+  isummary = inline_summaries->get_or_insert (callee);
   return isummary->inlinable;
 }
 
@@ -3068,7 +3058,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size,
 			     vec<ipa_agg_jump_function_p> known_aggs,
 			     inline_hints *hints)
 {
-  struct inline_edge_summary *es = inline_edge_summary (e);
+  struct inline_edge_summary *es = get_inline_edge_summary (e);
   int call_size = es->call_stmt_size;
   int call_time = es->call_stmt_time;
   int cur_size;
@@ -3105,7 +3095,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size,
   struct cgraph_edge *e;
   for (e = node->callees; e; e = e->next_callee)
     {
-      struct inline_edge_summary *es = inline_edge_summary (e);
+      struct inline_edge_summary *es = get_inline_edge_summary (e);
 
       /* Do not care about zero sized builtins.  */
       if (e->inline_failed && !es->call_stmt_size)
@@ -3136,7 +3126,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size,
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
     {
-      struct inline_edge_summary *es = inline_edge_summary (e);
+      struct inline_edge_summary *es = get_inline_edge_summary (e);
       if (!es->predicate
 	  || evaluate_predicate (es->predicate, possible_truths))
 	estimate_edge_size_and_time (e, size,
@@ -3168,7 +3158,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
 			     vec<inline_param_summary>
 			     inline_param_summary)
 {
-  struct inline_summary *info = inline_summaries->get (node);
+  struct inline_summary *info = inline_summaries->get_or_insert (node);
   size_time_entry *e;
   int size = 0;
   int time = 0;
@@ -3237,8 +3227,9 @@ estimate_node_size_and_time (struct cgraph_node *node,
   if (DECL_DECLARED_INLINE_P (node->decl))
     hints |= INLINE_HINT_declared_inline;
 
-  estimate_calls_size_and_time (node, &size, &min_size, &time, &hints, possible_truths,
-				known_vals, known_contexts, known_aggs);
+  estimate_calls_size_and_time (node, &size, &min_size, &time, &hints,
+				possible_truths, known_vals, known_contexts,
+				known_aggs);
   gcc_checking_assert (size >= 0);
   gcc_checking_assert (time >= 0);
   time = RDIV (time, INLINE_TIME_SCALE);
@@ -3278,7 +3269,8 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
   clause = evaluate_conditions_for_known_args (node, false, known_vals,
 					       known_aggs);
   estimate_node_size_and_time (node, clause, known_vals, known_contexts,
-			       known_aggs, ret_size, NULL, ret_time, hints, vNULL);
+			       known_aggs, ret_size, NULL, ret_time, hints,
+			       vNULL);
 }
 
 /* Translate all conditions from callee representation into caller
@@ -3384,9 +3376,10 @@ remap_predicate (struct inline_summary *info,
 static void
 inline_update_callee_summaries (struct cgraph_node *node, int depth)
 {
-  struct cgraph_edge *e;
-  struct inline_summary *callee_info = inline_summaries->get (node);
-  struct inline_summary *caller_info = inline_summaries->get (node->callers->caller);
+  cgraph_edge *e;
+  inline_summary *callee_info = inline_summaries->get_or_insert (node);
+  inline_summary *caller_info = inline_summaries->get_or_insert
+    (node->callers->caller);
   HOST_WIDE_INT peak;
 
   callee_info->stack_frame_offset
@@ -3394,17 +3387,19 @@ inline_update_callee_summaries (struct cgraph_node *node, int depth)
     + caller_info->estimated_self_stack_size;
   peak = callee_info->stack_frame_offset
     + callee_info->estimated_self_stack_size;
-  if (inline_summaries->get (node->global.inlined_to)->estimated_stack_size < peak)
-      inline_summaries->get (node->global.inlined_to)->estimated_stack_size = peak;
+  if (inline_summaries->get_or_insert
+	(node->global.inlined_to)->estimated_stack_size < peak)
+      inline_summaries->get_or_insert
+	(node->global.inlined_to)->estimated_stack_size = peak;
   ipa_propagate_frequency (node);
   for (e = node->callees; e; e = e->next_callee)
     {
       if (!e->inline_failed)
 	inline_update_callee_summaries (e->callee, depth);
-      inline_edge_summary (e)->loop_depth += depth;
+      get_inline_edge_summary (e)->loop_depth += depth;
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
-    inline_edge_summary (e)->loop_depth += depth;
+    get_inline_edge_summary (e)->loop_depth += depth;
 }
 
 /* Update change_prob of EDGE after INLINED_EDGE has been inlined.
@@ -3421,9 +3416,9 @@ remap_edge_change_prob (struct cgraph_edge *inlined_edge,
     {
       int i;
       struct ipa_edge_args *args = IPA_EDGE_REF (edge);
-      struct inline_edge_summary *es = inline_edge_summary (edge);
+      struct inline_edge_summary *es = get_inline_edge_summary (edge);
       struct inline_edge_summary *inlined_es
-	= inline_edge_summary (inlined_edge);
+	= get_inline_edge_summary (inlined_edge);
 
       for (i = 0; i < ipa_get_cs_argument_count (args); i++)
 	{
@@ -3466,7 +3461,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
   struct cgraph_edge *e, *next;
   for (e = node->callees; e; e = next)
     {
-      struct inline_edge_summary *es = inline_edge_summary (e);
+      struct inline_edge_summary *es = get_inline_edge_summary (e);
       struct predicate p;
       next = e->next_callee;
 
@@ -3491,7 +3486,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
     }
   for (e = node->indirect_calls; e; e = next)
     {
-      struct inline_edge_summary *es = inline_edge_summary (e);
+      struct inline_edge_summary *es = get_inline_edge_summary (e);
       struct predicate p;
       next = e->next_callee;
 
@@ -3541,10 +3536,10 @@ remap_hint_predicate (struct inline_summary *info,
 void
 inline_merge_summary (struct cgraph_edge *edge)
 {
-  struct inline_summary *callee_info = inline_summaries->get (edge->callee);
+  inline_summary *callee_info = inline_summaries->get_or_insert (edge->callee);
   struct cgraph_node *to = (edge->caller->global.inlined_to
 			    ? edge->caller->global.inlined_to : edge->caller);
-  struct inline_summary *info = inline_summaries->get (to);
+  struct inline_summary *info = inline_summaries->get_or_insert (to);
   clause_t clause = 0;		/* not_inline is known to be false.  */
   size_time_entry *e;
   vec<int> operand_map = vNULL;
@@ -3552,7 +3547,7 @@ inline_merge_summary (struct cgraph_edge *edge)
   int i;
   struct predicate toplev_predicate;
   struct predicate true_p = true_predicate ();
-  struct inline_edge_summary *es = inline_edge_summary (edge);
+  struct inline_edge_summary *es = get_inline_edge_summary (edge);
 
   if (es->predicate)
     toplev_predicate = *es->predicate;
@@ -3638,7 +3633,7 @@ inline_merge_summary (struct cgraph_edge *edge)
 			operand_map, offset_map, clause, &toplev_predicate);
 
   inline_update_callee_summaries (edge->callee,
-				  inline_edge_summary (edge)->loop_depth);
+				  get_inline_edge_summary (edge)->loop_depth);
 
   /* We do not maintain predicates of inlined edges, free it.  */
   edge_set_predicate (edge, &true_p);
@@ -3654,7 +3649,7 @@ inline_merge_summary (struct cgraph_edge *edge)
 void
 inline_update_overall_summary (struct cgraph_node *node)
 {
-  struct inline_summary *info = inline_summaries->get (node);
+  struct inline_summary *info = inline_summaries->get_or_insert (node);
   size_time_entry *e;
   int i;
 
@@ -3682,9 +3677,9 @@ simple_edge_hints (struct cgraph_edge *edge)
   struct cgraph_node *to = (edge->caller->global.inlined_to
 			    ? edge->caller->global.inlined_to : edge->caller);
   struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
-  if (inline_summaries->get (to)->scc_no
-      && inline_summaries->get (to)->scc_no
-	 == inline_summaries->get (callee)->scc_no
+  if (inline_summaries->get_or_insert (to)->scc_no
+      && inline_summaries->get_or_insert (to)->scc_no
+	 == inline_summaries->get_or_insert (callee)->scc_no
       && !edge->recursive_p ())
     hints |= INLINE_HINT_same_scc;
 
@@ -3714,7 +3709,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
   vec<tree> known_vals;
   vec<ipa_polymorphic_call_context> known_contexts;
   vec<ipa_agg_jump_function_p> known_aggs;
-  struct inline_edge_summary *es = inline_edge_summary (edge);
+  struct inline_edge_summary *es = get_inline_edge_summary (edge);
   int min_size;
 
   callee = edge->callee->ultimate_alias_target ();
@@ -3724,7 +3719,8 @@ do_estimate_edge_time (struct cgraph_edge *edge)
 				&clause, &known_vals, &known_contexts,
 				&known_aggs);
   estimate_node_size_and_time (callee, clause, known_vals, known_contexts,
-			       known_aggs, &size, &min_size, &time, &hints, es->param);
+			       known_aggs, &size, &min_size, &time, &hints,
+			       es->param);
 
   /* When we have profile feedback, we can quite safely identify hot
      edges and for those we disable size limits.  Don't do that when
@@ -3745,7 +3741,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
   /* When caching, update the cache entry.  */
   if (edge_growth_cache.exists ())
     {
-      inline_summaries->get (edge->callee)->min_size = min_size;
+      inline_summaries->get_or_insert (edge->callee)->min_size = min_size;
       if ((int) edge_growth_cache.length () <= edge->uid)
 	edge_growth_cache.safe_grow_cleared (symtab->edges_max_uid);
       edge_growth_cache[edge->uid].time = time + (time >= 0);
@@ -3843,18 +3839,19 @@ int
 estimate_time_after_inlining (struct cgraph_node *node,
 			      struct cgraph_edge *edge)
 {
-  struct inline_edge_summary *es = inline_edge_summary (edge);
+  struct inline_edge_summary *es = get_inline_edge_summary (edge);
   if (!es->predicate || !false_predicate_p (es->predicate))
     {
       gcov_type time =
-	inline_summaries->get (node)->time + estimate_edge_time (edge);
+	inline_summaries->get_or_insert (node)->time
+	+ estimate_edge_time (edge);
       if (time < 0)
 	time = 0;
       if (time > MAX_TIME)
 	time = MAX_TIME;
       return time;
     }
-  return inline_summaries->get (node)->time;
+  return inline_summaries->get_or_insert (node)->time;
 }
 
 
@@ -3865,14 +3862,15 @@ int
 estimate_size_after_inlining (struct cgraph_node *node,
 			      struct cgraph_edge *edge)
 {
-  struct inline_edge_summary *es = inline_edge_summary (edge);
+  struct inline_edge_summary *es = get_inline_edge_summary (edge);
   if (!es->predicate || !false_predicate_p (es->predicate))
     {
-      int size = inline_summaries->get (node)->size + estimate_edge_growth (edge);
+      int size = inline_summaries->get_or_insert (node)->size
+	+ estimate_edge_growth (edge);
       gcc_assert (size >= 0);
       return size;
     }
-  return inline_summaries->get (node)->size;
+  return inline_summaries->get_or_insert (node)->size;
 }
 
 
@@ -3920,7 +3918,7 @@ int
 estimate_growth (struct cgraph_node *node)
 {
   struct growth_data d = { node, false, false, 0 };
-  struct inline_summary *info = inline_summaries->get (node);
+  struct inline_summary *info = inline_summaries->get_or_insert (node);
 
   node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true);
 
@@ -3995,7 +3993,8 @@ growth_likely_positive (struct cgraph_node *node,
       || node->address_taken)
     return true;
 
-  max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2;
+  max_callers = inline_summaries->get_or_insert (node)->size * 4
+    / edge_growth + 2;
 
   for (e = node->callers; e; e = e->next_caller)
     {
@@ -4100,7 +4099,8 @@ inline_generate_summary (void)
     return;
 
   if (!inline_summaries)
-    inline_summaries = (inline_summary_t*) inline_summary_t::create_ggc (symtab);
+    inline_summaries = (inline_summary_t *) inline_summary_t::create_ggc
+      (symtab);
 
   inline_summaries->enable_insertion_hook ();
 
@@ -4142,7 +4142,7 @@ read_predicate (struct lto_input_block *ib)
 static void
 read_inline_edge_summary (struct lto_input_block *ib, struct cgraph_edge *e)
 {
-  struct inline_edge_summary *es = inline_edge_summary (e);
+  struct inline_edge_summary *es = get_inline_edge_summary (e);
   struct predicate p;
   int length, i;
 
@@ -4197,7 +4197,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
       encoder = file_data->symtab_node_encoder;
       node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
 								index));
-      info = inline_summaries->get (node);
+      info = inline_summaries->get_or_insert (node);
 
       info->estimated_stack_size
 	= info->estimated_self_stack_size = streamer_read_uhwi (&ib);
@@ -4315,7 +4315,7 @@ write_predicate (struct output_block *ob, struct predicate *p)
 static void
 write_inline_edge_summary (struct output_block *ob, struct cgraph_edge *e)
 {
-  struct inline_edge_summary *es = inline_edge_summary (e);
+  struct inline_edge_summary *es = get_inline_edge_summary (e);
   int i;
 
   streamer_write_uhwi (ob, es->call_stmt_size);
@@ -4356,7 +4356,7 @@ inline_write_summary (void)
       cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
       if (cnode && (node = cnode)->definition && !node->alias)
 	{
-	  struct inline_summary *info = inline_summaries->get (node);
+	  struct inline_summary *info = inline_summaries->get_or_insert (node);
 	  struct bitpack_d bp;
 	  struct cgraph_edge *edge;
 	  int i;
@@ -4411,26 +4411,22 @@ inline_write_summary (void)
     ipa_prop_write_jump_functions ();
 }
 
-
 /* Release inline summary.  */
 
 void
 inline_free_summary (void)
 {
   struct cgraph_node *node;
-  if (edge_removal_hook_holder)
-    symtab->remove_edge_removal_hook (edge_removal_hook_holder);
-  edge_removal_hook_holder = NULL;
-  if (edge_duplication_hook_holder)
-    symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
-  edge_duplication_hook_holder = NULL;
-  if (!inline_edge_summary_vec.exists ())
+  if (inline_edge_summaries == NULL)
     return;
   FOR_EACH_DEFINED_FUNCTION (node)
     if (!node->alias)
-      reset_inline_summary (node, inline_summaries->get (node));
+      reset_inline_summary (node, inline_summaries->get_or_insert (node));
+
+  delete inline_edge_summaries;
+  inline_edge_summaries = NULL;
+
   inline_summaries->release ();
   inline_summaries = NULL;
-  inline_edge_summary_vec.release ();
   edge_predicate_pool.release ();
 }
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index f836df6..bf0b155 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -158,7 +158,8 @@ caller_growth_limits (struct cgraph_edge *e)
   int newsize;
   int limit = 0;
   HOST_WIDE_INT stack_size_limit = 0, inlined_stack;
-  inline_summary *info, *what_info, *outer_info = inline_summaries->get (to);
+  inline_summary *info, *what_info;
+  inline_summary *outer_info = inline_summaries->get_or_insert (to);
 
   /* Look for function e->caller is inlined to.  While doing
      so work out the largest function body on the way.  As
@@ -170,7 +171,7 @@ caller_growth_limits (struct cgraph_edge *e)
      too much in order to prevent compiler from exploding".  */
   while (true)
     {
-      info = inline_summaries->get (to);
+      info = inline_summaries->get_or_insert (to);
       if (limit < info->self_size)
 	limit = info->self_size;
       if (stack_size_limit < info->estimated_self_stack_size)
@@ -181,7 +182,7 @@ caller_growth_limits (struct cgraph_edge *e)
 	break;
     }
 
-  what_info = inline_summaries->get (what);
+  what_info = inline_summaries->get_or_insert (what);
 
   if (limit < what_info->self_size)
     limit = what_info->self_size;
@@ -374,12 +375,12 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
       e->inline_failed = CIF_TARGET_OPTION_MISMATCH;
       inlinable = false;
     }
-  else if (!inline_summaries->get (callee)->inlinable)
+  else if (!inline_summaries->get_or_insert (callee)->inlinable)
     {
       e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
       inlinable = false;
     }
-  else if (inline_summaries->get (caller)->contains_cilk_spawn)
+  else if (inline_summaries->get_or_insert (caller)->contains_cilk_spawn)
     {
       e->inline_failed = CIF_CILK_SPAWN;
       inlinable = false;
@@ -515,7 +516,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
 		   > opt_for_fn (caller->decl, optimize)))
 	{
 	  if (estimate_edge_time (e)
-	      >= 20 + inline_edge_summary (e)->call_stmt_time)
+	      >= 20 + get_inline_edge_summary (e)->call_stmt_time)
 	    {
 	      e->inline_failed = CIF_OPTIMIZATION_MISMATCH;
 	      inlinable = false;
@@ -667,7 +668,7 @@ compute_uninlined_call_time (struct inline_summary *callee_info,
   else
     uninlined_call_time = uninlined_call_time >> 11;
 
-  int caller_time = inline_summaries->get (caller)->time;
+  int caller_time = inline_summaries->get_or_insert (caller)->time;
   return uninlined_call_time + caller_time;
 }
 
@@ -681,7 +682,7 @@ compute_inlined_call_time (struct cgraph_edge *edge,
   cgraph_node *caller = (edge->caller->global.inlined_to 
 			 ? edge->caller->global.inlined_to
 			 : edge->caller);
-  int caller_time = inline_summaries->get (caller)->time;
+  int caller_time = inline_summaries->get_or_insert (caller)->time;
   sreal time = edge_time;
 
   if (edge->count && caller->count)
@@ -695,7 +696,7 @@ compute_inlined_call_time (struct cgraph_edge *edge,
      FIXME: Once ipa-inline-analysis is converted to sreal this can be
      simplified.  */
   time -= (sreal) ((gcov_type) edge->frequency
-		   * inline_edge_summary (edge)->call_stmt_time
+		   * get_inline_edge_summary (edge)->call_stmt_time
 	           * (INLINE_TIME_SCALE / CGRAPH_FREQ_BASE)) / INLINE_TIME_SCALE;
   time += caller_time;
   if (time <= 0)
@@ -710,8 +711,8 @@ compute_inlined_call_time (struct cgraph_edge *edge,
 static bool
 big_speedup_p (struct cgraph_edge *e)
 {
-  sreal time = compute_uninlined_call_time (inline_summaries->get (e->callee),
-					    e);
+  sreal time = compute_uninlined_call_time
+    (inline_summaries->get_or_insert (e->callee), e);
   sreal inlined_time = compute_inlined_call_time (e, estimate_edge_time (e));
 
   if (time - inlined_time
@@ -744,16 +745,16 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
      MAX_INLINE_INSNS_SINGLE 16-fold for inline functions.  */
   else if ((!DECL_DECLARED_INLINE_P (callee->decl)
 	   && (!e->count || !e->maybe_hot_p ()))
-	   && inline_summaries->get (callee)->min_size
-		- inline_edge_summary (e)->call_stmt_size
+	   && inline_summaries->get_or_insert (callee)->min_size
+		- get_inline_edge_summary (e)->call_stmt_size
 	      > MAX (MAX_INLINE_INSNS_SINGLE, MAX_INLINE_INSNS_AUTO))
     {
       e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
       want_inline = false;
     }
   else if ((DECL_DECLARED_INLINE_P (callee->decl) || e->count)
-	   && inline_summaries->get (callee)->min_size
-		- inline_edge_summary (e)->call_stmt_size
+	   && inline_summaries->get_or_insert (callee)->min_size
+		- get_inline_edge_summary (e)->call_stmt_size
 	      > 16 * MAX_INLINE_INSNS_SINGLE)
     {
       e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl)
@@ -883,8 +884,8 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge,
 
   if (!want_inline)
     ;
-  /* Inlining of self recursive function into copy of itself within other function
-     is transformation similar to loop peeling.
+  /* Inlining of self recursive function into copy of itself within other
+     function is transformation similar to loop peeling.
 
      Peeling is profitable if we can inline enough copies to make probability
      of actual call to the self recursive function very small.  Be sure that
@@ -914,9 +915,9 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge,
 	  want_inline = false;
 	}
     }
-  /* Recursive inlining, i.e. equivalent of unrolling, is profitable if recursion
-     depth is large.  We reduce function call overhead and increase chances that
-     things fit in hardware return predictor.
+  /* Recursive inlining, i.e. equivalent of unrolling, is profitable if
+     recursion depth is large.  We reduce function call overhead and increase
+     chances that things fit in hardware return predictor.
 
      Recursive inlining might however increase cost of stack frame setup
      actually slowing down functions whose recursion tree is wide rather than
@@ -926,10 +927,10 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge,
      is tricky.  For now we disable recursive inlining when probability of self
      recursion is low. 
 
-     Recursive inlining of self recursive call within loop also results in large loop
-     depths that generally optimize badly.  We may want to throttle down inlining
-     in those cases.  In particular this seems to happen in one of libstdc++ rb tree
-     methods.  */
+     Recursive inlining of self recursive call within loop also results in large
+     loop depths that generally optimize badly.  We may want to throttle down
+     inlining in those cases.  In particular this seems to happen in one
+     of libstdc++ rb tree methods.  */
   else
     {
       if (max_count
@@ -1026,7 +1027,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
   sreal badness;
   int growth, edge_time;
   struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
-  struct inline_summary *callee_info = inline_summaries->get (callee);
+  struct inline_summary *callee_info = inline_summaries->get_or_insert (callee);
   inline_hints hints;
   cgraph_node *caller = (edge->caller->global.inlined_to 
 			 ? edge->caller->global.inlined_to
@@ -1134,7 +1135,8 @@ edge_badness (struct cgraph_edge *edge, bool dump)
 		  && (!DECL_DECLARED_INLINE_P (edge->callee->decl)
 		      || DECL_DECLARED_INLINE_P (caller->decl)))))
 	{
-	  struct inline_summary *caller_info = inline_summaries->get (caller);
+	  inline_summary *caller_info =
+	    inline_summaries->get_or_insert (caller);
 	  int caller_growth = caller_info->growth;
 
 	  /* Only apply the penalty when caller looks like inline candidate,
@@ -1164,7 +1166,8 @@ edge_badness (struct cgraph_edge *edge, bool dump)
 	    overall_growth += 256 * 256 - 256;
 	  denominator *= overall_growth;
         }
-      denominator *= inline_summaries->get (caller)->self_size + growth;
+      denominator *= inline_summaries->get_or_insert (caller)->self_size
+	+ growth;
 
       badness = - numerator / denominator;
 
@@ -1191,7 +1194,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
      of functions fully inlined in program.  */
   else
     {
-      int nest = MIN (inline_edge_summary (edge)->loop_depth, 8);
+      int nest = MIN (get_inline_edge_summary (edge)->loop_depth, 8);
       badness = growth;
 
       /* Decrease badness if call is nested.  */
@@ -1339,7 +1342,7 @@ update_caller_keys (edge_heap_t *heap, struct cgraph_node *node,
   struct cgraph_edge *edge;
   struct ipa_ref *ref;
 
-  if ((!node->alias && !inline_summaries->get (node)->inlinable)
+  if ((!node->alias && !inline_summaries->get_or_insert (node)->inlinable)
       || node->global.inlined_to)
     return;
   if (!bitmap_set_bit (updated_nodes, node->uid))
@@ -1397,7 +1400,7 @@ update_callee_keys (edge_heap_t *heap, struct cgraph_node *node,
            don't need updating.  */
 	if (e->inline_failed
 	    && (callee = e->callee->ultimate_alias_target (&avail))
-	    && inline_summaries->get (callee)->inlinable
+	    && inline_summaries->get_or_insert (callee)->inlinable
 	    && avail >= AVAIL_AVAILABLE
 	    && !bitmap_bit_p (updated_nodes, callee->uid))
 	  {
@@ -1568,8 +1571,10 @@ recursive_inlining (struct cgraph_edge *edge,
     fprintf (dump_file,
 	     "\n   Inlined %i times, "
 	     "body grown from size %i to %i, time %i to %i\n", n,
-	     inline_summaries->get (master_clone)->size, inline_summaries->get (node)->size,
-	     inline_summaries->get (master_clone)->time, inline_summaries->get (node)->time);
+	     inline_summaries->get_or_insert (master_clone)->size,
+	     inline_summaries->get_or_insert (node)->size,
+	     inline_summaries->get_or_insert (master_clone)->time,
+	     inline_summaries->get_or_insert (node)->time);
 
   /* Remove master clone we used for inlining.  We rely that clones inlined
      into master clone gets queued just before master clone so we don't
@@ -1766,11 +1771,12 @@ inline_small_functions (void)
 	if (!node->alias && node->analyzed
 	    && (node->has_gimple_body_p () || node->thunk.thunk_p))
 	  {
-	    struct inline_summary *info = inline_summaries->get (node);
-	    struct ipa_dfs_info *dfs = (struct ipa_dfs_info *) node->aux;
+	    inline_summary *info = inline_summaries->get_or_insert (node);
+	    ipa_dfs_info *dfs = (struct ipa_dfs_info *) node->aux;
 
 	    /* Do not account external functions, they will be optimized out
-	       if not inlined.  Also only count the non-cold portion of program.  */
+	       if not inlined.  Also only count the non-cold portion
+	       of program.  */
 	    if (inline_account_function_p (node))
 	      initial_size += info->size;
 	    info->growth = estimate_growth (node);
@@ -1787,7 +1793,8 @@ inline_small_functions (void)
 		for (n2 = node; n2;
 		     n2 = ((struct ipa_dfs_info *) node->aux)->next_cycle)
 		  {
-		    struct inline_summary *info2 = inline_summaries->get (n2);
+		    inline_summary *info2 =
+		      inline_summaries->get_or_insert (n2);
 		    if (info2->scc_no)
 		      break;
 		    info2->scc_no = id;
@@ -1804,8 +1811,8 @@ inline_small_functions (void)
 
   if (dump_file)
     fprintf (dump_file,
-	     "\nDeciding on inlining of small functions.  Starting with size %i.\n",
-	     initial_size);
+	     "\nDeciding on inlining of small functions.  "
+	     "Starting with size %i.\n", initial_size);
 
   overall_size = initial_size;
   max_size = compute_max_insns (overall_size);
@@ -1937,7 +1944,7 @@ inline_small_functions (void)
 	  fprintf (dump_file,
 		   "\nConsidering %s/%i with %i size\n",
 		   callee->name (), callee->order,
-		   inline_summaries->get (callee)->size);
+		   inline_summaries->get_or_insert (callee)->size);
 	  fprintf (dump_file,
 		   " to be inlined into %s/%i in %s:%i\n"
 		   " Estimated badness is %f, frequency %.2f.\n",
@@ -2067,8 +2074,8 @@ inline_small_functions (void)
 		   " Inlined into %s which now has time %i and size %i,"
 		   "net change of %+i.\n",
 		   edge->caller->name (),
-		   inline_summaries->get (edge->caller)->time,
-		   inline_summaries->get (edge->caller)->size,
+		   inline_summaries->get_or_insert (edge->caller)->time,
+		   inline_summaries->get_or_insert (edge->caller)->size,
 		   overall_size - old_size);
 	}
       if (min_size > overall_size)
@@ -2200,11 +2207,12 @@ inline_to_all_callers (struct cgraph_node *node, void *data)
 	  fprintf (dump_file,
 		   "\nInlining %s size %i.\n",
 		   node->name (),
-		   inline_summaries->get (node)->size);
+		   inline_summaries->get_or_insert (node)->size);
 	  fprintf (dump_file,
 		   " Called once from %s %i insns.\n",
 		   node->callers->caller->name (),
-		   inline_summaries->get (node->callers->caller)->size);
+		   inline_summaries->get_or_insert
+		     (node->callers->caller)->size);
 	}
 
       inline_call (node->callers, true, NULL, NULL, true, &callee_removed);
@@ -2212,7 +2220,7 @@ inline_to_all_callers (struct cgraph_node *node, void *data)
 	fprintf (dump_file,
 		 " Inlined into %s which now has %i size\n",
 		 caller->name (),
-		 inline_summaries->get (caller)->size);
+		 inline_summaries->get_or_insert (caller)->size);
       if (!(*num_calls)--)
 	{
 	  if (dump_file)
@@ -2236,7 +2244,7 @@ dump_overall_stats (void)
     if (!node->global.inlined_to
 	&& !node->alias)
       {
-	int time = inline_summaries->get (node)->time;
+	int time = inline_summaries->get_or_insert (node)->time;
 	sum += time;
 	sum_weighted += time * node->count;
       }
@@ -2573,7 +2581,7 @@ early_inline_small_functions (struct cgraph_node *node)
   for (e = node->callees; e; e = e->next_callee)
     {
       struct cgraph_node *callee = e->callee->ultimate_alias_target ();
-      if (!inline_summaries->get (callee)->inlinable
+      if (!inline_summaries->get_or_insert (callee)->inlinable
 	  || !e->inline_failed)
 	continue;
 
@@ -2688,9 +2696,9 @@ early_inliner (function *fun)
 	     statements that don't have inline parameters computed.  */
 	  for (edge = node->callees; edge; edge = edge->next_callee)
 	    {
-	      if (inline_edge_summary_vec.length () > (unsigned) edge->uid)
+	      if (inline_edge_summaries)
 		{
-		  struct inline_edge_summary *es = inline_edge_summary (edge);
+		  inline_edge_summary *es = get_inline_edge_summary (edge);
 		  es->call_stmt_size
 		    = estimate_num_insns (edge->call_stmt, &eni_size_weights);
 		  es->call_stmt_time
@@ -2716,9 +2724,9 @@ early_inliner (function *fun)
 	  for (edge = node->callees; edge; edge = edge->next_callee)
 	    {
 	      /* We have no summary for new bound store calls yet.  */
-	      if (inline_edge_summary_vec.length () > (unsigned)edge->uid)
+	      if (inline_edge_summaries)
 		{
-		  struct inline_edge_summary *es = inline_edge_summary (edge);
+		  inline_edge_summary *es = get_inline_edge_summary (edge);
 		  es->call_stmt_size
 		    = estimate_num_insns (edge->call_stmt, &eni_size_weights);
 		  es->call_stmt_time
diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h
index 85041f6..242b0f3 100644
--- a/gcc/ipa-inline.h
+++ b/gcc/ipa-inline.h
@@ -219,10 +219,20 @@ struct inline_edge_summary
   vec<inline_param_summary> param;
 };
 
-/* Need a typedef for inline_edge_summary because of inline function
-   'inline_edge_summary' below.  */
-typedef struct inline_edge_summary inline_edge_summary_t;
-extern vec<inline_edge_summary_t> inline_edge_summary_vec;
+class GTY((user)) inline_edge_summary_t:
+  public edge_summary <inline_edge_summary *>
+{
+public:
+  inline_edge_summary_t (symbol_table *symtab):
+    edge_summary <inline_edge_summary *> (symtab) {}
+
+  virtual void remove (cgraph_edge *edge, inline_edge_summary *s);
+  virtual void duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge,
+			  inline_edge_summary *src_data,
+			  inline_edge_summary *dst_data);
+};
+
+extern inline_edge_summary_t *inline_edge_summaries;
 
 struct edge_growth_cache_entry
 {
@@ -275,10 +285,10 @@ void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *,
 extern int ncalls_inlined;
 extern int nfunctions_inlined;
 
-static inline struct inline_edge_summary *
-inline_edge_summary (struct cgraph_edge *edge)
+static inline inline_edge_summary *
+get_inline_edge_summary (cgraph_edge *edge)
 {
-  return &inline_edge_summary_vec[edge->uid];
+  return inline_edge_summaries->get_or_insert (edge);
 }
 
 
@@ -300,11 +310,11 @@ static inline int
 estimate_edge_growth (struct cgraph_edge *edge)
 {
 #ifdef ENABLE_CHECKING
-  gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size
+  gcc_checking_assert (get_inline_edge_summary (edge)->call_stmt_size
 		       || !edge->callee->analyzed);
 #endif
   return (estimate_edge_size (edge)
-	  - inline_edge_summary (edge)->call_stmt_size);
+	  - get_inline_edge_summary (edge)->call_stmt_size);
 }
 
 /* Return estimated callee runtime increase after inlning
diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c
index 8291266..d30a08f 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -356,7 +356,7 @@ ipa_propagate_frequency_1 (struct cgraph_node *node, void *data)
 	    fprintf (dump_file, "  Called by %s that is executed once\n",
 		     edge->caller->name ());
 	  d->maybe_unlikely_executed = false;
-	  if (inline_edge_summary (edge)->loop_depth)
+	  if (get_inline_edge_summary (edge)->loop_depth)
 	    {
 	      d->maybe_executed_once = false;
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -628,7 +628,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 29178d4..a87e2d3 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)
@@ -2585,7 +2578,7 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
 				bool speculative)
 {
   struct cgraph_node *callee;
-  struct inline_edge_summary *es = inline_edge_summary (ie);
+  struct inline_edge_summary *es = get_inline_edge_summary (ie);
   bool unreachable = false;
 
   if (TREE_CODE (target) == ADDR_EXPR)
@@ -2734,7 +2727,7 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
 	 for direct call (adjusted by inline_edge_duplication_hook).  */
       if (ie == orig)
 	{
-	  es = inline_edge_summary (ie);
+	  es = get_inline_edge_summary (ie);
 	  es->call_stmt_size -= (eni_size_weights.indirect_call_cost
 				 - eni_size_weights.call_cost);
 	  es->call_stmt_time -= (eni_time_weights.indirect_call_cost
@@ -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,31 +3331,16 @@ 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
 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 +3392,17 @@ 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)
+ipa_edge_args_t *
+ipa_edge_args_t::create_ggc (symbol_table *symtab)
 {
-  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;
+  ipa_edge_args_t *summary = new (ggc_cleared_alloc <ipa_edge_args_t> ())
+    ipa_edge_args_t (symtab);
+  return summary;
+}
 
-  args = IPA_EDGE_REF (cs);
+void
+ipa_edge_args_t::remove (cgraph_edge *edge, ipa_edge_args *args)
+{
   if (args->jump_functions)
     {
       struct ipa_jump_func *jf;
@@ -3436,28 +3413,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 +3575,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 +3584,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 c495894..53c49db 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -493,13 +493,31 @@ 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);
+
+  /* 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_NODE_REF(NODE) (ipa_node_params_sum->get_or_insert (NODE))
+#define IPA_EDGE_REF(EDGE) (ipa_edge_args_sum->get_or_insert (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 +550,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/ipa-split.c b/gcc/ipa-split.c
index 69f293f..245caca 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1699,8 +1699,7 @@ execute_split_functions (void)
     }
   /* This can be relaxed; function might become inlinable after splitting
      away the uninlinable part.  */
-  if (inline_edge_summary_vec.exists ()
-      && !inline_summaries->get (node)->inlinable)
+  if (inline_edge_summaries && !inline_summaries->get (node)->inlinable)
     {
       if (dump_file)
 	fprintf (dump_file, "Not splitting: not inlinable.\n");
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 75e367f..46fe636 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -683,7 +683,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
 #endif
 
   /* If we removed something, perhaps profile could be improved.  */
-  if (changed && optimize && inline_edge_summary_vec.exists ())
+  if (changed && optimize && inline_edge_summaries)
     FOR_EACH_DEFINED_FUNCTION (node)
       ipa_propagate_frequency (node);
 
diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
index eefbfd9..3e8b24e 100644
--- a/gcc/symbol-summary.h
+++ b/gcc/symbol-summary.h
@@ -31,70 +31,34 @@ private:
   function_summary();
 };
 
+/* Function summary is a helper class that is used to associate a data structure
+   related to a callgraph node.  Typical usage can be seen in IPA passes which
+   create a temporary pass-related structures.  The summary class registers
+   hooks that are triggered when a new node is inserted, duplicated and deleted.
+   A user of a summary class can ovewrite virtual methods than are triggered by
+   the summary if such hook is triggered.  Apart from a callgraph node, the user
+   is given a data structure tied to the node.
+
+   The function summary class can work both with a heap-allocated memory and
+   a memory gained by garbage collected memory.  */
+
 template <class T>
 class GTY((user)) function_summary <T *>
 {
 public:
   /* Default construction takes SYMTAB as an argument.  */
-  function_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc),
-    m_map (13, ggc), m_insertion_enabled (true), m_symtab (symtab)
-  {
-#ifdef ENABLE_CHECKING
-    cgraph_node *node;
-
-    FOR_EACH_FUNCTION (node)
-    {
-      gcc_checking_assert (node->summary_uid > 0);
-    }
-#endif
-
-    m_symtab_insertion_hook =
-      symtab->add_cgraph_insertion_hook
-      (function_summary::symtab_insertion, this);
-
-    m_symtab_removal_hook =
-      symtab->add_cgraph_removal_hook
-      (function_summary::symtab_removal, this);
-    m_symtab_duplication_hook =
-      symtab->add_cgraph_duplication_hook
-      (function_summary::symtab_duplication, this);
-  }
+  function_summary (symbol_table *symtab, bool ggc = false);
 
   /* Destructor.  */
-  virtual ~function_summary ()
-  {
-    release ();
-  }
+  virtual ~function_summary ();
 
   /* Destruction method that can be called for GGT purpose.  */
-  void release ()
-  {
-    if (m_symtab_insertion_hook)
-      m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
-
-    if (m_symtab_removal_hook)
-      m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
-
-    if (m_symtab_duplication_hook)
-      m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
-
-    m_symtab_insertion_hook = NULL;
-    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);
-  }
+  void release ();
 
   /* 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);
-  }
+  void traverse (Arg a) const;
 
   /* Basic implementation of insert operation.  */
   virtual void insert (cgraph_node *, T *) {}
@@ -106,95 +70,36 @@ public:
   virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
 
   /* Allocates new data that are stored within map.  */
-  T* allocate_new ()
-  {
-    return m_ggc ? new (ggc_alloc <T> ()) T() : new T () ;
-  }
+  T* allocate_new ();
 
   /* Release an item that is stored within map.  */
-  void release (T *item)
-  {
-    if (m_ggc)
-      {
-	item->~T ();
-	ggc_free (item);
-      }
-    else
-      delete item;
-  }
+  void release (T *item);
 
-  /* Getter for summary callgraph node pointer.  */
-  T* get (cgraph_node *node)
-  {
-    return get (node->summary_uid);
-  }
+  /* Getter of function summary.  */
+  T* get (cgraph_node *node);
+
+  /* Getter of function summary.  If a summary for a node does not exist,
+     it will be created.  */
+  T* get_or_insert (cgraph_node *node);
 
   /* Return number of elements handled by data structure.  */
-  size_t elements ()
-  {
-    return m_map.elements ();
-  }
+  size_t elements ();
 
   /* Enable insertion hook invocation.  */
-  void enable_insertion_hook ()
-  {
-    m_insertion_enabled = true;
-  }
+  void enable_insertion_hook ();
 
   /* Enable insertion hook invocation.  */
-  void disable_insertion_hook ()
-  {
-    m_insertion_enabled = false;
-  }
+  void disable_insertion_hook ();
 
   /* Symbol insertion hook that is registered to symbol table.  */
-  static void symtab_insertion (cgraph_node *node, void *data)
-  {
-    function_summary *summary = (function_summary <T *> *) (data);
-
-    if (summary->m_insertion_enabled)
-      summary->insert (node, summary->get (node));
-  }
+  static void symtab_insertion (cgraph_node *node, void *data);
 
   /* Symbol removal hook that is registered to symbol table.  */
-  static void symtab_removal (cgraph_node *node, void *data)
-  {
-    gcc_checking_assert (node->summary_uid);
-    function_summary *summary = (function_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);
-      }
-  }
+  static void symtab_removal (cgraph_node *node, void *data);
 
   /* Symbol duplication hook that is registered to symbol table.  */
   static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
-				  void *data)
-  {
-    function_summary *summary = (function_summary <T *> *) (data);
-    T **v = summary->m_map.get (node->summary_uid);
-
-    gcc_checking_assert (node2->summary_uid > 0);
-
-    if (v)
-      {
-	/* This load is necessary, because we insert a new value!  */
-	T *data = *v;
-	T *duplicate = summary->allocate_new ();
-	summary->m_map.put (node2->summary_uid, duplicate);
-	summary->duplicate (node, node2, data, duplicate);
-      }
-  }
-
+				  void *data);
 protected:
   /* Indication if we use ggc summary.  */
   bool m_ggc;
@@ -202,16 +107,9 @@ protected:
 private:
   typedef int_hash <int, 0, -1> map_hash;
 
-  /* Getter for summary callgraph ID.  */
-  T* get (int uid)
-  {
-    bool existed;
-    T **v = &m_map.get_or_insert (uid, &existed);
-    if (!existed)
-      *v = allocate_new ();
-
-    return *v;
-  }
+  /* Getter of callgraph summary.  If LAZY_INSERT is set to true,
+     insert new summary, abort otherwise.  */
+  T* get (int uid, bool lazy_insert);
 
   /* Main summary store, where summary ID is used as key.  */
   hash_map <map_hash, T *> m_map;
@@ -233,8 +131,466 @@ private:
 };
 
 template <typename T>
+function_summary<T *>::function_summary (symbol_table *symtab, bool ggc)
+: m_ggc (ggc), m_map (13, ggc), m_insertion_enabled (true), m_symtab (symtab)
+{
+#ifdef ENABLE_CHECKING
+  cgraph_node *node;
+
+  FOR_EACH_FUNCTION (node)
+  {
+    gcc_checking_assert (node->summary_uid > 0);
+  }
+#endif
+
+  m_symtab_insertion_hook =
+    symtab->add_cgraph_insertion_hook
+    (function_summary::symtab_insertion, this);
+
+  m_symtab_removal_hook =
+    symtab->add_cgraph_removal_hook
+    (function_summary::symtab_removal, this);
+  m_symtab_duplication_hook =
+    symtab->add_cgraph_duplication_hook
+    (function_summary::symtab_duplication, this);
+}
+
+template <typename T>
+function_summary<T *>::~function_summary ()
+{
+  release ();
+}
+
+template <typename T>
+void
+function_summary<T *>::release ()
+{
+  if (m_symtab_insertion_hook)
+    m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
+
+  if (m_symtab_removal_hook)
+    m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
+
+  if (m_symtab_duplication_hook)
+    m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
+
+  m_symtab_insertion_hook = NULL;
+  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);
+}
+
+template <typename T>
+template<typename Arg, bool (*f)(const T &, Arg)>
+void
+function_summary<T *>::traverse (Arg a) const
+{
+  m_map.traverse <f> (a);
+}
+
+template <typename T>
+T *
+function_summary<T *>::allocate_new ()
+{
+  return m_ggc ? new (ggc_alloc <T> ()) T () : new T () ;
+}
+
+template <typename T>
+void
+function_summary<T *>::release (T *item)
+{
+  if (m_ggc)
+    {
+      item->~T ();
+      ggc_free (item);
+    }
+  else
+    delete item;
+}
+
+template <typename T>
+T *
+function_summary<T *>::get (cgraph_node *node)
+{
+  return get (node->summary_uid, false);
+}
+
+template <typename T>
+T *
+function_summary<T *>::get_or_insert (cgraph_node *node)
+{
+  return get (node->summary_uid, true);
+}
+
+template <typename T>
+size_t
+function_summary<T *>::elements ()
+{
+  return m_map.elements ();
+}
+
+template <typename T>
+void
+function_summary<T *>::enable_insertion_hook ()
+{
+  m_insertion_enabled = true;
+}
+
+template <typename T>
+void
+function_summary<T *>::disable_insertion_hook ()
+{
+  m_insertion_enabled = false;
+}
+
+template <typename T>
+void
+function_summary<T *>::symtab_insertion (cgraph_node *node, void *data)
+{
+  function_summary *summary = (function_summary <T *> *) (data);
+
+  if (summary->m_insertion_enabled)
+    summary->insert (node, summary->get (node));
+}
+
+template <typename T>
+void
+function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
+{
+  gcc_checking_assert (node->summary_uid);
+  function_summary *summary = (function_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);
+    }
+}
+
+template <typename T>
+void
+function_summary<T *>::symtab_duplication (cgraph_node *node,
+					   cgraph_node *node2,
+					   void *data)
+{
+  function_summary *summary = (function_summary <T *> *) (data);
+  T **v = summary->m_map.get (node->summary_uid);
+
+  gcc_checking_assert (node2->summary_uid > 0);
+
+  if (v)
+    {
+      T *data = *v;
+      T *duplicate = summary->allocate_new ();
+      summary->m_map.put (node2->summary_uid, duplicate);
+      summary->duplicate (node, node2, data, duplicate);
+    }
+}
+
+template <typename T>
+T *
+function_summary<T *>::get (int uid, bool lazy_insert)
+{
+  if (lazy_insert)
+    {
+      bool existed;
+      T **v = &m_map.get_or_insert (uid, &existed);
+      if (!existed)
+	*v = allocate_new ();
+
+      return *v;
+    }
+  else
+    {
+      T **v = m_map.get (uid);
+      return v == NULL ? NULL : *v;
+    }
+}
+
+template <typename T>
+void
+gt_ggc_mx (function_summary<T *>* const &summary)
+{
+  gcc_checking_assert (summary->m_ggc);
+  gt_ggc_mx (&summary->m_map);
+}
+
+template <typename T>
+void
+gt_pch_nx (function_summary<T *>* const &summary)
+{
+  gcc_checking_assert (summary->m_ggc);
+  gt_pch_nx (&summary->m_map);
+}
+
+template <typename T>
+void
+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 ();
+};
+
+/* Edge summary is a helper class that is used to associate a data structure
+   related to a callgraph edge.  Typical usage can be seen in IPA passes which
+   create a temporary pass-related structures.  The summary class registers
+   hooks that are triggered when a new edge is duplicated and deleted.
+   A user of a summary class can ovewrite virtual methods than are triggered by
+   the summary if such hook is triggered.  Apart from a callgraph edge, the user
+   is given a data structure tied to the edge.
+
+   The edge summary class can work both with a heap-allocated memory and
+   a memory gained by garbage collected memory.  */
+
+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);
+
+  /* Destructor.  */
+  virtual ~edge_summary ();
+
+  /* Destruction method that can be called for GGC purpose.  */
+  void release ();
+
+  /* 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;
+
+  /* Initializer is called after we allocate a new 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 *) {}
+
+  /* Allocates new data that are stored within map.  */
+  T* allocate_new (cgraph_edge *edge);
+
+  /* Release an item that is stored within map.  */
+  void release (T *item);
+
+  /* Getter of edge summary.  */
+  T* get (cgraph_edge *edge);
+
+  /* Getter of edge summary.  If a summary for an edge does not exist,
+     it will be created.  */
+  T* get_or_insert (cgraph_edge *edge);
+
+  /* Return number of elements handled by data structure.  */
+  size_t elements ();
+
+  /* Symbol removal hook that is registered to symbol table.  */
+  static void symtab_removal (cgraph_edge *edge, void *data);
+
+  /* Symbol duplication hook that is registered to symbol table.  */
+  static void symtab_duplication (cgraph_edge *edge, cgraph_edge *edge2,
+				  void *data);
+
+protected:
+  /* Indication if we use ggc summary.  */
+  bool m_ggc;
+
+private:
+  typedef int_hash <int, 0, -1> map_hash;
+
+  /* Getter of edge summary.  If LAZY_INSERT is set to true,
+     insert new summary, abort otherwise.  */
+  T* get (cgraph_edge *edge, bool lazy_insert);
+
+  /* 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>
+edge_summary<T *>::edge_summary (symbol_table *symtab, bool ggc)
+: m_ggc (ggc), m_map (13, ggc), m_symtab (symtab)
+{
+  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);
+}
+
+template <typename T>
+edge_summary<T *>::~edge_summary ()
+{
+  release ();
+}
+
+template <typename T>
+void
+edge_summary<T *>::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);
+}
+
+template <typename T>
+template<typename Arg, bool (*f)(const T &, Arg)>
+void
+edge_summary<T *>::traverse (Arg a) const
+{
+  m_map.traverse <f> (a);
+}
+
+template <typename T>
+T*
+edge_summary<T *>::allocate_new (cgraph_edge *edge)
+{
+  T *v = m_ggc ? new (ggc_alloc <T> ()) T () : new T () ;
+  initialize (edge, v);
+
+  return v;
+}
+
+template <typename T>
+void
+edge_summary<T *>::release (T *item)
+{
+  if (m_ggc)
+    {
+      item->~T ();
+      ggc_free (item);
+    }
+  else
+    delete item;
+}
+
+template <typename T>
+T *
+edge_summary<T *>::get (cgraph_edge *edge, bool lazy_insert)
+{
+  if (lazy_insert)
+    {
+      bool existed;
+      T **v = &m_map.get_or_insert (edge->summary_uid, &existed);
+      if (!existed)
+	*v = allocate_new (edge);
+
+      return *v;
+    }
+  else
+    {
+      T **v = m_map.get (edge->summary_uid);
+      return v == NULL ? NULL : *v;
+    }
+}
+
+template <typename T>
+T *
+edge_summary<T *>::get (cgraph_edge *edge)
+{
+  return get (edge, false);
+}
+
+template <typename T>
+T *
+edge_summary<T *>::get_or_insert (cgraph_edge *edge)
+{
+  return get (edge, true);
+}
+
+template <typename T>
+size_t
+edge_summary<T *>::elements ()
+{
+  return m_map.elements ();
+}
+
+template <typename T>
 void
-gt_ggc_mx(function_summary<T *>* const &summary)
+edge_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
+{
+  gcc_checking_assert (edge->summary_uid);
+  edge_summary *summary = (edge_summary <T *> *) (data);
+
+  int summary_uid = edge->summary_uid;
+  T **v = summary->m_map.get (summary_uid);
+
+  if (v)
+    {
+      summary->remove (edge, *v);
+
+      if (!summary->m_ggc)
+	delete (*v);
+
+      summary->m_map.remove (summary_uid);
+    }
+}
+
+template <typename T>
+void
+edge_summary<T *>::symtab_duplication (cgraph_edge *edge, cgraph_edge *edge2,
+				       void *data)
+{
+  edge_summary *summary = (edge_summary <T *> *) (data);
+  T *s = summary->get_or_insert (edge);
+
+  gcc_checking_assert (s);
+  gcc_checking_assert (edge2->summary_uid > 0);
+
+  T *duplicate = summary->allocate_new (edge2);
+  summary->m_map.put (edge2->summary_uid, duplicate);
+  summary->duplicate (edge, edge2, s, duplicate);
+}
+
+template <typename T>
+void
+gt_ggc_mx (edge_summary<T *>* const &summary)
 {
   gcc_checking_assert (summary->m_ggc);
   gt_ggc_mx (&summary->m_map);
@@ -242,7 +598,7 @@ gt_ggc_mx(function_summary<T *>* const &summary)
 
 template <typename T>
 void
-gt_pch_nx(function_summary<T *>* const &summary)
+gt_pch_nx (edge_summary<T *>* const &summary)
 {
   gcc_checking_assert (summary->m_ggc);
   gt_pch_nx (&summary->m_map);
@@ -250,11 +606,12 @@ 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 (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  */
-- 
2.4.5


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]