public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/6] hash_set: add iterator and remove method.
  2015-07-09 11:07 [PATCH 0/6] {function,edge}_summary for IPA passes mliska
@ 2015-07-09 11:07 ` mliska
  2015-07-09 17:05   ` Jeff Law
  2015-07-09 11:08 ` [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum mliska
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: mliska @ 2015-07-09 11:07 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

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

	* hash-set.h (remove): New function.
	(iterator): New iteration class for hash_set.
---
 gcc/hash-set.h | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/gcc/hash-set.h b/gcc/hash-set.h
index 2fb6cae..e85af2a 100644
--- a/gcc/hash-set.h
+++ b/gcc/hash-set.h
@@ -59,6 +59,11 @@ public:
       return !Traits::is_empty (e);
     }
 
+  void remove (const Key &k)
+    {
+      m_table.remove_elt_with_hash (k, Traits::hash (k));
+    }
+
   /* Call the call back on each pair of key and value with the passed in
      arg.  */
 
@@ -74,6 +79,40 @@ public:
 
   size_t elements () const { return m_table.elements (); }
 
+  class iterator
+  {
+  public:
+    explicit iterator (const typename hash_table<Traits>::iterator &iter) :
+      m_iter (iter) {}
+
+    iterator &operator++ ()
+      {
+	++m_iter;
+	return *this;
+      }
+
+    Key
+    operator* ()
+      {
+	return *m_iter;
+      }
+
+    bool
+    operator != (const iterator &other) const
+      {
+	return m_iter != other.m_iter;
+      }
+
+  private:
+    typename hash_table<Traits>::iterator m_iter;
+  };
+
+  /* Standard iterator retrieval methods.  */
+
+  iterator begin () const { return iterator (m_table.begin ()); }
+  iterator end () const { return iterator (m_table.end ()); }
+
+
 private:
 
   template<typename T, typename U> friend void gt_ggc_mx (hash_set<T, U> *);
-- 
2.4.5


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/6] {function,edge}_summary for IPA passes
@ 2015-07-09 11:07 mliska
  2015-07-09 11:07 ` [PATCH 1/6] hash_set: add iterator and remove method mliska
                   ` (5 more replies)
  0 siblings, 6 replies; 24+ messages in thread
From: mliska @ 2015-07-09 11:07 UTC (permalink / raw)
  To: gcc-patches

Following series of patches continues where I stopped at the end of
previous stage 1. It ports places in IPA passes to function_summary container
and I introduce a new edge_summary, which is essentially very similar to
the aforementioned container.

Patches were tested together on x86_64-linux-gnu and boostrap on both
x86_64-linux-gnu and ppc64le-linux-gnu machines.

Ready for trunk?

Thanks,
Martin

mliska (6):
  hash_set: add iterator and remove method.
  Introduce new edge_summary class and replace ipa_edge_args_sum.
  IPA inline: port inline_edge_summary to a new infrastructure.
  Port ipa-cp to use cgraph_edge summary.
  Port IPA reference to function_summary infrastructure.
  Migrate ipa-pure-const to function_summary.

 gcc/cgraph.c              |   2 +
 gcc/cgraph.h              |   5 +-
 gcc/hash-set.h            |  39 +++++++++
 gcc/ipa-cp.c              | 198 ++++++++++++++++++++++++-------------------
 gcc/ipa-inline-analysis.c | 107 +++++++++---------------
 gcc/ipa-inline.c          |  18 ++--
 gcc/ipa-inline.h          |  28 +++++--
 gcc/ipa-profile.c         |   4 +-
 gcc/ipa-prop.c            |  78 ++++-------------
 gcc/ipa-prop.h            |  44 ++++++----
 gcc/ipa-pure-const.c      | 177 +++++++++++++++------------------------
 gcc/ipa-reference.c       | 203 ++++++++++++++++++++++----------------------
 gcc/ipa-split.c           |   3 +-
 gcc/ipa.c                 |   2 +-
 gcc/symbol-summary.h      | 208 +++++++++++++++++++++++++++++++++++++++++++++-
 15 files changed, 645 insertions(+), 471 deletions(-)

-- 
2.4.5

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 4/6] Port ipa-cp to use cgraph_edge summary.
  2015-07-09 11:07 [PATCH 0/6] {function,edge}_summary for IPA passes mliska
  2015-07-09 11:07 ` [PATCH 1/6] hash_set: add iterator and remove method mliska
  2015-07-09 11:08 ` [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum mliska
@ 2015-07-09 11:08 ` mliska
  2015-07-09 17:39   ` Jeff Law
  2015-07-10 14:18   ` Martin Jambor
  2015-07-09 11:08 ` [PATCH 3/6] IPA inline: port inline_edge_summary to a new infrastructure mliska
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 24+ messages in thread
From: mliska @ 2015-07-09 11:08 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

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

	* ipa-cp.c (struct edge_clone_summary): New structure.
	(class edge_clone_summary_t): Likewise.
	(edge_clone_summary_t::initialize): New method.
	(edge_clone_summary_t::duplicate): Likewise.
	(get_next_cgraph_edge_clone): Remove.
	(get_info_about_necessary_edges): Refactor using the new
	data structure.
	(gather_edges_for_value): Likewise.
	(perhaps_add_new_callers): Likewise.
	(ipcp_driver): Allocate and deallocate newly added
	instance.
---
 gcc/ipa-cp.c | 198 ++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 113 insertions(+), 85 deletions(-)

diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 16b9cde..8a50b63 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -2888,54 +2888,79 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
     inline_update_overall_summary (node);
 }
 
-/* Vector of pointers which for linked lists of clones of an original crgaph
-   edge. */
+/* Edge clone summary.  */
 
-static vec<cgraph_edge *> next_edge_clone;
-static vec<cgraph_edge *> prev_edge_clone;
-
-static inline void
-grow_edge_clone_vectors (void)
+struct edge_clone_summary
 {
-  if (next_edge_clone.length ()
-      <=  (unsigned) symtab->edges_max_uid)
-    next_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
-  if (prev_edge_clone.length ()
-      <=  (unsigned) symtab->edges_max_uid)
-    prev_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
-}
+  /* Default constructor.  */
+  edge_clone_summary (): edge_set (NULL), edge (NULL) {}
 
-/* Edge duplication hook to grow the appropriate linked list in
-   next_edge_clone. */
+  /* Default destructor.  */
+  ~edge_clone_summary ()
+  {
+    gcc_assert (edge_set != NULL);
 
-static void
-ipcp_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
-			    void *)
+    if (edge != NULL)
+      {
+	gcc_checking_assert (edge_set->contains (edge));
+	edge_set->remove (edge);
+      }
+
+    /* Release memory for an empty set.  */
+    if (edge_set->elements () == 0)
+      delete edge_set;
+  }
+
+  hash_set <cgraph_edge *> *edge_set;
+  cgraph_edge *edge;
+};
+
+class edge_clone_summary_t:
+  public edge_summary <edge_clone_summary *>
 {
-  grow_edge_clone_vectors ();
+public:
+  edge_clone_summary_t (symbol_table *symtab):
+    edge_summary <edge_clone_summary *> (symtab) {}
+
+  virtual void initialize (cgraph_edge *edge, edge_clone_summary *data);
+  virtual void duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge,
+			  edge_clone_summary *src_data,
+			  edge_clone_summary *dst_data);
+};
 
-  struct cgraph_edge *old_next = next_edge_clone[src->uid];
-  if (old_next)
-    prev_edge_clone[old_next->uid] = dst;
-  prev_edge_clone[dst->uid] = src;
+static edge_summary <edge_clone_summary *> *edge_clone_summaries = NULL;
+
+void
+edge_clone_summary_t::initialize (cgraph_edge *edge, edge_clone_summary *data)
+{
+  gcc_checking_assert (data->edge_set == NULL);
 
-  next_edge_clone[dst->uid] = old_next;
-  next_edge_clone[src->uid] = dst;
+  data->edge_set = new hash_set <cgraph_edge *> ();
+  data->edge_set->add (edge);
+  data->edge = edge;
 }
 
-/* Hook that is called by cgraph.c when an edge is removed.  */
+/* Edge duplication hook.  */
 
-static void
-ipcp_edge_removal_hook (struct cgraph_edge *cs, void *)
+void
+edge_clone_summary_t::duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge,
+				 edge_clone_summary *src_data,
+				 edge_clone_summary *dst_data)
 {
-  grow_edge_clone_vectors ();
-
-  struct cgraph_edge *prev = prev_edge_clone[cs->uid];
-  struct cgraph_edge *next = next_edge_clone[cs->uid];
-  if (prev)
-    next_edge_clone[prev->uid] = next;
-  if (next)
-    prev_edge_clone[next->uid] = prev;
+  dst_data->edge = dst_edge;
+  if (src_data->edge_set == NULL)
+    {
+      src_data->edge_set = new hash_set <cgraph_edge *> ();
+      src_data->edge_set->add (src_edge);
+    }
+
+  src_data->edge_set->add (dst_edge);
+
+  /* As ::initialize processes an allocation, we have to release previous
+     edge_set.   */
+  delete dst_data->edge_set;
+
+  dst_data->edge_set = src_data->edge_set;
 }
 
 /* See if NODE is a clone with a known aggregate value at a given OFFSET of a
@@ -3050,14 +3075,6 @@ cgraph_edge_brings_value_p (cgraph_edge *cs,
 				plats->ctxlat.values->value);
 }
 
-/* Get the next clone in the linked list of clones of an edge.  */
-
-static inline struct cgraph_edge *
-get_next_cgraph_edge_clone (struct cgraph_edge *cs)
-{
-  return next_edge_clone[cs->uid];
-}
-
 /* Given VAL that is intended for DEST, iterate over all its sources and if
    they still hold, add their edge frequency and their number into *FREQUENCY
    and *CALLER_COUNT respectively.  */
@@ -3075,18 +3092,23 @@ get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
 
   for (src = val->sources; src; src = src->next)
     {
-      struct cgraph_edge *cs = src->cs;
-      while (cs)
-	{
-	  if (cgraph_edge_brings_value_p (cs, src, dest))
+      cgraph_edge *cs = src->cs;
+
+      edge_clone_summary *s = edge_clone_summaries->get (cs);
+      if (s->edge_set != NULL)
+	for (hash_set <cgraph_edge *>::iterator it = s->edge_set->begin ();
+	     it != s->edge_set->end (); ++it)
+	  {
+	    cs = *it;
+
+	    if (cgraph_edge_brings_value_p (cs, src, dest))
 	    {
 	      count++;
 	      freq += cs->frequency;
 	      cnt += cs->count;
 	      hot |= cs->maybe_hot_p ();
 	    }
-	  cs = get_next_cgraph_edge_clone (cs);
-	}
+	  }
     }
 
   *freq_sum = freq;
@@ -3109,13 +3131,16 @@ gather_edges_for_value (ipcp_value<valtype> *val, cgraph_node *dest,
   ret.create (caller_count);
   for (src = val->sources; src; src = src->next)
     {
-      struct cgraph_edge *cs = src->cs;
-      while (cs)
-	{
-	  if (cgraph_edge_brings_value_p (cs, src, dest))
-	    ret.quick_push (cs);
-	  cs = get_next_cgraph_edge_clone (cs);
-	}
+      cgraph_edge *cs = src->cs;
+      edge_clone_summary *s = edge_clone_summaries->get (cs);
+      if (s->edge_set != NULL)
+	for (hash_set <cgraph_edge *>::iterator it = s->edge_set->begin ();
+	     it != s->edge_set->end (); ++it)
+	  {
+	    cs = *it;
+	    if (cgraph_edge_brings_value_p (cs, src, dest))
+	      ret.quick_push (cs);
+	  }
     }
 
   return ret;
@@ -3971,25 +3996,35 @@ perhaps_add_new_callers (cgraph_node *node, ipcp_value<valtype> *val)
   for (src = val->sources; src; src = src->next)
     {
       struct cgraph_edge *cs = src->cs;
-      while (cs)
+
+      edge_clone_summary *s = edge_clone_summaries->get (cs);
+      if (s->edge_set != NULL)
 	{
-	  if (cgraph_edge_brings_value_p (cs, src, node)
-	      && cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node)
-	      && cgraph_edge_brings_all_agg_vals_for_node (cs, val->spec_node))
+	  for (hash_set <cgraph_edge *>::iterator it = s->edge_set->begin ();
+	       it != s->edge_set->end (); ++it)
 	    {
-	      if (dump_file)
-		fprintf (dump_file, " - adding an extra caller %s/%i"
-			 " of %s/%i\n",
-			 xstrdup_for_dump (cs->caller->name ()),
-			 cs->caller->order,
-			 xstrdup_for_dump (val->spec_node->name ()),
-			 val->spec_node->order);
-
-	      cs->redirect_callee_duplicating_thunks (val->spec_node);
-	      val->spec_node->expand_all_artificial_thunks ();
-	      redirected_sum += cs->count;
+	      cgraph_edge *cs = *it;
+
+	      if (cgraph_edge_brings_value_p (cs, src, node)
+		  && cgraph_edge_brings_all_scalars_for_node (cs,
+							      val->spec_node)
+		  && cgraph_edge_brings_all_agg_vals_for_node (cs,
+							       val->spec_node))
+		{
+		  if (dump_file)
+		    fprintf (dump_file, " - adding an extra caller %s/%i"
+			     " of %s/%i\n",
+			     xstrdup_for_dump (cs->caller->name ()),
+			     cs->caller->order,
+			     xstrdup_for_dump (val->spec_node->name ()),
+			     val->spec_node->order);
+
+		  cs->redirect_callee_duplicating_thunks (val->spec_node);
+		  val->spec_node->expand_all_artificial_thunks ();
+		  redirected_sum += cs->count;
+
+		}
 	    }
-	  cs = get_next_cgraph_edge_clone (cs);
 	}
     }
 
@@ -4441,17 +4476,13 @@ ipcp_store_alignment_results (void)
 static unsigned int
 ipcp_driver (void)
 {
-  struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
-  struct cgraph_edge_hook_list *edge_removal_hook_holder;
   struct ipa_topo_info topo;
 
+  if (edge_clone_summaries == NULL)
+    edge_clone_summaries = new edge_clone_summary_t (symtab);
+
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
-  grow_edge_clone_vectors ();
-  edge_duplication_hook_holder =
-    symtab->add_edge_duplication_hook (&ipcp_edge_duplication_hook, NULL);
-  edge_removal_hook_holder =
-    symtab->add_edge_removal_hook (&ipcp_edge_removal_hook, NULL);
 
   if (dump_file)
     {
@@ -4472,10 +4503,7 @@ ipcp_driver (void)
 
   /* Free all IPCP structures.  */
   free_toporder_info (&topo);
-  next_edge_clone.release ();
-  prev_edge_clone.release ();
-  symtab->remove_edge_removal_hook (edge_removal_hook_holder);
-  symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
+  delete edge_clone_summaries;
   ipa_free_all_structures_after_ipa_cp ();
   if (dump_file)
     fprintf (dump_file, "\nIPA constant propagation end\n");
-- 
2.4.5


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum.
  2015-07-09 11:07 [PATCH 0/6] {function,edge}_summary for IPA passes mliska
  2015-07-09 11:07 ` [PATCH 1/6] hash_set: add iterator and remove method mliska
@ 2015-07-09 11:08 ` mliska
  2015-07-09 17:15   ` Jeff Law
  2015-07-10 13:31   ` Martin Jambor
  2015-07-09 11:08 ` [PATCH 4/6] Port ipa-cp to use cgraph_edge summary mliska
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 24+ messages in thread
From: mliska @ 2015-07-09 11:08 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

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

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

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


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5/6] Port IPA reference to function_summary infrastructure.
  2015-07-09 11:07 [PATCH 0/6] {function,edge}_summary for IPA passes mliska
                   ` (3 preceding siblings ...)
  2015-07-09 11:08 ` [PATCH 3/6] IPA inline: port inline_edge_summary to a new infrastructure mliska
@ 2015-07-09 11:08 ` mliska
  2015-07-09 17:35   ` Jeff Law
  2015-07-10 13:30   ` Martin Jambor
  2015-07-09 11:09 ` [PATCH 6/6] Migrate ipa-pure-const to function_summary mliska
  5 siblings, 2 replies; 24+ messages in thread
From: mliska @ 2015-07-09 11:08 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

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

	* ipa-reference.c (ipa_ref_opt_summary_t): New class.
	(get_reference_optimization_summary): Use it.
	(set_reference_optimization_summary): Likewise.
	(ipa_init): Remove hook holders usage.
	(ipa_reference_c_finalize): Likewise.
	(ipa_ref_opt_summary_t::duplicate): New function.
	(ipa_ref_opt_summary_t::remove): Likewise.
	(propagate): Allocate the summary if does not exist.
	(ipa_reference_read_optimization_summary): Likewise.
	(struct ipa_reference_vars_info_d): Add new method.
	(struct ipa_reference_optimization_summary_d): Likewise.
	(get_reference_vars_info): Use new underlying container.
	(set_reference_vars_info): Remove.
	(init_function_info): Set up the container.
---
 gcc/ipa-reference.c | 203 ++++++++++++++++++++++++++--------------------------
 1 file changed, 102 insertions(+), 101 deletions(-)

diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index 465a74b..2afd9ad 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -58,12 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "data-streamer.h"
 #include "lto-streamer.h"
-
-static void remove_node_data (struct cgraph_node *node,
-			      void *data ATTRIBUTE_UNUSED);
-static void duplicate_node_data (struct cgraph_node *src,
-				 struct cgraph_node *dst,
-				 void *data ATTRIBUTE_UNUSED);
+#include "symbol-summary.h"
 
 /* The static variables defined within the compilation unit that are
    loaded or stored directly by function that owns this structure.  */
@@ -89,6 +84,13 @@ struct ipa_reference_global_vars_info_d
 
 struct ipa_reference_optimization_summary_d
 {
+  /* Return true if the data structure is empty.  */
+  inline bool
+  empty_p ()
+  {
+    return statics_not_read == NULL && statics_not_written == NULL;
+  }
+
   bitmap statics_not_read;
   bitmap statics_not_written;
 };
@@ -99,6 +101,14 @@ typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_
 
 struct ipa_reference_vars_info_d
 {
+  /* Return true if the data structure is empty.  */
+  inline bool
+  empty_p ()
+  {
+    return local.statics_read == NULL && local.statics_written == NULL
+      && global.statics_read == NULL && global.statics_written == NULL;
+  }
+
   struct ipa_reference_local_vars_info_d local;
   struct ipa_reference_global_vars_info_d global;
 };
@@ -123,57 +133,61 @@ static bitmap_obstack local_info_obstack;
 /* Obstack holding global analysis live forever.  */
 static bitmap_obstack optimization_summary_obstack;
 
-/* Holders of ipa cgraph hooks: */
-static struct cgraph_2node_hook_list *node_duplication_hook_holder;
-static struct cgraph_node_hook_list *node_removal_hook_holder;
+class ipa_ref_var_info_summary_t: public function_summary
+			  <ipa_reference_vars_info_d *>
+{
+public:
+  ipa_ref_var_info_summary_t (symbol_table *symtab):
+    function_summary <ipa_reference_vars_info_d *> (symtab) {}
+};
 
-/* Vector where the reference var infos are actually stored. 
-   Indexed by UID of call graph nodes.  */
-static vec<ipa_reference_vars_info_t> ipa_reference_vars_vector;
+static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL;
 
-/* TODO: find a place where we should release the vector.  */
-static vec<ipa_reference_optimization_summary_t> ipa_reference_opt_sum_vector;
+class ipa_ref_opt_summary_t: public function_summary
+			     <ipa_reference_optimization_summary_d *>
+{
+public:
+  ipa_ref_opt_summary_t (symbol_table *symtab):
+    function_summary <ipa_reference_optimization_summary_d *> (symtab) {}
+
+
+  virtual void remove (cgraph_node *src_node,
+		       ipa_reference_optimization_summary_d *data);
+  virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
+			  ipa_reference_optimization_summary_d *src_data,
+			  ipa_reference_optimization_summary_d *dst_data);
+};
+
+static ipa_ref_opt_summary_t *ipa_ref_opt_sum_summaries = NULL;
 
 /* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
 static inline ipa_reference_vars_info_t
 get_reference_vars_info (struct cgraph_node *node)
 {
-  if (!ipa_reference_vars_vector.exists ()
-      || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
+  if (ipa_ref_var_info_summaries == NULL)
     return NULL;
-  return ipa_reference_vars_vector[node->uid];
+
+  ipa_reference_vars_info_t v = ipa_ref_var_info_summaries->get (node);
+  if (v->empty_p ())
+    return NULL;
+
+  return v;
 }
 
 /* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
 static inline ipa_reference_optimization_summary_t
 get_reference_optimization_summary (struct cgraph_node *node)
 {
-  if (!ipa_reference_opt_sum_vector.exists ()
-      || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
+  if (ipa_ref_opt_sum_summaries == NULL)
     return NULL;
-  return ipa_reference_opt_sum_vector[node->uid];
-}
 
-/* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
-static inline void
-set_reference_vars_info (struct cgraph_node *node,
-			 ipa_reference_vars_info_t info)
-{
-  if (!ipa_reference_vars_vector.exists ()
-      || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
-    ipa_reference_vars_vector.safe_grow_cleared (node->uid + 1);
-  ipa_reference_vars_vector[node->uid] = info;
-}
+  ipa_reference_optimization_summary_t v = ipa_ref_opt_sum_summaries->get
+    (node);
 
-/* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
-static inline void
-set_reference_optimization_summary (struct cgraph_node *node,
-				    ipa_reference_optimization_summary_t info)
-{
-  if (!ipa_reference_opt_sum_vector.exists ()
-      || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
-    ipa_reference_opt_sum_vector.safe_grow_cleared (node->uid + 1);
-  ipa_reference_opt_sum_vector[node->uid] = info;
+  if (v->empty_p ())
+    return NULL;
+
+  return v;
 }
 
 /* Return a bitmap indexed by DECL_UID for the static variables that
@@ -412,10 +426,14 @@ ipa_init (void)
   all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
   ignore_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
 
-  node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
-  node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
+  if (ipa_ref_var_info_summaries == NULL)
+    ipa_ref_var_info_summaries = new ipa_ref_var_info_summary_t (symtab);
+
+  if (ipa_ref_opt_sum_summaries != NULL)
+    {
+      delete ipa_ref_opt_sum_summaries;
+      ipa_ref_opt_sum_summaries = NULL;
+    }
 }
 
 
@@ -424,11 +442,7 @@ ipa_init (void)
 static ipa_reference_local_vars_info_t
 init_function_info (struct cgraph_node *fn)
 {
-  ipa_reference_vars_info_t info
-    = XCNEW (struct ipa_reference_vars_info_d);
-
-  /* Add the info to the tree's annotation.  */
-  set_reference_vars_info (fn, info);
+  ipa_reference_vars_info_t info = ipa_ref_var_info_summaries->get (fn);
 
   info->local.statics_read = BITMAP_ALLOC (&local_info_obstack);
   info->local.statics_written = BITMAP_ALLOC (&local_info_obstack);
@@ -491,18 +505,12 @@ analyze_function (struct cgraph_node *fn)
 
 /* Called when new clone is inserted to callgraph late.  */
 
-static void
-duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
-	 	     void *data ATTRIBUTE_UNUSED)
+void
+ipa_ref_opt_summary_t::duplicate (cgraph_node *, cgraph_node *,
+				  ipa_reference_optimization_summary_d *ginfo,
+				  ipa_reference_optimization_summary_d
+				  *dst_ginfo)
 {
-  ipa_reference_optimization_summary_t ginfo;
-  ipa_reference_optimization_summary_t dst_ginfo;
-
-  ginfo = get_reference_optimization_summary (src);
-  if (!ginfo)
-    return;
-  dst_ginfo = XCNEW (struct ipa_reference_optimization_summary_d);
-  set_reference_optimization_summary (dst, dst_ginfo);
   dst_ginfo->statics_not_read =
     copy_static_var_set (ginfo->statics_not_read);
   dst_ginfo->statics_not_written =
@@ -511,23 +519,17 @@ duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
 
 /* Called when node is removed.  */
 
-static void
-remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+ipa_ref_opt_summary_t::remove (cgraph_node *,
+			       ipa_reference_optimization_summary_d *ginfo)
 {
-  ipa_reference_optimization_summary_t ginfo;
-  ginfo = get_reference_optimization_summary (node);
-  if (ginfo)
-    {
-      if (ginfo->statics_not_read
-	  && ginfo->statics_not_read != all_module_statics)
-	BITMAP_FREE (ginfo->statics_not_read);
-
-      if (ginfo->statics_not_written
-	  && ginfo->statics_not_written != all_module_statics)
-	BITMAP_FREE (ginfo->statics_not_written);
-      free (ginfo);
-      set_reference_optimization_summary (node, NULL);
-    }
+  if (ginfo->statics_not_read
+      && ginfo->statics_not_read != all_module_statics)
+    BITMAP_FREE (ginfo->statics_not_read);
+
+  if (ginfo->statics_not_written
+      && ginfo->statics_not_written != all_module_statics)
+    BITMAP_FREE (ginfo->statics_not_written);
 }
 
 /* Analyze each function in the cgraph to see which global or statics
@@ -837,12 +839,14 @@ propagate (void)
 	}
     }
 
+  if (ipa_ref_opt_sum_summaries == NULL)
+    ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
+
   /* Cleanup. */
   FOR_EACH_DEFINED_FUNCTION (node)
     {
       ipa_reference_vars_info_t node_info;
       ipa_reference_global_vars_info_t node_g;
-      ipa_reference_optimization_summary_t opt;
 
       node_info = get_reference_vars_info (node);
       if (!node->alias && opt_for_fn (node->decl, flag_ipa_reference)
@@ -851,8 +855,8 @@ propagate (void)
 	{
 	  node_g = &node_info->global;
 
-	  opt = XCNEW (struct ipa_reference_optimization_summary_d);
-	  set_reference_optimization_summary (node, opt);
+	  ipa_reference_optimization_summary_d *opt =
+	    ipa_ref_opt_sum_summaries->get (node);
 
 	  /* Create the complimentary sets.  */
 
@@ -880,14 +884,20 @@ propagate (void)
 				  node_g->statics_written);
 	    }
 	}
-      free (node_info);
    }
 
   ipa_free_postorder_info ();
   free (order);
 
   bitmap_obstack_release (&local_info_obstack);
-  ipa_reference_vars_vector.release ();
+
+  if (ipa_ref_var_info_summaries == NULL)
+    {
+      delete ipa_ref_var_info_summaries;
+      ipa_ref_var_info_summaries = NULL;
+    }
+
+  ipa_ref_var_info_summaries = NULL;
   if (dump_file)
     splay_tree_delete (reference_vars_to_consider);
   reference_vars_to_consider = NULL;
@@ -907,8 +917,10 @@ write_node_summary_p (struct cgraph_node *node,
   if (!node->definition || node->global.inlined_to)
     return false;
   info = get_reference_optimization_summary (node);
-  if (!info || (bitmap_empty_p (info->statics_not_read)
-		&& bitmap_empty_p (info->statics_not_written)))
+  if (!info
+      || info->empty_p ()
+      || (bitmap_empty_p (info->statics_not_read)
+	  && bitmap_empty_p (info->statics_not_written)))
     return false;
 
   /* See if we want to encode it.
@@ -1047,10 +1059,9 @@ ipa_reference_read_optimization_summary (void)
   unsigned int j = 0;
   bitmap_obstack_initialize (&optimization_summary_obstack);
 
-  node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
-  node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
+  if (ipa_ref_opt_sum_summaries == NULL)
+    ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
+
   all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
 
   while ((file_data = file_data_vec[j++]))
@@ -1085,7 +1096,6 @@ ipa_reference_read_optimization_summary (void)
 	    {
 	      unsigned int j, index;
 	      struct cgraph_node *node;
-	      ipa_reference_optimization_summary_t info;
 	      int v_count;
 	      lto_symtab_encoder_t encoder;
 
@@ -1093,8 +1103,10 @@ ipa_reference_read_optimization_summary (void)
 	      encoder = file_data->symtab_node_encoder;
 	      node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref
 		(encoder, index));
-	      info = XCNEW (struct ipa_reference_optimization_summary_d);
-	      set_reference_optimization_summary (node, info);
+
+	      ipa_reference_optimization_summary_d *info =
+		ipa_ref_opt_sum_summaries->get (node);
+
 	      info->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack);
 	      info->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack);
 	      if (dump_file)
@@ -1223,15 +1235,4 @@ ipa_reference_c_finalize (void)
       bitmap_obstack_release (&optimization_summary_obstack);
       ipa_init_p = false;
     }
-
-  if (node_removal_hook_holder)
-    {
-      symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
-      node_removal_hook_holder = NULL;
-    }
-  if (node_duplication_hook_holder)
-    {
-      symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
-      node_duplication_hook_holder = NULL;
-    }
 }
-- 
2.4.5


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/6] IPA inline: port inline_edge_summary to a new infrastructure.
  2015-07-09 11:07 [PATCH 0/6] {function,edge}_summary for IPA passes mliska
                   ` (2 preceding siblings ...)
  2015-07-09 11:08 ` [PATCH 4/6] Port ipa-cp to use cgraph_edge summary mliska
@ 2015-07-09 11:08 ` mliska
  2015-07-09 17:21   ` Jeff Law
  2015-07-09 11:08 ` [PATCH 5/6] Port IPA reference to function_summary infrastructure mliska
  2015-07-09 11:09 ` [PATCH 6/6] Migrate ipa-pure-const to function_summary mliska
  5 siblings, 1 reply; 24+ messages in thread
From: mliska @ 2015-07-09 11:08 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

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

	* ipa-inline-analysis.c
	(inline_edge_summaries): New data structure.
	(redirect_to_unreachable): Use renamed
	function get_inline_edge_summary.
	(edge_set_predicate): Likewise.
	(evaluate_properties_for_edge): Likewise.
	(reset_inline_edge_summary): Likewise.
	(inline_summary_t::duplicate): New function.
	(inline_edge_summary_t::duplicate): Likewise.
	(dump_inline_edge_summary): Use renamed function
	get_inline_edge_summary.
	(estimate_function_body_sizes): Likewise.
	(compute_inline_parameters): Likewise.
	(estimate_edge_size_and_time): Likewise.
	(estimate_calls_size_and_time): Likewise.
	(inline_update_callee_summaries): Likewise.
	(remap_edge_change_prob): Likewise.
	(remap_edge_summaries): Likewise.
	(inline_merge_summary): Likewise.
	(do_estimate_edge_time): Likewise.
	(estimate_time_after_inlining): Likewise.
	(estimate_size_after_inlining): Likewise.
	(read_inline_edge_summary): Likewise.
	(write_inline_edge_summary): Likewise.
	(inline_summary_alloc): Remove symtab hook holders.
	(inline_free_summary): Likewise.
	* ipa-inline.c (can_inline_edge_p): Use get_inline_edge_summary.
	(compute_inlined_call_time): Likewise.
	(want_inline_small_function_p): Likewise.
	(edge_badness): Likewise.
	(early_inliner): Likewise.
	* ipa-inline.h (get_inline_edge_summary): Renamed from
	inline_edge_summary.
	(estimate_edge_growth): Use the function.
	* ipa-profile.c (ipa_propagate_frequency_1): Likewise.
	* ipa-prop.c (ipa_make_edge_direct_to_target): Likewise.
	(ipa_free_all_edge_args): Remove unused arguments.
	* ipa-split.c (execute_split_functions): change guard to the
	newly added class.
	* ipa.c (symbol_table::remove_unreachable_nodes): Likewise.
---
 gcc/ipa-inline-analysis.c | 105 ++++++++++++++++++----------------------------
 gcc/ipa-inline.c          |  18 ++++----
 gcc/ipa-inline.h          |  28 +++++++++----
 gcc/ipa-profile.c         |   2 +-
 gcc/ipa-prop.c            |   7 +---
 gcc/ipa-split.c           |   3 +-
 gcc/ipa.c                 |   2 +-
 7 files changed, 73 insertions(+), 92 deletions(-)

diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index c11dc9c..6ce737f 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)
@@ -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)
@@ -1209,7 +1195,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 +1216,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 +1272,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 +1293,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 +1332,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;
 
@@ -1398,7 +1379,7 @@ dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node,
     }
   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, "",
@@ -2644,7 +2625,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
@@ -2886,7 +2867,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;
@@ -3068,7 +3049,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 +3086,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 +3117,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,
@@ -3401,10 +3382,10 @@ inline_update_callee_summaries (struct cgraph_node *node, int depth)
     {
       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 +3402,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 +3447,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 +3472,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;
 
@@ -3552,7 +3533,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 +3619,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);
@@ -3714,7 +3695,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 ();
@@ -3843,7 +3824,7 @@ 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 =
@@ -3865,7 +3846,7 @@ 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);
@@ -4142,7 +4123,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;
 
@@ -4315,7 +4296,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);
@@ -4411,26 +4392,20 @@ 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));
+  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..fb6d007 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -515,7 +515,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;
@@ -695,7 +695,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)
@@ -745,7 +745,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
   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
+		- 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;
@@ -753,7 +753,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
     }
   else if ((DECL_DECLARED_INLINE_P (callee->decl) || e->count)
 	   && inline_summaries->get (callee)->min_size
-		- inline_edge_summary (e)->call_stmt_size
+		- get_inline_edge_summary (e)->call_stmt_size
 	      > 16 * MAX_INLINE_INSNS_SINGLE)
     {
       e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl)
@@ -1191,7 +1191,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.  */
@@ -2688,9 +2688,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 +2716,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..8a6fd31 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 (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 6d6afb3..2e9c6ff 100644
--- a/gcc/ipa-profile.c
+++ b/gcc/ipa-profile.c
@@ -355,7 +355,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))
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 9750a26..a825643 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -2578,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)
@@ -2727,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
@@ -3336,9 +3336,6 @@ ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
 void
 ipa_free_all_edge_args (void)
 {
-  int i;
-  struct ipa_edge_args *args;
-
   if (!ipa_edge_args_sum)
     return;
 
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index df6572f..05d7967 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1698,8 +1698,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);
 
-- 
2.4.5


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 6/6] Migrate ipa-pure-const to function_summary.
  2015-07-09 11:07 [PATCH 0/6] {function,edge}_summary for IPA passes mliska
                   ` (4 preceding siblings ...)
  2015-07-09 11:08 ` [PATCH 5/6] Port IPA reference to function_summary infrastructure mliska
@ 2015-07-09 11:09 ` mliska
  2015-07-09 17:44   ` Jeff Law
  5 siblings, 1 reply; 24+ messages in thread
From: mliska @ 2015-07-09 11:09 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

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

	* ipa-pure-const.c (struct funct_state_d): New.
	(funct_state_d::default_p): Likewise.
	(has_function_state): Remove.
	(get_function_state): Likewise.
	(set_function_state): Likewise.
	(add_new_function): Rename and port to ::insert.
	(duplicate_node_data): Rename and port to ::duplicate.
	(funct_state_summary_t::duplicate): New function.
	(register_hooks): Remove hook registration.
	(pure_const_generate_summary): Use new data structure.
	(pure_const_write_summary): Likewise.
	(pure_const_read_summary): Likewise.
	(propagate_pure_const): Likewise.
	(propagate_nothrow): Likewise.
	(execute): Remove hook usage.
	(pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
---
 gcc/ipa-pure-const.c | 177 +++++++++++++++++++--------------------------------
 1 file changed, 66 insertions(+), 111 deletions(-)

diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index f0373e6..565083c 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -67,6 +67,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "opts.h"
 #include "varasm.h"
+#include "symbol-summary.h"
 
 /* Lattice values for const and pure functions.  Everything starts out
    being const, then may drop to pure and then neither depending on
@@ -84,6 +85,18 @@ const char *pure_const_names[3] = {"const", "pure", "neither"};
    decl.  */
 struct funct_state_d
 {
+  funct_state_d (): pure_const_state (IPA_NEITHER),
+    state_previously_known (IPA_NEITHER), looping_previously_known (true),
+    looping (true), can_throw (true), can_free (true) {}
+
+  funct_state_d (const funct_state_d &s): pure_const_state (s.pure_const_state),
+    state_previously_known (s.state_previously_known),
+    looping_previously_known (s.looping_previously_known),
+    looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
+
+  /* Return true if the value is default.  */
+  bool default_p ();
+
   /* See above.  */
   enum pure_const_state_e pure_const_state;
   /* What user set here; we can be always sure about this.  */
@@ -105,10 +118,16 @@ struct funct_state_d
   bool can_free;
 };
 
-/* State used when we know nothing about function.  */
-static struct funct_state_d varying_state
-   = { IPA_NEITHER, IPA_NEITHER, true, true, true, true };
-
+bool
+funct_state_d::default_p ()
+{
+  return pure_const_state == IPA_NEITHER
+    && state_previously_known == IPA_NEITHER
+    && looping_previously_known
+    && looping
+    && can_throw
+    && can_free;
+}
 
 typedef struct funct_state_d * funct_state;
 
@@ -116,9 +135,19 @@ typedef struct funct_state_d * funct_state;
    possibility that it may be desirable to move this to the cgraph
    local info.  */
 
-/* Array, indexed by cgraph node uid, of function states.  */
+class funct_state_summary_t: public function_summary <funct_state_d *>
+{
+public:
+  funct_state_summary_t (symbol_table *symtab):
+    function_summary <funct_state_d *> (symtab) {}
 
-static vec<funct_state> funct_state_vec;
+  virtual void insert (cgraph_node *, funct_state_d *state);
+  virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
+			  funct_state_d *src_data,
+			  funct_state_d *dst_data);
+};
+
+static funct_state_summary_t *funct_state_summaries = NULL;
 
 static bool gate_pure_const (void);
 
@@ -150,12 +179,6 @@ public:
 
 private:
   bool init_p;
-
-  /* Holders of ipa cgraph hooks: */
-  struct cgraph_node_hook_list *function_insertion_hook_holder;
-  struct cgraph_2node_hook_list *node_duplication_hook_holder;
-  struct cgraph_node_hook_list *node_removal_hook_holder;
-
 }; // class pass_ipa_pure_const
 
 } // anon namespace
@@ -237,41 +260,6 @@ warn_function_noreturn (tree decl)
 			   true, warned_about, "noreturn");
 }
 
-/* Return true if we have a function state for NODE.  */
-
-static inline bool
-has_function_state (struct cgraph_node *node)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid)
-    return false;
-  return funct_state_vec[node->uid] != NULL;
-}
-
-/* Return the function state from NODE.  */
-
-static inline funct_state
-get_function_state (struct cgraph_node *node)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid
-      || !funct_state_vec[node->uid])
-    /* We might want to put correct previously_known state into varying.  */
-    return &varying_state;
- return funct_state_vec[node->uid];
-}
-
-/* Set the function state S for NODE.  */
-
-static inline void
-set_function_state (struct cgraph_node *node, funct_state s)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid)
-     funct_state_vec.safe_grow_cleared (node->uid + 1);
-  funct_state_vec[node->uid] = s;
-}
-
 /* Check to see if the use (or definition when CHECKING_WRITE is true)
    variable T is legal in a function that is either pure or const.  */
 
@@ -903,9 +891,8 @@ end:
   return l;
 }
 
-/* Called when new function is inserted to callgraph late.  */
-static void
-add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::insert (cgraph_node *node, funct_state_d *state)
 {
  if (node->get_availability () < AVAIL_INTERPOSABLE)
    return;
@@ -915,36 +902,21 @@ add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
      operations.  */
   if (node->get_availability () > AVAIL_INTERPOSABLE
       && opt_for_fn (node->decl, flag_ipa_pure_const))
-    set_function_state (node, analyze_function (node, true));
-}
-
-/* Called when new clone is inserted to callgraph late.  */
-
-static void
-duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
-	 	     void *data ATTRIBUTE_UNUSED)
-{
-  if (has_function_state (src))
     {
-      funct_state l = XNEW (struct funct_state_d);
-      gcc_assert (!has_function_state (dst));
-      memcpy (l, get_function_state (src), sizeof (*l));
-      set_function_state (dst, l);
+      funct_state_d *a = analyze_function (node, true);
+      new (state) funct_state_d (*a);
+      free (a);
     }
 }
 
 /* Called when new clone is inserted to callgraph late.  */
 
-static void
-remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::duplicate (cgraph_node *, cgraph_node *,
+				  funct_state_d *src_data,
+				  funct_state_d *dst_data)
 {
-  if (has_function_state (node))
-    {
-      funct_state l = get_function_state (node);
-      if (l != &varying_state)
-        free (l);
-      set_function_state (node, NULL);
-    }
+  new (dst_data) funct_state_d (*src_data);
 }
 
 \f
@@ -957,12 +929,7 @@ register_hooks (void)
 
   init_p = true;
 
-  node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
-  node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
-  function_insertion_hook_holder =
-      symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
+  funct_state_summaries = new funct_state_summary_t (symtab);
 }
 
 
@@ -986,7 +953,11 @@ pure_const_generate_summary (void)
   FOR_EACH_DEFINED_FUNCTION (node)
     if (node->get_availability () >= AVAIL_INTERPOSABLE
         && opt_for_fn (node->decl, flag_ipa_pure_const))
-      set_function_state (node, analyze_function (node, true));
+      {
+	funct_state_d *a = analyze_function (node, true);
+	new (funct_state_summaries->get (node)) funct_state_d (*a);
+	free (a);
+      }
 }
 
 
@@ -1008,7 +979,8 @@ pure_const_write_summary (void)
        lsei_next_function_in_partition (&lsei))
     {
       node = lsei_cgraph_node (lsei);
-      if (node->definition && has_function_state (node))
+      if (node->definition
+	  && !funct_state_summaries->get (node)->default_p ())
 	count++;
     }
 
@@ -1019,15 +991,13 @@ pure_const_write_summary (void)
        lsei_next_function_in_partition (&lsei))
     {
       node = lsei_cgraph_node (lsei);
-      if (node->definition && has_function_state (node))
+      funct_state_d *fs = funct_state_summaries->get (node);
+      if (node->definition && !fs->default_p ())
 	{
 	  struct bitpack_d bp;
-	  funct_state fs;
 	  int node_ref;
 	  lto_symtab_encoder_t encoder;
 
-	  fs = get_function_state (node);
-
 	  encoder = ob->decl_state->symtab_node_encoder;
 	  node_ref = lto_symtab_encoder_encode (encoder, node);
 	  streamer_write_uhwi_stream (ob->main_stream, node_ref);
@@ -1082,13 +1052,12 @@ pure_const_read_summary (void)
 	      funct_state fs;
 	      lto_symtab_encoder_t encoder;
 
-	      fs = XCNEW (struct funct_state_d);
 	      index = streamer_read_uhwi (ib);
 	      encoder = file_data->symtab_node_encoder;
 	      node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
 									index));
-	      set_function_state (node, fs);
 
+	      fs = funct_state_summaries->get (node);
 	      /* Note that the flags must be read in the opposite
 		 order in which they were written (the bitflags were
 		 pushed into FLAGS).  */
@@ -1216,7 +1185,7 @@ propagate_pure_const (void)
 	  int i;
 	  struct ipa_ref *ref = NULL;
 
-	  funct_state w_l = get_function_state (w);
+	  funct_state w_l = funct_state_summaries->get (w);
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "  Visiting %s/%i state:%s looping %i\n",
 		     w->name (),
@@ -1272,7 +1241,7 @@ propagate_pure_const (void)
 		}
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = get_function_state (y);
+		  funct_state_d *y_l = funct_state_summaries->get (y);
 		  if (dump_file && (dump_flags & TDF_DETAILS))
 		    {
 		      fprintf (dump_file,
@@ -1389,7 +1358,7 @@ propagate_pure_const (void)
       while (w && !can_free)
 	{
 	  struct cgraph_edge *e;
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 
 	  if (w_l->can_free
 	      || w->get_availability () == AVAIL_INTERPOSABLE
@@ -1403,7 +1372,7 @@ propagate_pure_const (void)
 				function_or_virtual_thunk_symbol (&avail);
 
 	      if (avail > AVAIL_INTERPOSABLE)
-		can_free = get_function_state (y)->can_free;
+		can_free = funct_state_summaries->get (y)->can_free;
 	      else
 		can_free = true;
 	    }
@@ -1416,7 +1385,7 @@ propagate_pure_const (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 	  enum pure_const_state_e this_state = pure_const_state;
 	  bool this_looping = looping;
 
@@ -1526,7 +1495,7 @@ propagate_nothrow (void)
       while (w && !can_throw)
 	{
 	  struct cgraph_edge *e, *ie;
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 
 	  if (w_l->can_throw
 	      || w->get_availability () == AVAIL_INTERPOSABLE)
@@ -1540,7 +1509,7 @@ propagate_nothrow (void)
 
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = get_function_state (y);
+		  funct_state_d *y_l = funct_state_summaries->get (y);
 
 		  if (y_l->can_throw && !TREE_NOTHROW (w->decl)
 		      && e->can_throw_external)
@@ -1561,7 +1530,7 @@ propagate_nothrow (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 	  if (!can_throw && !TREE_NOTHROW (w->decl))
 	    {
 	      /* Inline clones share declaration with their offline copies;
@@ -1594,23 +1563,14 @@ unsigned int
 pass_ipa_pure_const::
 execute (function *)
 {
-  struct cgraph_node *node;
   bool remove_p;
 
-  symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
-  symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
-  symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
-
   /* Nothrow makes more function to not lead to return and improve
      later analysis.  */
   propagate_nothrow ();
   remove_p = propagate_pure_const ();
 
-  /* Cleanup. */
-  FOR_EACH_FUNCTION (node)
-    if (has_function_state (node))
-      free (get_function_state (node));
-  funct_state_vec.release ();
+  delete funct_state_summaries;
   return remove_p ? TODO_remove_functions : 0;
 }
 
@@ -1631,12 +1591,7 @@ pass_ipa_pure_const::pass_ipa_pure_const(gcc::context *ctxt)
 		     0, /* function_transform_todo_flags_start */
 		     NULL, /* function_transform */
 		     NULL), /* variable_transform */
-  init_p(false),
-  function_insertion_hook_holder(NULL),
-  node_duplication_hook_holder(NULL),
-  node_removal_hook_holder(NULL)
-{
-}
+  init_p (false) {}
 
 ipa_opt_pass_d *
 make_pass_ipa_pure_const (gcc::context *ctxt)
-- 
2.4.5

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/6] hash_set: add iterator and remove method.
  2015-07-09 11:07 ` [PATCH 1/6] hash_set: add iterator and remove method mliska
@ 2015-07-09 17:05   ` Jeff Law
  0 siblings, 0 replies; 24+ messages in thread
From: Jeff Law @ 2015-07-09 17:05 UTC (permalink / raw)
  To: mliska, gcc-patches

On 07/09/2015 03:13 AM, mliska wrote:
> gcc/ChangeLog:
>
> 2015-07-03  Martin Liska  <mliska@suse.cz>
>
> 	* hash-set.h (remove): New function.
> 	(iterator): New iteration class for hash_set.
OK.
jeff

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum.
  2015-07-09 11:08 ` [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum mliska
@ 2015-07-09 17:15   ` Jeff Law
  2015-07-09 20:45     ` Martin Liška
  2015-07-10 13:31   ` Martin Jambor
  1 sibling, 1 reply; 24+ messages in thread
From: Jeff Law @ 2015-07-09 17:15 UTC (permalink / raw)
  To: mliska, gcc-patches

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


OK for the trunk.

Thanks,
Jeff

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/6] IPA inline: port inline_edge_summary to a new infrastructure.
  2015-07-09 11:08 ` [PATCH 3/6] IPA inline: port inline_edge_summary to a new infrastructure mliska
@ 2015-07-09 17:21   ` Jeff Law
  0 siblings, 0 replies; 24+ messages in thread
From: Jeff Law @ 2015-07-09 17:21 UTC (permalink / raw)
  To: mliska, gcc-patches

On 07/09/2015 03:13 AM, mliska wrote:
> gcc/ChangeLog:
>
> 2015-07-03  Martin Liska  <mliska@suse.cz>
>
> 	* ipa-inline-analysis.c
> 	(inline_edge_summaries): New data structure.
> 	(redirect_to_unreachable): Use renamed
> 	function get_inline_edge_summary.
> 	(edge_set_predicate): Likewise.
> 	(evaluate_properties_for_edge): Likewise.
> 	(reset_inline_edge_summary): Likewise.
> 	(inline_summary_t::duplicate): New function.
> 	(inline_edge_summary_t::duplicate): Likewise.
> 	(dump_inline_edge_summary): Use renamed function
> 	get_inline_edge_summary.
> 	(estimate_function_body_sizes): Likewise.
> 	(compute_inline_parameters): Likewise.
> 	(estimate_edge_size_and_time): Likewise.
> 	(estimate_calls_size_and_time): Likewise.
> 	(inline_update_callee_summaries): Likewise.
> 	(remap_edge_change_prob): Likewise.
> 	(remap_edge_summaries): Likewise.
> 	(inline_merge_summary): Likewise.
> 	(do_estimate_edge_time): Likewise.
> 	(estimate_time_after_inlining): Likewise.
> 	(estimate_size_after_inlining): Likewise.
> 	(read_inline_edge_summary): Likewise.
> 	(write_inline_edge_summary): Likewise.
> 	(inline_summary_alloc): Remove symtab hook holders.
> 	(inline_free_summary): Likewise.
> 	* ipa-inline.c (can_inline_edge_p): Use get_inline_edge_summary.
> 	(compute_inlined_call_time): Likewise.
> 	(want_inline_small_function_p): Likewise.
> 	(edge_badness): Likewise.
> 	(early_inliner): Likewise.
> 	* ipa-inline.h (get_inline_edge_summary): Renamed from
> 	inline_edge_summary.
> 	(estimate_edge_growth): Use the function.
> 	* ipa-profile.c (ipa_propagate_frequency_1): Likewise.
> 	* ipa-prop.c (ipa_make_edge_direct_to_target): Likewise.
> 	(ipa_free_all_edge_args): Remove unused arguments.
> 	* ipa-split.c (execute_split_functions): change guard to the
> 	newly added class.
> 	* ipa.c (symbol_table::remove_unreachable_nodes): Likewise.
> ---
>   gcc/ipa-inline-analysis.c | 105 ++++++++++++++++++----------------------------
>   gcc/ipa-inline.c          |  18 ++++----
>   gcc/ipa-inline.h          |  28 +++++++++----
>   gcc/ipa-profile.c         |   2 +-
>   gcc/ipa-prop.c            |   7 +---
>   gcc/ipa-split.c           |   3 +-
>   gcc/ipa.c                 |   2 +-
>   7 files changed, 73 insertions(+), 92 deletions(-)
OK.  FWIW, it might have been easier to have the renaming as a separate 
patch given it was so mechanical.

Jeff

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5/6] Port IPA reference to function_summary infrastructure.
  2015-07-09 11:08 ` [PATCH 5/6] Port IPA reference to function_summary infrastructure mliska
@ 2015-07-09 17:35   ` Jeff Law
  2015-07-09 20:46     ` Martin Liška
  2015-07-10 13:30   ` Martin Jambor
  1 sibling, 1 reply; 24+ messages in thread
From: Jeff Law @ 2015-07-09 17:35 UTC (permalink / raw)
  To: mliska, gcc-patches

On 07/09/2015 03:13 AM, mliska wrote:
> gcc/ChangeLog:
>
> 2015-07-03  Martin Liska  <mliska@suse.cz>
>
> 	* ipa-reference.c (ipa_ref_opt_summary_t): New class.
> 	(get_reference_optimization_summary): Use it.
> 	(set_reference_optimization_summary): Likewise.
> 	(ipa_init): Remove hook holders usage.
> 	(ipa_reference_c_finalize): Likewise.
> 	(ipa_ref_opt_summary_t::duplicate): New function.
> 	(ipa_ref_opt_summary_t::remove): Likewise.
> 	(propagate): Allocate the summary if does not exist.
> 	(ipa_reference_read_optimization_summary): Likewise.
> 	(struct ipa_reference_vars_info_d): Add new method.
> 	(struct ipa_reference_optimization_summary_d): Likewise.
> 	(get_reference_vars_info): Use new underlying container.
> 	(set_reference_vars_info): Remove.
> 	(init_function_info): Set up the container.

> @@ -89,6 +84,13 @@ struct ipa_reference_global_vars_info_d
>
>   struct ipa_reference_optimization_summary_d
>   {
> +  /* Return true if the data structure is empty.  */
> +  inline bool
> +  empty_p ()
> +  {
> +    return statics_not_read == NULL && statics_not_written == NULL;
> +  }
> +
Presumably this is still POD, even with the inline function, so "struct" 
is still correct, right?



> @@ -99,6 +101,14 @@ typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_
>
>   struct ipa_reference_vars_info_d
>   {
> +  /* Return true if the data structure is empty.  */
> +  inline bool
> +  empty_p ()
> +  {
> +    return local.statics_read == NULL && local.statics_written == NULL
> +      && global.statics_read == NULL && global.statics_written == NULL;
> +  }
> +
Similarly.

So please confirm those are still POD types.  If they are, then the 
patch is OK as-is.  If they're not PODs, then change them to classes and 
that patch is pre-approved.

jeff

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 4/6] Port ipa-cp to use cgraph_edge summary.
  2015-07-09 11:08 ` [PATCH 4/6] Port ipa-cp to use cgraph_edge summary mliska
@ 2015-07-09 17:39   ` Jeff Law
  2015-07-10 14:18   ` Martin Jambor
  1 sibling, 0 replies; 24+ messages in thread
From: Jeff Law @ 2015-07-09 17:39 UTC (permalink / raw)
  To: mliska, gcc-patches

On 07/09/2015 03:13 AM, mliska wrote:
> gcc/ChangeLog:
>
> 2015-07-03  Martin Liska  <mliska@suse.cz>
>
> 	* ipa-cp.c (struct edge_clone_summary): New structure.
> 	(class edge_clone_summary_t): Likewise.
> 	(edge_clone_summary_t::initialize): New method.
> 	(edge_clone_summary_t::duplicate): Likewise.
> 	(get_next_cgraph_edge_clone): Remove.
> 	(get_info_about_necessary_edges): Refactor using the new
> 	data structure.
> 	(gather_edges_for_value): Likewise.
> 	(perhaps_add_new_callers): Likewise.
> 	(ipcp_driver): Allocate and deallocate newly added
> 	instance.
> ---
OK.
Jeff


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 6/6] Migrate ipa-pure-const to function_summary.
  2015-07-09 11:09 ` [PATCH 6/6] Migrate ipa-pure-const to function_summary mliska
@ 2015-07-09 17:44   ` Jeff Law
  2015-07-09 20:47     ` Martin Liška
  0 siblings, 1 reply; 24+ messages in thread
From: Jeff Law @ 2015-07-09 17:44 UTC (permalink / raw)
  To: mliska, gcc-patches

On 07/09/2015 03:13 AM, mliska wrote:
> gcc/ChangeLog:
>
> 2015-07-03  Martin Liska  <mliska@suse.cz>
>
> 	* ipa-pure-const.c (struct funct_state_d): New.
> 	(funct_state_d::default_p): Likewise.
> 	(has_function_state): Remove.
> 	(get_function_state): Likewise.
> 	(set_function_state): Likewise.
> 	(add_new_function): Rename and port to ::insert.
> 	(duplicate_node_data): Rename and port to ::duplicate.
> 	(funct_state_summary_t::duplicate): New function.
> 	(register_hooks): Remove hook registration.
> 	(pure_const_generate_summary): Use new data structure.
> 	(pure_const_write_summary): Likewise.
> 	(pure_const_read_summary): Likewise.
> 	(propagate_pure_const): Likewise.
> 	(propagate_nothrow): Likewise.
> 	(execute): Remove hook usage.
> 	(pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
> ---
> @@ -84,6 +85,18 @@ const char *pure_const_names[3] = {"const", "pure", "neither"};
>      decl.  */
>   struct funct_state_d
>   {
> +  funct_state_d (): pure_const_state (IPA_NEITHER),
> +    state_previously_known (IPA_NEITHER), looping_previously_known (true),
> +    looping (true), can_throw (true), can_free (true) {}
> +
> +  funct_state_d (const funct_state_d &s): pure_const_state (s.pure_const_state),
> +    state_previously_known (s.state_previously_known),
> +    looping_previously_known (s.looping_previously_known),
> +    looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
> +
> +  /* Return true if the value is default.  */
> +  bool default_p ();
> +
>     /* See above.  */
>     enum pure_const_state_e pure_const_state;
>     /* What user set here; we can be always sure about this.  */
Doesn't this need to be a "class" rather then a "struct"?


OK with that change.

jeff

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum.
  2015-07-09 17:15   ` Jeff Law
@ 2015-07-09 20:45     ` Martin Liška
  0 siblings, 0 replies; 24+ messages in thread
From: Martin Liška @ 2015-07-09 20:45 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1716 bytes --]

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

Hi.

Should be 'GGC', fixed in attached patch.

Thanks,
Martin

>
>
> OK for the trunk.
>
> Thanks,
> Jeff


[-- Attachment #2: 0002-Introduce-new-edge_summary-class-and-replace-ipa_edg.patch --]
[-- Type: text/x-patch, Size: 18234 bytes --]

From 86a698b6fe9a0bbb55a0e2fa090d74cb02677d2f Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Thu, 9 Jul 2015 11:13:52 +0200
Subject: [PATCH 2/6] Introduce new edge_summary class and replace
 ipa_edge_args_sum.

gcc/ChangeLog:

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

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

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


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5/6] Port IPA reference to function_summary infrastructure.
  2015-07-09 17:35   ` Jeff Law
@ 2015-07-09 20:46     ` Martin Liška
  0 siblings, 0 replies; 24+ messages in thread
From: Martin Liška @ 2015-07-09 20:46 UTC (permalink / raw)
  To: gcc-patches

On 07/09/2015 07:35 PM, Jeff Law wrote:
> On 07/09/2015 03:13 AM, mliska wrote:
>> gcc/ChangeLog:
>>
>> 2015-07-03  Martin Liska  <mliska@suse.cz>
>>
>>     * ipa-reference.c (ipa_ref_opt_summary_t): New class.
>>     (get_reference_optimization_summary): Use it.
>>     (set_reference_optimization_summary): Likewise.
>>     (ipa_init): Remove hook holders usage.
>>     (ipa_reference_c_finalize): Likewise.
>>     (ipa_ref_opt_summary_t::duplicate): New function.
>>     (ipa_ref_opt_summary_t::remove): Likewise.
>>     (propagate): Allocate the summary if does not exist.
>>     (ipa_reference_read_optimization_summary): Likewise.
>>     (struct ipa_reference_vars_info_d): Add new method.
>>     (struct ipa_reference_optimization_summary_d): Likewise.
>>     (get_reference_vars_info): Use new underlying container.
>>     (set_reference_vars_info): Remove.
>>     (init_function_info): Set up the container.
>
>> @@ -89,6 +84,13 @@ struct ipa_reference_global_vars_info_d
>>
>>   struct ipa_reference_optimization_summary_d
>>   {
>> +  /* Return true if the data structure is empty.  */
>> +  inline bool
>> +  empty_p ()
>> +  {
>> +    return statics_not_read == NULL && statics_not_written == NULL;
>> +  }
>> +
> Presumably this is still POD, even with the inline function, so "struct" is still correct, right?
>
>
>
>> @@ -99,6 +101,14 @@ typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_
>>
>>   struct ipa_reference_vars_info_d
>>   {
>> +  /* Return true if the data structure is empty.  */
>> +  inline bool
>> +  empty_p ()
>> +  {
>> +    return local.statics_read == NULL && local.statics_written == NULL
>> +      && global.statics_read == NULL && global.statics_written == NULL;
>> +  }
>> +
> Similarly.
>
> So please confirm those are still POD types.  If they are, then the patch is OK as-is.  If they're not PODs, then change them to classes and that patch is pre-approved.
>
> jeff
>

Hi.

Yes, that are POD types.

Martin

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 6/6] Migrate ipa-pure-const to function_summary.
  2015-07-09 17:44   ` Jeff Law
@ 2015-07-09 20:47     ` Martin Liška
  2015-07-16 14:17       ` Martin Liška
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Liška @ 2015-07-09 20:47 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2027 bytes --]

On 07/09/2015 07:44 PM, Jeff Law wrote:
> On 07/09/2015 03:13 AM, mliska wrote:
>> gcc/ChangeLog:
>>
>> 2015-07-03  Martin Liska  <mliska@suse.cz>
>>
>>     * ipa-pure-const.c (struct funct_state_d): New.
>>     (funct_state_d::default_p): Likewise.
>>     (has_function_state): Remove.
>>     (get_function_state): Likewise.
>>     (set_function_state): Likewise.
>>     (add_new_function): Rename and port to ::insert.
>>     (duplicate_node_data): Rename and port to ::duplicate.
>>     (funct_state_summary_t::duplicate): New function.
>>     (register_hooks): Remove hook registration.
>>     (pure_const_generate_summary): Use new data structure.
>>     (pure_const_write_summary): Likewise.
>>     (pure_const_read_summary): Likewise.
>>     (propagate_pure_const): Likewise.
>>     (propagate_nothrow): Likewise.
>>     (execute): Remove hook usage.
>>     (pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
>> ---
>> @@ -84,6 +85,18 @@ const char *pure_const_names[3] = {"const", "pure", "neither"};
>>      decl.  */
>>   struct funct_state_d
>>   {
>> +  funct_state_d (): pure_const_state (IPA_NEITHER),
>> +    state_previously_known (IPA_NEITHER), looping_previously_known (true),
>> +    looping (true), can_throw (true), can_free (true) {}
>> +
>> +  funct_state_d (const funct_state_d &s): pure_const_state (s.pure_const_state),
>> +    state_previously_known (s.state_previously_known),
>> +    looping_previously_known (s.looping_previously_known),
>> +    looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
>> +
>> +  /* Return true if the value is default.  */
>> +  bool default_p ();
>> +
>>     /* See above.  */
>>     enum pure_const_state_e pure_const_state;
>>     /* What user set here; we can be always sure about this.  */
> Doesn't this need to be a "class" rather then a "struct"?
>
>
> OK with that change.
>
> jeff

Yeah.

'class' will be more appropriate. As I'm going to be AFK for Friday and upcoming weekend,
I will install these patches on Monday.

Thanks,
Martin

[-- Attachment #2: 0006-Migrate-ipa-pure-const-to-function_summary.patch --]
[-- Type: text/x-patch, Size: 12960 bytes --]

From b20c6ceaf82210c564465be1ab92f6586fc706e4 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Thu, 9 Jul 2015 11:13:55 +0200
Subject: [PATCH 6/6] Migrate ipa-pure-const to function_summary.

gcc/ChangeLog:

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

	* ipa-pure-const.c (struct funct_state_d): New.
	(funct_state_d::default_p): Likewise.
	(has_function_state): Remove.
	(get_function_state): Likewise.
	(set_function_state): Likewise.
	(add_new_function): Rename and port to ::insert.
	(duplicate_node_data): Rename and port to ::duplicate.
	(funct_state_summary_t::duplicate): New function.
	(register_hooks): Remove hook registration.
	(pure_const_generate_summary): Use new data structure.
	(pure_const_write_summary): Likewise.
	(pure_const_read_summary): Likewise.
	(propagate_pure_const): Likewise.
	(propagate_nothrow): Likewise.
	(execute): Remove hook usage.
	(pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
---
 gcc/ipa-pure-const.c | 180 +++++++++++++++++++--------------------------------
 1 file changed, 68 insertions(+), 112 deletions(-)

diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index f0373e6..f978950f 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -67,6 +67,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "opts.h"
 #include "varasm.h"
+#include "symbol-summary.h"
 
 /* Lattice values for const and pure functions.  Everything starts out
    being const, then may drop to pure and then neither depending on
@@ -82,8 +83,21 @@ const char *pure_const_names[3] = {"const", "pure", "neither"};
 
 /* Holder for the const_state.  There is one of these per function
    decl.  */
-struct funct_state_d
+class funct_state_d
 {
+public:
+  funct_state_d (): pure_const_state (IPA_NEITHER),
+    state_previously_known (IPA_NEITHER), looping_previously_known (true),
+    looping (true), can_throw (true), can_free (true) {}
+
+  funct_state_d (const funct_state_d &s): pure_const_state (s.pure_const_state),
+    state_previously_known (s.state_previously_known),
+    looping_previously_known (s.looping_previously_known),
+    looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
+
+  /* Return true if the value is default.  */
+  bool default_p ();
+
   /* See above.  */
   enum pure_const_state_e pure_const_state;
   /* What user set here; we can be always sure about this.  */
@@ -105,10 +119,16 @@ struct funct_state_d
   bool can_free;
 };
 
-/* State used when we know nothing about function.  */
-static struct funct_state_d varying_state
-   = { IPA_NEITHER, IPA_NEITHER, true, true, true, true };
-
+bool
+funct_state_d::default_p ()
+{
+  return pure_const_state == IPA_NEITHER
+    && state_previously_known == IPA_NEITHER
+    && looping_previously_known
+    && looping
+    && can_throw
+    && can_free;
+}
 
 typedef struct funct_state_d * funct_state;
 
@@ -116,9 +136,19 @@ typedef struct funct_state_d * funct_state;
    possibility that it may be desirable to move this to the cgraph
    local info.  */
 
-/* Array, indexed by cgraph node uid, of function states.  */
+class funct_state_summary_t: public function_summary <funct_state_d *>
+{
+public:
+  funct_state_summary_t (symbol_table *symtab):
+    function_summary <funct_state_d *> (symtab) {}
+
+  virtual void insert (cgraph_node *, funct_state_d *state);
+  virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
+			  funct_state_d *src_data,
+			  funct_state_d *dst_data);
+};
 
-static vec<funct_state> funct_state_vec;
+static funct_state_summary_t *funct_state_summaries = NULL;
 
 static bool gate_pure_const (void);
 
@@ -150,12 +180,6 @@ public:
 
 private:
   bool init_p;
-
-  /* Holders of ipa cgraph hooks: */
-  struct cgraph_node_hook_list *function_insertion_hook_holder;
-  struct cgraph_2node_hook_list *node_duplication_hook_holder;
-  struct cgraph_node_hook_list *node_removal_hook_holder;
-
 }; // class pass_ipa_pure_const
 
 } // anon namespace
@@ -237,41 +261,6 @@ warn_function_noreturn (tree decl)
 			   true, warned_about, "noreturn");
 }
 
-/* Return true if we have a function state for NODE.  */
-
-static inline bool
-has_function_state (struct cgraph_node *node)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid)
-    return false;
-  return funct_state_vec[node->uid] != NULL;
-}
-
-/* Return the function state from NODE.  */
-
-static inline funct_state
-get_function_state (struct cgraph_node *node)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid
-      || !funct_state_vec[node->uid])
-    /* We might want to put correct previously_known state into varying.  */
-    return &varying_state;
- return funct_state_vec[node->uid];
-}
-
-/* Set the function state S for NODE.  */
-
-static inline void
-set_function_state (struct cgraph_node *node, funct_state s)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid)
-     funct_state_vec.safe_grow_cleared (node->uid + 1);
-  funct_state_vec[node->uid] = s;
-}
-
 /* Check to see if the use (or definition when CHECKING_WRITE is true)
    variable T is legal in a function that is either pure or const.  */
 
@@ -903,9 +892,8 @@ end:
   return l;
 }
 
-/* Called when new function is inserted to callgraph late.  */
-static void
-add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::insert (cgraph_node *node, funct_state_d *state)
 {
  if (node->get_availability () < AVAIL_INTERPOSABLE)
    return;
@@ -915,36 +903,21 @@ add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
      operations.  */
   if (node->get_availability () > AVAIL_INTERPOSABLE
       && opt_for_fn (node->decl, flag_ipa_pure_const))
-    set_function_state (node, analyze_function (node, true));
-}
-
-/* Called when new clone is inserted to callgraph late.  */
-
-static void
-duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
-	 	     void *data ATTRIBUTE_UNUSED)
-{
-  if (has_function_state (src))
     {
-      funct_state l = XNEW (struct funct_state_d);
-      gcc_assert (!has_function_state (dst));
-      memcpy (l, get_function_state (src), sizeof (*l));
-      set_function_state (dst, l);
+      funct_state_d *a = analyze_function (node, true);
+      new (state) funct_state_d (*a);
+      free (a);
     }
 }
 
 /* Called when new clone is inserted to callgraph late.  */
 
-static void
-remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::duplicate (cgraph_node *, cgraph_node *,
+				  funct_state_d *src_data,
+				  funct_state_d *dst_data)
 {
-  if (has_function_state (node))
-    {
-      funct_state l = get_function_state (node);
-      if (l != &varying_state)
-        free (l);
-      set_function_state (node, NULL);
-    }
+  new (dst_data) funct_state_d (*src_data);
 }
 
 \f
@@ -957,12 +930,7 @@ register_hooks (void)
 
   init_p = true;
 
-  node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
-  node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
-  function_insertion_hook_holder =
-      symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
+  funct_state_summaries = new funct_state_summary_t (symtab);
 }
 
 
@@ -986,7 +954,11 @@ pure_const_generate_summary (void)
   FOR_EACH_DEFINED_FUNCTION (node)
     if (node->get_availability () >= AVAIL_INTERPOSABLE
         && opt_for_fn (node->decl, flag_ipa_pure_const))
-      set_function_state (node, analyze_function (node, true));
+      {
+	funct_state_d *a = analyze_function (node, true);
+	new (funct_state_summaries->get (node)) funct_state_d (*a);
+	free (a);
+      }
 }
 
 
@@ -1008,7 +980,8 @@ pure_const_write_summary (void)
        lsei_next_function_in_partition (&lsei))
     {
       node = lsei_cgraph_node (lsei);
-      if (node->definition && has_function_state (node))
+      if (node->definition
+	  && !funct_state_summaries->get (node)->default_p ())
 	count++;
     }
 
@@ -1019,15 +992,13 @@ pure_const_write_summary (void)
        lsei_next_function_in_partition (&lsei))
     {
       node = lsei_cgraph_node (lsei);
-      if (node->definition && has_function_state (node))
+      funct_state_d *fs = funct_state_summaries->get (node);
+      if (node->definition && !fs->default_p ())
 	{
 	  struct bitpack_d bp;
-	  funct_state fs;
 	  int node_ref;
 	  lto_symtab_encoder_t encoder;
 
-	  fs = get_function_state (node);
-
 	  encoder = ob->decl_state->symtab_node_encoder;
 	  node_ref = lto_symtab_encoder_encode (encoder, node);
 	  streamer_write_uhwi_stream (ob->main_stream, node_ref);
@@ -1082,13 +1053,12 @@ pure_const_read_summary (void)
 	      funct_state fs;
 	      lto_symtab_encoder_t encoder;
 
-	      fs = XCNEW (struct funct_state_d);
 	      index = streamer_read_uhwi (ib);
 	      encoder = file_data->symtab_node_encoder;
 	      node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
 									index));
-	      set_function_state (node, fs);
 
+	      fs = funct_state_summaries->get (node);
 	      /* Note that the flags must be read in the opposite
 		 order in which they were written (the bitflags were
 		 pushed into FLAGS).  */
@@ -1216,7 +1186,7 @@ propagate_pure_const (void)
 	  int i;
 	  struct ipa_ref *ref = NULL;
 
-	  funct_state w_l = get_function_state (w);
+	  funct_state w_l = funct_state_summaries->get (w);
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "  Visiting %s/%i state:%s looping %i\n",
 		     w->name (),
@@ -1272,7 +1242,7 @@ propagate_pure_const (void)
 		}
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = get_function_state (y);
+		  funct_state_d *y_l = funct_state_summaries->get (y);
 		  if (dump_file && (dump_flags & TDF_DETAILS))
 		    {
 		      fprintf (dump_file,
@@ -1389,7 +1359,7 @@ propagate_pure_const (void)
       while (w && !can_free)
 	{
 	  struct cgraph_edge *e;
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 
 	  if (w_l->can_free
 	      || w->get_availability () == AVAIL_INTERPOSABLE
@@ -1403,7 +1373,7 @@ propagate_pure_const (void)
 				function_or_virtual_thunk_symbol (&avail);
 
 	      if (avail > AVAIL_INTERPOSABLE)
-		can_free = get_function_state (y)->can_free;
+		can_free = funct_state_summaries->get (y)->can_free;
 	      else
 		can_free = true;
 	    }
@@ -1416,7 +1386,7 @@ propagate_pure_const (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 	  enum pure_const_state_e this_state = pure_const_state;
 	  bool this_looping = looping;
 
@@ -1526,7 +1496,7 @@ propagate_nothrow (void)
       while (w && !can_throw)
 	{
 	  struct cgraph_edge *e, *ie;
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 
 	  if (w_l->can_throw
 	      || w->get_availability () == AVAIL_INTERPOSABLE)
@@ -1540,7 +1510,7 @@ propagate_nothrow (void)
 
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = get_function_state (y);
+		  funct_state_d *y_l = funct_state_summaries->get (y);
 
 		  if (y_l->can_throw && !TREE_NOTHROW (w->decl)
 		      && e->can_throw_external)
@@ -1561,7 +1531,7 @@ propagate_nothrow (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get (w);
 	  if (!can_throw && !TREE_NOTHROW (w->decl))
 	    {
 	      /* Inline clones share declaration with their offline copies;
@@ -1594,23 +1564,14 @@ unsigned int
 pass_ipa_pure_const::
 execute (function *)
 {
-  struct cgraph_node *node;
   bool remove_p;
 
-  symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
-  symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
-  symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
-
   /* Nothrow makes more function to not lead to return and improve
      later analysis.  */
   propagate_nothrow ();
   remove_p = propagate_pure_const ();
 
-  /* Cleanup. */
-  FOR_EACH_FUNCTION (node)
-    if (has_function_state (node))
-      free (get_function_state (node));
-  funct_state_vec.release ();
+  delete funct_state_summaries;
   return remove_p ? TODO_remove_functions : 0;
 }
 
@@ -1631,12 +1592,7 @@ pass_ipa_pure_const::pass_ipa_pure_const(gcc::context *ctxt)
 		     0, /* function_transform_todo_flags_start */
 		     NULL, /* function_transform */
 		     NULL), /* variable_transform */
-  init_p(false),
-  function_insertion_hook_holder(NULL),
-  node_duplication_hook_holder(NULL),
-  node_removal_hook_holder(NULL)
-{
-}
+  init_p (false) {}
 
 ipa_opt_pass_d *
 make_pass_ipa_pure_const (gcc::context *ctxt)
-- 
2.4.5


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5/6] Port IPA reference to function_summary infrastructure.
  2015-07-09 11:08 ` [PATCH 5/6] Port IPA reference to function_summary infrastructure mliska
  2015-07-09 17:35   ` Jeff Law
@ 2015-07-10 13:30   ` Martin Jambor
  2015-07-16 14:14     ` Martin Liška
  1 sibling, 1 reply; 24+ messages in thread
From: Martin Jambor @ 2015-07-10 13:30 UTC (permalink / raw)
  To: mliska; +Cc: gcc-patches

Hi,

I've spotted a likely typo:

On Thu, Jul 09, 2015 at 11:13:53AM +0200, Martin Liska wrote:
> gcc/ChangeLog:
> 
> 2015-07-03  Martin Liska  <mliska@suse.cz>
> 
> 	* ipa-reference.c (ipa_ref_opt_summary_t): New class.
> 	(get_reference_optimization_summary): Use it.
> 	(set_reference_optimization_summary): Likewise.
> 	(ipa_init): Remove hook holders usage.
> 	(ipa_reference_c_finalize): Likewise.
> 	(ipa_ref_opt_summary_t::duplicate): New function.
> 	(ipa_ref_opt_summary_t::remove): Likewise.
> 	(propagate): Allocate the summary if does not exist.
> 	(ipa_reference_read_optimization_summary): Likewise.
> 	(struct ipa_reference_vars_info_d): Add new method.
> 	(struct ipa_reference_optimization_summary_d): Likewise.
> 	(get_reference_vars_info): Use new underlying container.
> 	(set_reference_vars_info): Remove.
> 	(init_function_info): Set up the container.
> ---
>  gcc/ipa-reference.c | 203 ++++++++++++++++++++++++++--------------------------
>  1 file changed, 102 insertions(+), 101 deletions(-)
> 
> diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
> index 465a74b..2afd9ad 100644
> --- a/gcc/ipa-reference.c
> +++ b/gcc/ipa-reference.c

...

> @@ -837,12 +839,14 @@ propagate (void)
>  	}
>      }
>  
> +  if (ipa_ref_opt_sum_summaries == NULL)
> +    ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
> +
>    /* Cleanup. */
>    FOR_EACH_DEFINED_FUNCTION (node)
>      {
>        ipa_reference_vars_info_t node_info;
>        ipa_reference_global_vars_info_t node_g;
> -      ipa_reference_optimization_summary_t opt;
>  
>        node_info = get_reference_vars_info (node);
>        if (!node->alias && opt_for_fn (node->decl, flag_ipa_reference)
> @@ -851,8 +855,8 @@ propagate (void)
>  	{
>  	  node_g = &node_info->global;
>  
> -	  opt = XCNEW (struct ipa_reference_optimization_summary_d);
> -	  set_reference_optimization_summary (node, opt);
> +	  ipa_reference_optimization_summary_d *opt =
> +	    ipa_ref_opt_sum_summaries->get (node);
>  
>  	  /* Create the complimentary sets.  */
>  
> @@ -880,14 +884,20 @@ propagate (void)
>  				  node_g->statics_written);
>  	    }
>  	}
> -      free (node_info);
>     }
>  
>    ipa_free_postorder_info ();
>    free (order);
>  
>    bitmap_obstack_release (&local_info_obstack);
> -  ipa_reference_vars_vector.release ();
> +
> +  if (ipa_ref_var_info_summaries == NULL)

I assume you meant != NULL here.

> +    {
> +      delete ipa_ref_var_info_summaries;
> +      ipa_ref_var_info_summaries = NULL;
> +    }
> +
> +  ipa_ref_var_info_summaries = NULL;
>    if (dump_file)
>      splay_tree_delete (reference_vars_to_consider);
>    reference_vars_to_consider = NULL;

Thanks,

Martin

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum.
  2015-07-09 11:08 ` [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum mliska
  2015-07-09 17:15   ` Jeff Law
@ 2015-07-10 13:31   ` Martin Jambor
  2015-07-16 14:06     ` Martin Liška
  1 sibling, 1 reply; 24+ messages in thread
From: Martin Jambor @ 2015-07-10 13:31 UTC (permalink / raw)
  To: mliska; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 4/6] Port ipa-cp to use cgraph_edge summary.
  2015-07-09 11:08 ` [PATCH 4/6] Port ipa-cp to use cgraph_edge summary mliska
  2015-07-09 17:39   ` Jeff Law
@ 2015-07-10 14:18   ` Martin Jambor
  2015-07-16 14:08     ` Martin Liška
  1 sibling, 1 reply; 24+ messages in thread
From: Martin Jambor @ 2015-07-10 14:18 UTC (permalink / raw)
  To: mliska; +Cc: gcc-patches

Hi,

I know the patch has been approved by Jeff, but please do not commit
it before considering the following:

On Thu, Jul 09, 2015 at 11:13:53AM +0200, Martin Liska wrote:
> gcc/ChangeLog:
> 
> 2015-07-03  Martin Liska  <mliska@suse.cz>
> 
> 	* ipa-cp.c (struct edge_clone_summary): New structure.
> 	(class edge_clone_summary_t): Likewise.
> 	(edge_clone_summary_t::initialize): New method.
> 	(edge_clone_summary_t::duplicate): Likewise.
> 	(get_next_cgraph_edge_clone): Remove.
> 	(get_info_about_necessary_edges): Refactor using the new
> 	data structure.
> 	(gather_edges_for_value): Likewise.
> 	(perhaps_add_new_callers): Likewise.
> 	(ipcp_driver): Allocate and deallocate newly added
> 	instance.
> ---
>  gcc/ipa-cp.c | 198 ++++++++++++++++++++++++++++++++++-------------------------
>  1 file changed, 113 insertions(+), 85 deletions(-)
> 
> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
> index 16b9cde..8a50b63 100644
> --- a/gcc/ipa-cp.c
> +++ b/gcc/ipa-cp.c
> @@ -2888,54 +2888,79 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
>      inline_update_overall_summary (node);
>  }
>  
> -/* Vector of pointers which for linked lists of clones of an original crgaph
> -   edge. */
> +/* Edge clone summary.  */
>  
> -static vec<cgraph_edge *> next_edge_clone;
> -static vec<cgraph_edge *> prev_edge_clone;
> -
> -static inline void
> -grow_edge_clone_vectors (void)
> +struct edge_clone_summary

I's got constructors and destructors so it should be a class, reaally.

>  {
> -  if (next_edge_clone.length ()
> -      <=  (unsigned) symtab->edges_max_uid)
> -    next_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
> -  if (prev_edge_clone.length ()
> -      <=  (unsigned) symtab->edges_max_uid)
> -    prev_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
> -}
> +  /* Default constructor.  */
> +  edge_clone_summary (): edge_set (NULL), edge (NULL) {}
>  
> -/* Edge duplication hook to grow the appropriate linked list in
> -   next_edge_clone. */
> +  /* Default destructor.  */
> +  ~edge_clone_summary ()
> +  {
> +    gcc_assert (edge_set != NULL);
>  
> -static void
> -ipcp_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
> -			    void *)
> +    if (edge != NULL)
> +      {
> +	gcc_checking_assert (edge_set->contains (edge));
> +	edge_set->remove (edge);
> +      }
> +
> +    /* Release memory for an empty set.  */
> +    if (edge_set->elements () == 0)
> +      delete edge_set;
> +  }
> +
> +  hash_set <cgraph_edge *> *edge_set;
> +  cgraph_edge *edge;

If the hash set is supposed to replace the linked list of edge clones,
then a removal mechanism seems to be missing.  The whole point of
prev_edge_clone vector was to allow removal of edges from the linked
list, because as speculative edges are thrown away, clones can be too
and then we must remove the pointer from the list, or hash set.

Have you tried -O3 LTOing Firefox with these changes?

But I must say that I'm not convinced that converting the linked list
into a hash_set is a good idea at all.  Apart from the self-removal
operation, the lists are always traversed linearly and in full, so
except for using a C++-style iterator, I really do not see any point.

Moreover, you seem to create a hash table for each and every edge,
even when it has no clones, just to be able to enter the edge itself
into it, and so not skip it when you iterate over all clones.  That
really seems like unjustifiable overhead.  And the deletion in
duplication hook is also very unappealing.  So the bottom line is that
while I like turning the two vectors into a summary, I do not like the
hash set at all.  If absolutely think it is a good idea, please make
that change in a separate patch so that we can better argue about its
merits.

On the other hand, since the summaries are hash-based themselves, it
would be great if they had a predicate to find out whether there is
any summary for a given edge at all and have get_next_cgraph_edge_clone
return false if there was none.  That would actually save memory.

Thanks,

Martin

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum.
  2015-07-10 13:31   ` Martin Jambor
@ 2015-07-16 14:06     ` Martin Liška
  2015-08-03 15:22       ` Martin Liška
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Liška @ 2015-07-16 14:06 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 11532 bytes --]

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



[-- Attachment #2: 0002-Introduce-new-edge_summary-class-and-port-IPA-inline.patch --]
[-- Type: text/x-patch, Size: 80761 bytes --]

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


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 4/6] Port ipa-cp to use cgraph_edge summary.
  2015-07-10 14:18   ` Martin Jambor
@ 2015-07-16 14:08     ` Martin Liška
  0 siblings, 0 replies; 24+ messages in thread
From: Martin Liška @ 2015-07-16 14:08 UTC (permalink / raw)
  To: gcc-patches

On 07/10/2015 04:18 PM, Martin Jambor wrote:
> Hi,
> 
> I know the patch has been approved by Jeff, but please do not commit
> it before considering the following:
> 
> On Thu, Jul 09, 2015 at 11:13:53AM +0200, Martin Liska wrote:
>> gcc/ChangeLog:
>>
>> 2015-07-03  Martin Liska  <mliska@suse.cz>
>>
>> 	* ipa-cp.c (struct edge_clone_summary): New structure.
>> 	(class edge_clone_summary_t): Likewise.
>> 	(edge_clone_summary_t::initialize): New method.
>> 	(edge_clone_summary_t::duplicate): Likewise.
>> 	(get_next_cgraph_edge_clone): Remove.
>> 	(get_info_about_necessary_edges): Refactor using the new
>> 	data structure.
>> 	(gather_edges_for_value): Likewise.
>> 	(perhaps_add_new_callers): Likewise.
>> 	(ipcp_driver): Allocate and deallocate newly added
>> 	instance.
>> ---
>>  gcc/ipa-cp.c | 198 ++++++++++++++++++++++++++++++++++-------------------------
>>  1 file changed, 113 insertions(+), 85 deletions(-)
>>
>> diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
>> index 16b9cde..8a50b63 100644
>> --- a/gcc/ipa-cp.c
>> +++ b/gcc/ipa-cp.c
>> @@ -2888,54 +2888,79 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
>>      inline_update_overall_summary (node);
>>  }
>>  
>> -/* Vector of pointers which for linked lists of clones of an original crgaph
>> -   edge. */
>> +/* Edge clone summary.  */
>>  
>> -static vec<cgraph_edge *> next_edge_clone;
>> -static vec<cgraph_edge *> prev_edge_clone;
>> -
>> -static inline void
>> -grow_edge_clone_vectors (void)
>> +struct edge_clone_summary
> 
> I's got constructors and destructors so it should be a class, reaally.
> 
>>  {
>> -  if (next_edge_clone.length ()
>> -      <=  (unsigned) symtab->edges_max_uid)
>> -    next_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
>> -  if (prev_edge_clone.length ()
>> -      <=  (unsigned) symtab->edges_max_uid)
>> -    prev_edge_clone.safe_grow_cleared (symtab->edges_max_uid + 1);
>> -}
>> +  /* Default constructor.  */
>> +  edge_clone_summary (): edge_set (NULL), edge (NULL) {}
>>  
>> -/* Edge duplication hook to grow the appropriate linked list in
>> -   next_edge_clone. */
>> +  /* Default destructor.  */
>> +  ~edge_clone_summary ()
>> +  {
>> +    gcc_assert (edge_set != NULL);
>>  
>> -static void
>> -ipcp_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
>> -			    void *)
>> +    if (edge != NULL)
>> +      {
>> +	gcc_checking_assert (edge_set->contains (edge));
>> +	edge_set->remove (edge);
>> +      }
>> +
>> +    /* Release memory for an empty set.  */
>> +    if (edge_set->elements () == 0)
>> +      delete edge_set;
>> +  }
>> +
>> +  hash_set <cgraph_edge *> *edge_set;
>> +  cgraph_edge *edge;
> 
> If the hash set is supposed to replace the linked list of edge clones,
> then a removal mechanism seems to be missing.  The whole point of
> prev_edge_clone vector was to allow removal of edges from the linked
> list, because as speculative edges are thrown away, clones can be too
> and then we must remove the pointer from the list, or hash set.
> 
> Have you tried -O3 LTOing Firefox with these changes?
> 
> But I must say that I'm not convinced that converting the linked list
> into a hash_set is a good idea at all.  Apart from the self-removal
> operation, the lists are always traversed linearly and in full, so
> except for using a C++-style iterator, I really do not see any point.
> 
> Moreover, you seem to create a hash table for each and every edge,
> even when it has no clones, just to be able to enter the edge itself
> into it, and so not skip it when you iterate over all clones.  That
> really seems like unjustifiable overhead.  And the deletion in
> duplication hook is also very unappealing.  So the bottom line is that
> while I like turning the two vectors into a summary, I do not like the
> hash set at all.  If absolutely think it is a good idea, please make
> that change in a separate patch so that we can better argue about its
> merits.
> 
> On the other hand, since the summaries are hash-based themselves, it
> would be great if they had a predicate to find out whether there is
> any summary for a given edge at all and have get_next_cgraph_edge_clone
> return false if there was none.  That would actually save memory.
> 
> Thanks,
> 
> Martin
> 

After a discussion with Martin, we made a decision to preserve current implementation
and not to port the IPA CP to he newly introduced summary.

Martin

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 5/6] Port IPA reference to function_summary infrastructure.
  2015-07-10 13:30   ` Martin Jambor
@ 2015-07-16 14:14     ` Martin Liška
  0 siblings, 0 replies; 24+ messages in thread
From: Martin Liška @ 2015-07-16 14:14 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2893 bytes --]

On 07/10/2015 03:30 PM, Martin Jambor wrote:
> Hi,
> 
> I've spotted a likely typo:
> 
> On Thu, Jul 09, 2015 at 11:13:53AM +0200, Martin Liska wrote:
>> gcc/ChangeLog:
>>
>> 2015-07-03  Martin Liska  <mliska@suse.cz>
>>
>> 	* ipa-reference.c (ipa_ref_opt_summary_t): New class.
>> 	(get_reference_optimization_summary): Use it.
>> 	(set_reference_optimization_summary): Likewise.
>> 	(ipa_init): Remove hook holders usage.
>> 	(ipa_reference_c_finalize): Likewise.
>> 	(ipa_ref_opt_summary_t::duplicate): New function.
>> 	(ipa_ref_opt_summary_t::remove): Likewise.
>> 	(propagate): Allocate the summary if does not exist.
>> 	(ipa_reference_read_optimization_summary): Likewise.
>> 	(struct ipa_reference_vars_info_d): Add new method.
>> 	(struct ipa_reference_optimization_summary_d): Likewise.
>> 	(get_reference_vars_info): Use new underlying container.
>> 	(set_reference_vars_info): Remove.
>> 	(init_function_info): Set up the container.
>> ---
>>  gcc/ipa-reference.c | 203 ++++++++++++++++++++++++++--------------------------
>>  1 file changed, 102 insertions(+), 101 deletions(-)
>>
>> diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
>> index 465a74b..2afd9ad 100644
>> --- a/gcc/ipa-reference.c
>> +++ b/gcc/ipa-reference.c
> 
> ...
> 
>> @@ -837,12 +839,14 @@ propagate (void)
>>  	}
>>      }
>>  
>> +  if (ipa_ref_opt_sum_summaries == NULL)
>> +    ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
>> +
>>    /* Cleanup. */
>>    FOR_EACH_DEFINED_FUNCTION (node)
>>      {
>>        ipa_reference_vars_info_t node_info;
>>        ipa_reference_global_vars_info_t node_g;
>> -      ipa_reference_optimization_summary_t opt;
>>  
>>        node_info = get_reference_vars_info (node);
>>        if (!node->alias && opt_for_fn (node->decl, flag_ipa_reference)
>> @@ -851,8 +855,8 @@ propagate (void)
>>  	{
>>  	  node_g = &node_info->global;
>>  
>> -	  opt = XCNEW (struct ipa_reference_optimization_summary_d);
>> -	  set_reference_optimization_summary (node, opt);
>> +	  ipa_reference_optimization_summary_d *opt =
>> +	    ipa_ref_opt_sum_summaries->get (node);
>>  
>>  	  /* Create the complimentary sets.  */
>>  
>> @@ -880,14 +884,20 @@ propagate (void)
>>  				  node_g->statics_written);
>>  	    }
>>  	}
>> -      free (node_info);
>>     }
>>  
>>    ipa_free_postorder_info ();
>>    free (order);
>>  
>>    bitmap_obstack_release (&local_info_obstack);
>> -  ipa_reference_vars_vector.release ();
>> +
>> +  if (ipa_ref_var_info_summaries == NULL)
> 
> I assume you meant != NULL here.
> 
>> +    {
>> +      delete ipa_ref_var_info_summaries;
>> +      ipa_ref_var_info_summaries = NULL;
>> +    }
>> +
>> +  ipa_ref_var_info_summaries = NULL;
>>    if (dump_file)
>>      splay_tree_delete (reference_vars_to_consider);
>>    reference_vars_to_consider = NULL;
> 
> Thanks,
> 
> Martin
> 

Hello

I send v2 of the patch.

Thanks,
Martin

[-- Attachment #2: 0003-Port-IPA-reference-to-function_summary-infrastructur.patch --]
[-- Type: text/x-patch, Size: 15721 bytes --]

From 06877d19c6cf617730e188bd998926b0f9852cd3 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Thu, 9 Jul 2015 11:13:53 +0200
Subject: [PATCH 3/4] Port IPA reference to function_summary infrastructure.

gcc/ChangeLog:

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

	* ipa-reference.c (ipa_ref_opt_summary_t): New class.
	(get_reference_optimization_summary): Use it.
	(set_reference_optimization_summary): Likewise.
	(ipa_init): Remove hook holders usage.
	(ipa_reference_c_finalize): Likewise.
	(ipa_ref_opt_summary_t::duplicate): New function.
	(ipa_ref_opt_summary_t::remove): Likewise.
	(propagate): Allocate the summary if does not exist.
	(ipa_reference_read_optimization_summary): Likewise.
	(struct ipa_reference_vars_info_d): Add new method.
	(struct ipa_reference_optimization_summary_d): Likewise.
	(get_reference_vars_info): Use new underlying container.
	(set_reference_vars_info): Remove.
	(init_function_info): Set up the container.
	(is_proper_for_analysis): Fix coding style.
	(write_node_summary_p): Likewise.
	(stream_out_bitmap): Likewise.
---
 gcc/ipa-reference.c | 214 ++++++++++++++++++++++++----------------------------
 1 file changed, 100 insertions(+), 114 deletions(-)

diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index c00fca3..f35c66c 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -57,12 +57,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "diagnostic.h"
 #include "data-streamer.h"
-
-static void remove_node_data (struct cgraph_node *node,
-			      void *data ATTRIBUTE_UNUSED);
-static void duplicate_node_data (struct cgraph_node *src,
-				 struct cgraph_node *dst,
-				 void *data ATTRIBUTE_UNUSED);
+#include "symbol-summary.h"
 
 /* The static variables defined within the compilation unit that are
    loaded or stored directly by function that owns this structure.  */
@@ -92,9 +87,10 @@ struct ipa_reference_optimization_summary_d
   bitmap statics_not_written;
 };
 
-typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
-typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
-typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_summary_t;
+typedef ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
+typedef ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
+typedef ipa_reference_optimization_summary_d *
+  ipa_reference_optimization_summary_t;
 
 struct ipa_reference_vars_info_d
 {
@@ -122,57 +118,55 @@ static bitmap_obstack local_info_obstack;
 /* Obstack holding global analysis live forever.  */
 static bitmap_obstack optimization_summary_obstack;
 
-/* Holders of ipa cgraph hooks: */
-static struct cgraph_2node_hook_list *node_duplication_hook_holder;
-static struct cgraph_node_hook_list *node_removal_hook_holder;
+class ipa_ref_var_info_summary_t: public function_summary
+			  <ipa_reference_vars_info_d *>
+{
+public:
+  ipa_ref_var_info_summary_t (symbol_table *symtab):
+    function_summary <ipa_reference_vars_info_d *> (symtab) {}
+};
 
-/* Vector where the reference var infos are actually stored. 
-   Indexed by UID of call graph nodes.  */
-static vec<ipa_reference_vars_info_t> ipa_reference_vars_vector;
+static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL;
 
-/* TODO: find a place where we should release the vector.  */
-static vec<ipa_reference_optimization_summary_t> ipa_reference_opt_sum_vector;
+class ipa_ref_opt_summary_t: public function_summary
+			     <ipa_reference_optimization_summary_d *>
+{
+public:
+  ipa_ref_opt_summary_t (symbol_table *symtab):
+    function_summary <ipa_reference_optimization_summary_d *> (symtab) {}
+
+
+  virtual void remove (cgraph_node *src_node,
+		       ipa_reference_optimization_summary_d *data);
+  virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
+			  ipa_reference_optimization_summary_d *src_data,
+			  ipa_reference_optimization_summary_d *dst_data);
+};
+
+static ipa_ref_opt_summary_t *ipa_ref_opt_sum_summaries = NULL;
 
 /* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
 static inline ipa_reference_vars_info_t
 get_reference_vars_info (struct cgraph_node *node)
 {
-  if (!ipa_reference_vars_vector.exists ()
-      || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
+  if (ipa_ref_var_info_summaries == NULL)
     return NULL;
-  return ipa_reference_vars_vector[node->uid];
+
+  ipa_reference_vars_info_t v = ipa_ref_var_info_summaries->get (node);
+  return v == NULL ? NULL : v;
 }
 
 /* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
 static inline ipa_reference_optimization_summary_t
 get_reference_optimization_summary (struct cgraph_node *node)
 {
-  if (!ipa_reference_opt_sum_vector.exists ()
-      || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
+  if (ipa_ref_opt_sum_summaries == NULL)
     return NULL;
-  return ipa_reference_opt_sum_vector[node->uid];
-}
 
-/* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
-static inline void
-set_reference_vars_info (struct cgraph_node *node,
-			 ipa_reference_vars_info_t info)
-{
-  if (!ipa_reference_vars_vector.exists ()
-      || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
-    ipa_reference_vars_vector.safe_grow_cleared (node->uid + 1);
-  ipa_reference_vars_vector[node->uid] = info;
-}
+  ipa_reference_optimization_summary_t v = ipa_ref_opt_sum_summaries->get
+    (node);
 
-/* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
-static inline void
-set_reference_optimization_summary (struct cgraph_node *node,
-				    ipa_reference_optimization_summary_t info)
-{
-  if (!ipa_reference_opt_sum_vector.exists ()
-      || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
-    ipa_reference_opt_sum_vector.safe_grow_cleared (node->uid + 1);
-  ipa_reference_opt_sum_vector[node->uid] = info;
+  return v == NULL ? NULL : v;
 }
 
 /* Return a bitmap indexed by DECL_UID for the static variables that
@@ -242,8 +236,8 @@ is_proper_for_analysis (tree t)
   if (TREE_ADDRESSABLE (t))
     return false;
 
-  /* TODO: We could track public variables that are not addressable, but currently
-     frontends don't give us those.  */
+  /* TODO: We could track public variables that are not addressable,
+     but currently frontends don't give us those.  */
   if (TREE_PUBLIC (t))
     return false;
 
@@ -411,10 +405,14 @@ ipa_init (void)
   all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
   ignore_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
 
-  node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
-  node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
+  if (ipa_ref_var_info_summaries == NULL)
+    ipa_ref_var_info_summaries = new ipa_ref_var_info_summary_t (symtab);
+
+  if (ipa_ref_opt_sum_summaries != NULL)
+    {
+      delete ipa_ref_opt_sum_summaries;
+      ipa_ref_opt_sum_summaries = NULL;
+    }
 }
 
 
@@ -423,11 +421,8 @@ ipa_init (void)
 static ipa_reference_local_vars_info_t
 init_function_info (struct cgraph_node *fn)
 {
-  ipa_reference_vars_info_t info
-    = XCNEW (struct ipa_reference_vars_info_d);
-
-  /* Add the info to the tree's annotation.  */
-  set_reference_vars_info (fn, info);
+  ipa_reference_vars_info_t info =
+    ipa_ref_var_info_summaries->get_or_insert (fn);
 
   info->local.statics_read = BITMAP_ALLOC (&local_info_obstack);
   info->local.statics_written = BITMAP_ALLOC (&local_info_obstack);
@@ -490,18 +485,12 @@ analyze_function (struct cgraph_node *fn)
 
 /* Called when new clone is inserted to callgraph late.  */
 
-static void
-duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
-	 	     void *data ATTRIBUTE_UNUSED)
+void
+ipa_ref_opt_summary_t::duplicate (cgraph_node *, cgraph_node *,
+				  ipa_reference_optimization_summary_d *ginfo,
+				  ipa_reference_optimization_summary_d
+				  *dst_ginfo)
 {
-  ipa_reference_optimization_summary_t ginfo;
-  ipa_reference_optimization_summary_t dst_ginfo;
-
-  ginfo = get_reference_optimization_summary (src);
-  if (!ginfo)
-    return;
-  dst_ginfo = XCNEW (struct ipa_reference_optimization_summary_d);
-  set_reference_optimization_summary (dst, dst_ginfo);
   dst_ginfo->statics_not_read =
     copy_static_var_set (ginfo->statics_not_read);
   dst_ginfo->statics_not_written =
@@ -510,23 +499,17 @@ duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
 
 /* Called when node is removed.  */
 
-static void
-remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+ipa_ref_opt_summary_t::remove (cgraph_node *,
+			       ipa_reference_optimization_summary_d *ginfo)
 {
-  ipa_reference_optimization_summary_t ginfo;
-  ginfo = get_reference_optimization_summary (node);
-  if (ginfo)
-    {
-      if (ginfo->statics_not_read
-	  && ginfo->statics_not_read != all_module_statics)
-	BITMAP_FREE (ginfo->statics_not_read);
-
-      if (ginfo->statics_not_written
-	  && ginfo->statics_not_written != all_module_statics)
-	BITMAP_FREE (ginfo->statics_not_written);
-      free (ginfo);
-      set_reference_optimization_summary (node, NULL);
-    }
+  if (ginfo->statics_not_read
+      && ginfo->statics_not_read != all_module_statics)
+    BITMAP_FREE (ginfo->statics_not_read);
+
+  if (ginfo->statics_not_written
+      && ginfo->statics_not_written != all_module_statics)
+    BITMAP_FREE (ginfo->statics_not_written);
 }
 
 /* Analyze each function in the cgraph to see which global or statics
@@ -653,7 +636,8 @@ get_read_write_all_from_node (struct cgraph_node *node,
       struct cgraph_node *callee = e->callee->function_symbol (&avail);
       gcc_checking_assert (callee);
       if (avail <= AVAIL_INTERPOSABLE
-          || (callee->analyzed && !opt_for_fn (callee->decl, flag_ipa_reference)))
+	  || (callee->analyzed && !opt_for_fn (callee->decl,
+					       flag_ipa_reference)))
 	read_write_all_from_decl (callee, read_all, write_all);
     }
 
@@ -836,12 +820,14 @@ propagate (void)
 	}
     }
 
+  if (ipa_ref_opt_sum_summaries == NULL)
+    ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
+
   /* Cleanup. */
   FOR_EACH_DEFINED_FUNCTION (node)
     {
       ipa_reference_vars_info_t node_info;
       ipa_reference_global_vars_info_t node_g;
-      ipa_reference_optimization_summary_t opt;
 
       node_info = get_reference_vars_info (node);
       if (!node->alias && opt_for_fn (node->decl, flag_ipa_reference)
@@ -850,8 +836,8 @@ propagate (void)
 	{
 	  node_g = &node_info->global;
 
-	  opt = XCNEW (struct ipa_reference_optimization_summary_d);
-	  set_reference_optimization_summary (node, opt);
+	  ipa_reference_optimization_summary_d *opt =
+	    ipa_ref_opt_sum_summaries->get_or_insert (node);
 
 	  /* Create the complimentary sets.  */
 
@@ -879,14 +865,20 @@ propagate (void)
 				  node_g->statics_written);
 	    }
 	}
-      free (node_info);
    }
 
   ipa_free_postorder_info ();
   free (order);
 
   bitmap_obstack_release (&local_info_obstack);
-  ipa_reference_vars_vector.release ();
+
+  if (ipa_ref_var_info_summaries == NULL)
+    {
+      delete ipa_ref_var_info_summaries;
+      ipa_ref_var_info_summaries = NULL;
+    }
+
+  ipa_ref_var_info_summaries = NULL;
   if (dump_file)
     splay_tree_delete (reference_vars_to_consider);
   reference_vars_to_consider = NULL;
@@ -906,8 +898,9 @@ write_node_summary_p (struct cgraph_node *node,
   if (!node->definition || node->global.inlined_to)
     return false;
   info = get_reference_optimization_summary (node);
-  if (!info || (bitmap_empty_p (info->statics_not_read)
-		&& bitmap_empty_p (info->statics_not_written)))
+  if (!info
+      || (bitmap_empty_p (info->statics_not_read)
+	  && bitmap_empty_p (info->statics_not_written)))
     return false;
 
   /* See if we want to encode it.
@@ -957,7 +950,8 @@ stream_out_bitmap (struct lto_simple_output_block *ob,
     return;
   EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
     {
-      tree decl = (tree)splay_tree_lookup (reference_vars_to_consider, index)->value;
+      tree decl = (tree)splay_tree_lookup (reference_vars_to_consider,
+					   index)->value;
       lto_output_var_decl_index (ob->decl_state, ob->main_stream, decl);
     }
 }
@@ -1046,10 +1040,9 @@ ipa_reference_read_optimization_summary (void)
   unsigned int j = 0;
   bitmap_obstack_initialize (&optimization_summary_obstack);
 
-  node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
-  node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
+  if (ipa_ref_opt_sum_summaries == NULL)
+    ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab);
+
   all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
 
   while ((file_data = file_data_vec[j++]))
@@ -1084,7 +1077,6 @@ ipa_reference_read_optimization_summary (void)
 	    {
 	      unsigned int j, index;
 	      struct cgraph_node *node;
-	      ipa_reference_optimization_summary_t info;
 	      int v_count;
 	      lto_symtab_encoder_t encoder;
 
@@ -1092,10 +1084,14 @@ ipa_reference_read_optimization_summary (void)
 	      encoder = file_data->symtab_node_encoder;
 	      node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref
 		(encoder, index));
-	      info = XCNEW (struct ipa_reference_optimization_summary_d);
-	      set_reference_optimization_summary (node, info);
-	      info->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack);
-	      info->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack);
+
+	      ipa_reference_optimization_summary_d *info =
+		ipa_ref_opt_sum_summaries->get_or_insert (node);
+
+	      info->statics_not_read = BITMAP_ALLOC
+		(&optimization_summary_obstack);
+	      info->statics_not_written = BITMAP_ALLOC
+		(&optimization_summary_obstack);
 	      if (dump_file)
 		fprintf (dump_file,
 			 "\nFunction name:%s/%i:\n  static not read:",
@@ -1137,7 +1133,8 @@ ipa_reference_read_optimization_summary (void)
 		    unsigned int var_index = streamer_read_uhwi (ib);
 		    tree v_decl = lto_file_decl_data_get_var_decl (file_data,
 								   var_index);
-		    bitmap_set_bit (info->statics_not_written, DECL_UID (v_decl));
+		    bitmap_set_bit (info->statics_not_written,
+				    DECL_UID (v_decl));
 		    if (dump_file)
 		      fprintf (dump_file, " %s", fndecl_name (v_decl));
 		  }
@@ -1150,9 +1147,9 @@ ipa_reference_read_optimization_summary (void)
 					  ib, data, len);
 	}
       else
-	/* Fatal error here.  We do not want to support compiling ltrans units with
-	   different version of compiler or different flags than the WPA unit, so
-	   this should never happen.  */
+	/* Fatal error here.  We do not want to support compiling ltrans units
+	   with different version of compiler or different flags than
+	   the WPA unit, so this should never happen.  */
 	fatal_error (input_location,
 		     "ipa reference summary is missing in ltrans unit");
     }
@@ -1222,15 +1219,4 @@ ipa_reference_c_finalize (void)
       bitmap_obstack_release (&optimization_summary_obstack);
       ipa_init_p = false;
     }
-
-  if (node_removal_hook_holder)
-    {
-      symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
-      node_removal_hook_holder = NULL;
-    }
-  if (node_duplication_hook_holder)
-    {
-      symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
-      node_duplication_hook_holder = NULL;
-    }
 }
-- 
2.4.5


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 6/6] Migrate ipa-pure-const to function_summary.
  2015-07-09 20:47     ` Martin Liška
@ 2015-07-16 14:17       ` Martin Liška
  0 siblings, 0 replies; 24+ messages in thread
From: Martin Liška @ 2015-07-16 14:17 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2179 bytes --]

On 07/09/2015 10:47 PM, Martin Liška wrote:
> On 07/09/2015 07:44 PM, Jeff Law wrote:
>> On 07/09/2015 03:13 AM, mliska wrote:
>>> gcc/ChangeLog:
>>>
>>> 2015-07-03  Martin Liska  <mliska@suse.cz>
>>>
>>>     * ipa-pure-const.c (struct funct_state_d): New.
>>>     (funct_state_d::default_p): Likewise.
>>>     (has_function_state): Remove.
>>>     (get_function_state): Likewise.
>>>     (set_function_state): Likewise.
>>>     (add_new_function): Rename and port to ::insert.
>>>     (duplicate_node_data): Rename and port to ::duplicate.
>>>     (funct_state_summary_t::duplicate): New function.
>>>     (register_hooks): Remove hook registration.
>>>     (pure_const_generate_summary): Use new data structure.
>>>     (pure_const_write_summary): Likewise.
>>>     (pure_const_read_summary): Likewise.
>>>     (propagate_pure_const): Likewise.
>>>     (propagate_nothrow): Likewise.
>>>     (execute): Remove hook usage.
>>>     (pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
>>> ---
>>> @@ -84,6 +85,18 @@ const char *pure_const_names[3] = {"const", "pure", "neither"};
>>>      decl.  */
>>>   struct funct_state_d
>>>   {
>>> +  funct_state_d (): pure_const_state (IPA_NEITHER),
>>> +    state_previously_known (IPA_NEITHER), looping_previously_known (true),
>>> +    looping (true), can_throw (true), can_free (true) {}
>>> +
>>> +  funct_state_d (const funct_state_d &s): pure_const_state (s.pure_const_state),
>>> +    state_previously_known (s.state_previously_known),
>>> +    looping_previously_known (s.looping_previously_known),
>>> +    looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
>>> +
>>> +  /* Return true if the value is default.  */
>>> +  bool default_p ();
>>> +
>>>     /* See above.  */
>>>     enum pure_const_state_e pure_const_state;
>>>     /* What user set here; we can be always sure about this.  */
>> Doesn't this need to be a "class" rather then a "struct"?
>>
>>
>> OK with that change.
>>
>> jeff
> 
> Yeah.
> 
> 'class' will be more appropriate. As I'm going to be AFK for Friday and upcoming weekend,
> I will install these patches on Monday.
> 
> Thanks,
> Martin

Hello.

v2 of the patch.

Thanks,
Martin

[-- Attachment #2: 0004-Port-ipa-pure-const-to-function_summary.patch --]
[-- Type: text/x-patch, Size: 12782 bytes --]

From a17b6f69d944894ffda2f8db93577014dde070b9 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Thu, 9 Jul 2015 11:13:55 +0200
Subject: [PATCH 4/4] Port ipa-pure-const to function_summary.

gcc/ChangeLog:

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

	* ipa-pure-const.c (struct funct_state_d): New.
	(funct_state_d::default_p): Likewise.
	(has_function_state): Remove.
	(get_function_state): Likewise.
	(set_function_state): Likewise.
	(add_new_function): Rename and port to ::insert.
	(duplicate_node_data): Rename and port to ::duplicate.
	(funct_state_summary_t::duplicate): New function.
	(register_hooks): Remove hook registration.
	(pure_const_generate_summary): Use new data structure.
	(pure_const_write_summary): Likewise.
	(pure_const_read_summary): Likewise.
	(propagate_pure_const): Likewise.
	(propagate_nothrow): Likewise.
	(execute): Remove hook usage.
	(pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
---
 gcc/ipa-pure-const.c | 168 +++++++++++++++++----------------------------------
 1 file changed, 55 insertions(+), 113 deletions(-)

diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index f0373e6..90f1c9f 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -67,6 +67,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "opts.h"
 #include "varasm.h"
+#include "symbol-summary.h"
 
 /* Lattice values for const and pure functions.  Everything starts out
    being const, then may drop to pure and then neither depending on
@@ -82,8 +83,18 @@ const char *pure_const_names[3] = {"const", "pure", "neither"};
 
 /* Holder for the const_state.  There is one of these per function
    decl.  */
-struct funct_state_d
+class funct_state_d
 {
+public:
+  funct_state_d (): pure_const_state (IPA_NEITHER),
+    state_previously_known (IPA_NEITHER), looping_previously_known (true),
+    looping (true), can_throw (true), can_free (true) {}
+
+  funct_state_d (const funct_state_d &s): pure_const_state (s.pure_const_state),
+    state_previously_known (s.state_previously_known),
+    looping_previously_known (s.looping_previously_known),
+    looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
+
   /* See above.  */
   enum pure_const_state_e pure_const_state;
   /* What user set here; we can be always sure about this.  */
@@ -105,20 +116,25 @@ struct funct_state_d
   bool can_free;
 };
 
-/* State used when we know nothing about function.  */
-static struct funct_state_d varying_state
-   = { IPA_NEITHER, IPA_NEITHER, true, true, true, true };
-
-
 typedef struct funct_state_d * funct_state;
 
 /* The storage of the funct_state is abstracted because there is the
    possibility that it may be desirable to move this to the cgraph
    local info.  */
 
-/* Array, indexed by cgraph node uid, of function states.  */
+class funct_state_summary_t: public function_summary <funct_state_d *>
+{
+public:
+  funct_state_summary_t (symbol_table *symtab):
+    function_summary <funct_state_d *> (symtab) {}
+
+  virtual void insert (cgraph_node *, funct_state_d *state);
+  virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
+			  funct_state_d *src_data,
+			  funct_state_d *dst_data);
+};
 
-static vec<funct_state> funct_state_vec;
+static funct_state_summary_t *funct_state_summaries = NULL;
 
 static bool gate_pure_const (void);
 
@@ -150,12 +166,6 @@ public:
 
 private:
   bool init_p;
-
-  /* Holders of ipa cgraph hooks: */
-  struct cgraph_node_hook_list *function_insertion_hook_holder;
-  struct cgraph_2node_hook_list *node_duplication_hook_holder;
-  struct cgraph_node_hook_list *node_removal_hook_holder;
-
 }; // class pass_ipa_pure_const
 
 } // anon namespace
@@ -237,41 +247,6 @@ warn_function_noreturn (tree decl)
 			   true, warned_about, "noreturn");
 }
 
-/* Return true if we have a function state for NODE.  */
-
-static inline bool
-has_function_state (struct cgraph_node *node)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid)
-    return false;
-  return funct_state_vec[node->uid] != NULL;
-}
-
-/* Return the function state from NODE.  */
-
-static inline funct_state
-get_function_state (struct cgraph_node *node)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid
-      || !funct_state_vec[node->uid])
-    /* We might want to put correct previously_known state into varying.  */
-    return &varying_state;
- return funct_state_vec[node->uid];
-}
-
-/* Set the function state S for NODE.  */
-
-static inline void
-set_function_state (struct cgraph_node *node, funct_state s)
-{
-  if (!funct_state_vec.exists ()
-      || funct_state_vec.length () <= (unsigned int)node->uid)
-     funct_state_vec.safe_grow_cleared (node->uid + 1);
-  funct_state_vec[node->uid] = s;
-}
-
 /* Check to see if the use (or definition when CHECKING_WRITE is true)
    variable T is legal in a function that is either pure or const.  */
 
@@ -903,9 +878,8 @@ end:
   return l;
 }
 
-/* Called when new function is inserted to callgraph late.  */
-static void
-add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::insert (cgraph_node *node, funct_state_d *state)
 {
  if (node->get_availability () < AVAIL_INTERPOSABLE)
    return;
@@ -915,36 +889,21 @@ add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
      operations.  */
   if (node->get_availability () > AVAIL_INTERPOSABLE
       && opt_for_fn (node->decl, flag_ipa_pure_const))
-    set_function_state (node, analyze_function (node, true));
-}
-
-/* Called when new clone is inserted to callgraph late.  */
-
-static void
-duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
-	 	     void *data ATTRIBUTE_UNUSED)
-{
-  if (has_function_state (src))
     {
-      funct_state l = XNEW (struct funct_state_d);
-      gcc_assert (!has_function_state (dst));
-      memcpy (l, get_function_state (src), sizeof (*l));
-      set_function_state (dst, l);
+      funct_state_d *a = analyze_function (node, true);
+      new (state) funct_state_d (*a);
+      free (a);
     }
 }
 
 /* Called when new clone is inserted to callgraph late.  */
 
-static void
-remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::duplicate (cgraph_node *, cgraph_node *,
+				  funct_state_d *src_data,
+				  funct_state_d *dst_data)
 {
-  if (has_function_state (node))
-    {
-      funct_state l = get_function_state (node);
-      if (l != &varying_state)
-        free (l);
-      set_function_state (node, NULL);
-    }
+  new (dst_data) funct_state_d (*src_data);
 }
 
 \f
@@ -957,12 +916,7 @@ register_hooks (void)
 
   init_p = true;
 
-  node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
-  node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
-  function_insertion_hook_holder =
-      symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
+  funct_state_summaries = new funct_state_summary_t (symtab);
 }
 
 
@@ -986,7 +940,11 @@ pure_const_generate_summary (void)
   FOR_EACH_DEFINED_FUNCTION (node)
     if (node->get_availability () >= AVAIL_INTERPOSABLE
         && opt_for_fn (node->decl, flag_ipa_pure_const))
-      set_function_state (node, analyze_function (node, true));
+      {
+	funct_state_d *a = analyze_function (node, true);
+	new (funct_state_summaries->get_or_insert (node)) funct_state_d (*a);
+	free (a);
+      }
 }
 
 
@@ -1008,7 +966,8 @@ pure_const_write_summary (void)
        lsei_next_function_in_partition (&lsei))
     {
       node = lsei_cgraph_node (lsei);
-      if (node->definition && has_function_state (node))
+      if (node->definition
+	  && funct_state_summaries->get_or_insert (node) != NULL)
 	count++;
     }
 
@@ -1019,15 +978,13 @@ pure_const_write_summary (void)
        lsei_next_function_in_partition (&lsei))
     {
       node = lsei_cgraph_node (lsei);
-      if (node->definition && has_function_state (node))
+      funct_state_d *fs = funct_state_summaries->get_or_insert (node);
+      if (node->definition && fs != NULL)
 	{
 	  struct bitpack_d bp;
-	  funct_state fs;
 	  int node_ref;
 	  lto_symtab_encoder_t encoder;
 
-	  fs = get_function_state (node);
-
 	  encoder = ob->decl_state->symtab_node_encoder;
 	  node_ref = lto_symtab_encoder_encode (encoder, node);
 	  streamer_write_uhwi_stream (ob->main_stream, node_ref);
@@ -1082,13 +1039,12 @@ pure_const_read_summary (void)
 	      funct_state fs;
 	      lto_symtab_encoder_t encoder;
 
-	      fs = XCNEW (struct funct_state_d);
 	      index = streamer_read_uhwi (ib);
 	      encoder = file_data->symtab_node_encoder;
 	      node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
 									index));
-	      set_function_state (node, fs);
 
+	      fs = funct_state_summaries->get_or_insert (node);
 	      /* Note that the flags must be read in the opposite
 		 order in which they were written (the bitflags were
 		 pushed into FLAGS).  */
@@ -1216,7 +1172,7 @@ propagate_pure_const (void)
 	  int i;
 	  struct ipa_ref *ref = NULL;
 
-	  funct_state w_l = get_function_state (w);
+	  funct_state w_l = funct_state_summaries->get_or_insert (w);
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "  Visiting %s/%i state:%s looping %i\n",
 		     w->name (),
@@ -1272,7 +1228,7 @@ propagate_pure_const (void)
 		}
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = get_function_state (y);
+		  funct_state_d *y_l = funct_state_summaries->get_or_insert (y);
 		  if (dump_file && (dump_flags & TDF_DETAILS))
 		    {
 		      fprintf (dump_file,
@@ -1389,7 +1345,7 @@ propagate_pure_const (void)
       while (w && !can_free)
 	{
 	  struct cgraph_edge *e;
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get_or_insert (w);
 
 	  if (w_l->can_free
 	      || w->get_availability () == AVAIL_INTERPOSABLE
@@ -1403,7 +1359,7 @@ propagate_pure_const (void)
 				function_or_virtual_thunk_symbol (&avail);
 
 	      if (avail > AVAIL_INTERPOSABLE)
-		can_free = get_function_state (y)->can_free;
+		can_free = funct_state_summaries->get_or_insert (y)->can_free;
 	      else
 		can_free = true;
 	    }
@@ -1416,7 +1372,7 @@ propagate_pure_const (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get_or_insert (w);
 	  enum pure_const_state_e this_state = pure_const_state;
 	  bool this_looping = looping;
 
@@ -1526,7 +1482,7 @@ propagate_nothrow (void)
       while (w && !can_throw)
 	{
 	  struct cgraph_edge *e, *ie;
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get_or_insert (w);
 
 	  if (w_l->can_throw
 	      || w->get_availability () == AVAIL_INTERPOSABLE)
@@ -1540,7 +1496,7 @@ propagate_nothrow (void)
 
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = get_function_state (y);
+		  funct_state_d *y_l = funct_state_summaries->get_or_insert (y);
 
 		  if (y_l->can_throw && !TREE_NOTHROW (w->decl)
 		      && e->can_throw_external)
@@ -1561,7 +1517,7 @@ propagate_nothrow (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state_d *w_l = funct_state_summaries->get_or_insert (w);
 	  if (!can_throw && !TREE_NOTHROW (w->decl))
 	    {
 	      /* Inline clones share declaration with their offline copies;
@@ -1594,23 +1550,14 @@ unsigned int
 pass_ipa_pure_const::
 execute (function *)
 {
-  struct cgraph_node *node;
   bool remove_p;
 
-  symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
-  symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
-  symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
-
   /* Nothrow makes more function to not lead to return and improve
      later analysis.  */
   propagate_nothrow ();
   remove_p = propagate_pure_const ();
 
-  /* Cleanup. */
-  FOR_EACH_FUNCTION (node)
-    if (has_function_state (node))
-      free (get_function_state (node));
-  funct_state_vec.release ();
+  delete funct_state_summaries;
   return remove_p ? TODO_remove_functions : 0;
 }
 
@@ -1631,12 +1578,7 @@ pass_ipa_pure_const::pass_ipa_pure_const(gcc::context *ctxt)
 		     0, /* function_transform_todo_flags_start */
 		     NULL, /* function_transform */
 		     NULL), /* variable_transform */
-  init_p(false),
-  function_insertion_hook_holder(NULL),
-  node_duplication_hook_holder(NULL),
-  node_removal_hook_holder(NULL)
-{
-}
+  init_p (false) {}
 
 ipa_opt_pass_d *
 make_pass_ipa_pure_const (gcc::context *ctxt)
-- 
2.4.5


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum.
  2015-07-16 14:06     ` Martin Liška
@ 2015-08-03 15:22       ` Martin Liška
  0 siblings, 0 replies; 24+ messages in thread
From: Martin Liška @ 2015-08-03 15:22 UTC (permalink / raw)
  To: gcc-patches

On 07/16/2015 04:05 PM, Martin Liška wrote:
> 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
> 
> 

Hello.

Is the patch ready to be installed to trunk branch?

Thanks,
Martin

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2015-08-03 15:22 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-09 11:07 [PATCH 0/6] {function,edge}_summary for IPA passes mliska
2015-07-09 11:07 ` [PATCH 1/6] hash_set: add iterator and remove method mliska
2015-07-09 17:05   ` Jeff Law
2015-07-09 11:08 ` [PATCH 2/6] Introduce new edge_summary class and replace ipa_edge_args_sum mliska
2015-07-09 17:15   ` Jeff Law
2015-07-09 20:45     ` Martin Liška
2015-07-10 13:31   ` Martin Jambor
2015-07-16 14:06     ` Martin Liška
2015-08-03 15:22       ` Martin Liška
2015-07-09 11:08 ` [PATCH 4/6] Port ipa-cp to use cgraph_edge summary mliska
2015-07-09 17:39   ` Jeff Law
2015-07-10 14:18   ` Martin Jambor
2015-07-16 14:08     ` Martin Liška
2015-07-09 11:08 ` [PATCH 3/6] IPA inline: port inline_edge_summary to a new infrastructure mliska
2015-07-09 17:21   ` Jeff Law
2015-07-09 11:08 ` [PATCH 5/6] Port IPA reference to function_summary infrastructure mliska
2015-07-09 17:35   ` Jeff Law
2015-07-09 20:46     ` Martin Liška
2015-07-10 13:30   ` Martin Jambor
2015-07-16 14:14     ` Martin Liška
2015-07-09 11:09 ` [PATCH 6/6] Migrate ipa-pure-const to function_summary mliska
2015-07-09 17:44   ` Jeff Law
2015-07-09 20:47     ` Martin Liška
2015-07-16 14:17       ` Martin Liška

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).