[07/14] Covert ipa-pure-const.c to symbol_summary.

Message ID 63a8ee89cd0e78f9d2f5e7abcdbff905c04777a9.1526551813.git.mliska@suse.cz
State New
Headers show
Series
  • Finish transition of {symbol,call}_summary.
Related show

Commit Message

Martin Liška April 20, 2018, 10:23 a.m.
gcc/ChangeLog:

2018-04-24  Martin Liska  <mliska@suse.cz>

	* ipa-pure-const.c (struct funct_state_d): Do it class instead
	of struct.
	(class funct_state_summary_t): New function_summary class.
	(has_function_state): Remove.
	(get_function_state): Likewise.
	(set_function_state): Likewise.
	(add_new_function): Likewise.
	(funct_state_summary_t::insert): New function.
	(duplicate_node_data): Remove.
	(remove_node_data): Remove.
	(funct_state_summary_t::duplicate): New function.
	(register_hooks): Create new funct_state_summaries.
	(pure_const_generate_summary): Use it.
	(pure_const_write_summary): Likewise.
	(pure_const_read_summary): Likewise.
	(propagate_pure_const): Likewise.
	(propagate_nothrow): Likewise.
	(dump_malloc_lattice): Likewise.
	(propagate_malloc): Likewise.
	(execute): Do not register hooks, just remove summary
	instead.
	(pass_ipa_pure_const::pass_ipa_pure_const): Simplify
	constructor.
---
 gcc/ipa-pure-const.c | 193 ++++++++++++++++++---------------------------------
 1 file changed, 66 insertions(+), 127 deletions(-)

Comments

Jan Hubicka June 7, 2018, 12:57 p.m. | #1
> 

> gcc/ChangeLog:

> 

> 2018-04-24  Martin Liska  <mliska@suse.cz>

> 

> 	* ipa-pure-const.c (struct funct_state_d): Do it class instead

> 	of struct.

> 	(class funct_state_summary_t): New function_summary class.

> 	(has_function_state): Remove.

> 	(get_function_state): Likewise.

> 	(set_function_state): Likewise.

> 	(add_new_function): Likewise.

> 	(funct_state_summary_t::insert): New function.

> 	(duplicate_node_data): Remove.

> 	(remove_node_data): Remove.

> 	(funct_state_summary_t::duplicate): New function.

> 	(register_hooks): Create new funct_state_summaries.

> 	(pure_const_generate_summary): Use it.

> 	(pure_const_write_summary): Likewise.

> 	(pure_const_read_summary): Likewise.

> 	(propagate_pure_const): Likewise.

> 	(propagate_nothrow): Likewise.

> 	(dump_malloc_lattice): Likewise.

> 	(propagate_malloc): Likewise.

> 	(execute): Do not register hooks, just remove summary

> 	instead.

> 	(pass_ipa_pure_const::pass_ipa_pure_const): Simplify

> 	constructor.


OK with changes below.
In general, it would be cool to reorg this pass into simple SCC propagation template
because it does same things over and over again (sometimes on slightly different graph
because it has feature to skip uninteresting edges e.g. for nothrow propagation).
> @@ -1485,7 +1439,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_create (w);

>  	  if (dump_file && (dump_flags & TDF_DETAILS))

>  	    fprintf (dump_file, "  Visiting %s state:%s looping %i\n",

>  		     w->dump_name (),

> @@ -1527,7 +1481,7 @@ propagate_pure_const (void)

>  		}

>  	      if (avail > AVAIL_INTERPOSABLE)

>  		{

> -		  funct_state y_l = get_function_state (y);

> +		  funct_state y_l = funct_state_summaries->get_create (y);

>  		  if (dump_file && (dump_flags & TDF_DETAILS))

>  		    {

>  		      fprintf (dump_file,


The functions are organized in a way that it goes cycle by cycle. First loop initializes
everything in the cycle and in this case you want get_create (where w_l is set)
y_l looks for calls and because it works in SCC order all calls are either in same cycle
or processed.  I do not see any guard checking that y_l is initialized and because you
now initialize it to pesimistic state I think it will turn any SCC component into non-pure
now (while it originaly worked by initializing to 0 which is optimistic state CONST)

So i would add guard that y is in different SCC component and make code to crash
if get() returns NULL.
Similarly for all other propagators.

> @@ -1642,7 +1596,7 @@ propagate_pure_const (void)

>        while (w && !can_free)

>  	{

>  	  struct cgraph_edge *e;

> -	  funct_state w_l = get_function_state (w);

> +	  funct_state w_l = funct_state_summaries->get_create (w);

>  

>  	  if (w_l->can_free

>  	      || w->get_availability () == AVAIL_INTERPOSABLE

> @@ -1657,7 +1611,7 @@ propagate_pure_const (void)

>  								  e->caller);

>  

>  	      if (avail > AVAIL_INTERPOSABLE)

> -		can_free = get_function_state (y)->can_free;

> +		can_free = funct_state_summaries->get_create (y)->can_free;

>  	      else

>  		can_free = true;

>  	    }


Here everything should be computed already.

OK with those changes provides it does not affect generated code.

Honza
Martin Liška June 8, 2018, 12:05 p.m. | #2
On 06/07/2018 02:57 PM, Jan Hubicka wrote:
>>

>> gcc/ChangeLog:

>>

>> 2018-04-24  Martin Liska  <mliska@suse.cz>

>>

>> 	* ipa-pure-const.c (struct funct_state_d): Do it class instead

>> 	of struct.

>> 	(class funct_state_summary_t): New function_summary class.

>> 	(has_function_state): Remove.

>> 	(get_function_state): Likewise.

>> 	(set_function_state): Likewise.

>> 	(add_new_function): Likewise.

>> 	(funct_state_summary_t::insert): New function.

>> 	(duplicate_node_data): Remove.

>> 	(remove_node_data): Remove.

>> 	(funct_state_summary_t::duplicate): New function.

>> 	(register_hooks): Create new funct_state_summaries.

>> 	(pure_const_generate_summary): Use it.

>> 	(pure_const_write_summary): Likewise.

>> 	(pure_const_read_summary): Likewise.

>> 	(propagate_pure_const): Likewise.

>> 	(propagate_nothrow): Likewise.

>> 	(dump_malloc_lattice): Likewise.

>> 	(propagate_malloc): Likewise.

>> 	(execute): Do not register hooks, just remove summary

>> 	instead.

>> 	(pass_ipa_pure_const::pass_ipa_pure_const): Simplify

>> 	constructor.

> 

> OK with changes below.

> In general, it would be cool to reorg this pass into simple SCC propagation template

> because it does same things over and over again (sometimes on slightly different graph

> because it has feature to skip uninteresting edges e.g. for nothrow propagation).

>> @@ -1485,7 +1439,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_create (w);

>>  	  if (dump_file && (dump_flags & TDF_DETAILS))

>>  	    fprintf (dump_file, "  Visiting %s state:%s looping %i\n",

>>  		     w->dump_name (),

>> @@ -1527,7 +1481,7 @@ propagate_pure_const (void)

>>  		}

>>  	      if (avail > AVAIL_INTERPOSABLE)

>>  		{

>> -		  funct_state y_l = get_function_state (y);

>> +		  funct_state y_l = funct_state_summaries->get_create (y);

>>  		  if (dump_file && (dump_flags & TDF_DETAILS))

>>  		    {

>>  		      fprintf (dump_file,

> 

> The functions are organized in a way that it goes cycle by cycle. First loop initializes

> everything in the cycle and in this case you want get_create (where w_l is set)

> y_l looks for calls and because it works in SCC order all calls are either in same cycle

> or processed.  I do not see any guard checking that y_l is initialized and because you

> now initialize it to pesimistic state I think it will turn any SCC component into non-pure

> now (while it originaly worked by initializing to 0 which is optimistic state CONST)

> 

> So i would add guard that y is in different SCC component and make code to crash

> if get() returns NULL.

> Similarly for all other propagators.

> 

>> @@ -1642,7 +1596,7 @@ propagate_pure_const (void)

>>        while (w && !can_free)

>>  	{

>>  	  struct cgraph_edge *e;

>> -	  funct_state w_l = get_function_state (w);

>> +	  funct_state w_l = funct_state_summaries->get_create (w);

>>  

>>  	  if (w_l->can_free

>>  	      || w->get_availability () == AVAIL_INTERPOSABLE

>> @@ -1657,7 +1611,7 @@ propagate_pure_const (void)

>>  								  e->caller);

>>  

>>  	      if (avail > AVAIL_INTERPOSABLE)

>> -		can_free = get_function_state (y)->can_free;

>> +		can_free = funct_state_summaries->get_create (y)->can_free;

>>  	      else

>>  		can_free = true;

>>  	    }

> 

> Here everything should be computed already.

> 

> OK with those changes provides it does not affect generated code.

> 

> Honza

> 


Hi.

Ok, I'll do that with one additional patch that I'm sending.

Martin
From 42f122845969bf39ec606a0592d7a511b87c4657 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>

Date: Fri, 8 Jun 2018 12:59:34 +0200
Subject: [PATCH] Make ipa-pure-const more strict about summary constrains.

gcc/ChangeLog:

2018-06-08  Martin Liska  <mliska@suse.cz>

	* ipa-pure-const.c (propagate_pure_const): Use ::get at places
        where we expect an existing summary.
---
 gcc/ipa-pure-const.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 8c415bc1fc0..d0f9cb8d7f7 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -1477,7 +1477,7 @@ propagate_pure_const (void)
 		}
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = funct_state_summaries->get_create (y);
+		  funct_state y_l = funct_state_summaries->get (y);
 		  if (dump_file && (dump_flags & TDF_DETAILS))
 		    {
 		      fprintf (dump_file,
@@ -1591,7 +1591,7 @@ propagate_pure_const (void)
       while (w && !can_free)
 	{
 	  struct cgraph_edge *e;
-	  funct_state w_l = funct_state_summaries->get_create (w);
+	  funct_state w_l = funct_state_summaries->get (w);
 
 	  if (w_l->can_free
 	      || w->get_availability () == AVAIL_INTERPOSABLE
@@ -1606,7 +1606,7 @@ propagate_pure_const (void)
 								  e->caller);
 
 	      if (avail > AVAIL_INTERPOSABLE)
-		can_free = funct_state_summaries->get_create (y)->can_free;
+		can_free = funct_state_summaries->get (y)->can_free;
 	      else
 		can_free = true;
 	    }
@@ -1619,7 +1619,7 @@ propagate_pure_const (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = funct_state_summaries->get_create (w);
+	  funct_state w_l = funct_state_summaries->get (w);
 	  enum pure_const_state_e this_state = pure_const_state;
 	  bool this_looping = looping;
 
-- 
2.17.0

Patch

diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 1f624965f1a..4ac2021c04e 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -85,8 +85,20 @@  static const char *malloc_state_names[] = {"malloc_top", "malloc", "malloc_botto
 
 /* 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),
+    malloc_state (STATE_MALLOC_BOTTOM) {}
+
+  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),
+    malloc_state (s.malloc_state) {}
+
   /* See above.  */
   enum pure_const_state_e pure_const_state;
   /* What user set here; we can be always sure about this.  */
@@ -110,20 +122,25 @@  struct funct_state_d
   enum malloc_state_e malloc_state;
 };
 
-/* State used when we know nothing about function.  */
-static struct funct_state_d varying_state
-   = { IPA_NEITHER, IPA_NEITHER, true, true, true, true, STATE_MALLOC_BOTTOM };
-
-
 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);
 
@@ -155,12 +172,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
@@ -286,48 +297,6 @@  warn_function_cold (tree decl)
 			 true, warned_about, "cold");
 }
 
-/* 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);
-
-  /* If funct_state_vec already contains a funct_state, we have to release
-     it before it's going to be ovewritten.  */
-  if (funct_state_vec[node->uid] != NULL
-      && funct_state_vec[node->uid] != &varying_state)
-    free (funct_state_vec[node->uid]);
-
-  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.  */
 
@@ -1152,40 +1121,29 @@  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)
 {
   /* There are some shared nodes, in particular the initializers on
      static declarations.  We do not need to scan them more than once
      since all we would be interested in are the addressof
      operations.  */
   if (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))
-    set_function_state (node, NULL);
+  new (dst_data) funct_state_d (*src_data);
 }
 
 
@@ -1198,12 +1156,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);
 }
 
 
@@ -1226,7 +1179,11 @@  pure_const_generate_summary (void)
 
   FOR_EACH_DEFINED_FUNCTION (node)
     if (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_create (node)) funct_state_d (*a);
+	free (a);
+      }
 }
 
 
@@ -1248,7 +1205,7 @@  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->exists (node))
 	count++;
     }
 
@@ -1259,15 +1216,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 != 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);
@@ -1323,13 +1278,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_create (node);
 	      /* Note that the flags must be read in the opposite
 		 order in which they were written (the bitflags were
 		 pushed into FLAGS).  */
@@ -1485,7 +1439,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_create (w);
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "  Visiting %s state:%s looping %i\n",
 		     w->dump_name (),
@@ -1527,7 +1481,7 @@  propagate_pure_const (void)
 		}
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = get_function_state (y);
+		  funct_state y_l = funct_state_summaries->get_create (y);
 		  if (dump_file && (dump_flags & TDF_DETAILS))
 		    {
 		      fprintf (dump_file,
@@ -1642,7 +1596,7 @@  propagate_pure_const (void)
       while (w && !can_free)
 	{
 	  struct cgraph_edge *e;
-	  funct_state w_l = get_function_state (w);
+	  funct_state w_l = funct_state_summaries->get_create (w);
 
 	  if (w_l->can_free
 	      || w->get_availability () == AVAIL_INTERPOSABLE
@@ -1657,7 +1611,7 @@  propagate_pure_const (void)
 								  e->caller);
 
 	      if (avail > AVAIL_INTERPOSABLE)
-		can_free = get_function_state (y)->can_free;
+		can_free = funct_state_summaries->get_create (y)->can_free;
 	      else
 		can_free = true;
 	    }
@@ -1670,7 +1624,7 @@  propagate_pure_const (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state w_l = funct_state_summaries->get_create (w);
 	  enum pure_const_state_e this_state = pure_const_state;
 	  bool this_looping = looping;
 
@@ -1809,7 +1763,7 @@  propagate_nothrow (void)
 
 	  if (!TREE_NOTHROW (w->decl))
 	    {
-	      funct_state w_l = get_function_state (w);
+	      funct_state w_l = funct_state_summaries->get_create (w);
 
 	      if (w_l->can_throw
 		  || w->get_availability () == AVAIL_INTERPOSABLE)
@@ -1834,7 +1788,7 @@  propagate_nothrow (void)
 		     throw.  */
 		  if (avail <= AVAIL_INTERPOSABLE
 		      || (!TREE_NOTHROW (y->decl)
-			  && (get_function_state (y)->can_throw
+			  && (funct_state_summaries->get_create (y)->can_throw
 			      || (opt_for_fn (y->decl, flag_non_call_exceptions)
 				  && !e->callee->binds_to_current_def_p (w)))))
 		    can_throw = true;
@@ -1854,7 +1808,7 @@  propagate_nothrow (void)
       w = node;
       while (w)
 	{
-	  funct_state w_l = get_function_state (w);
+	  funct_state w_l = funct_state_summaries->get_create (w);
 	  if (!can_throw && !TREE_NOTHROW (w->decl))
 	    {
 	      /* Inline clones share declaration with their offline copies;
@@ -1892,7 +1846,7 @@  dump_malloc_lattice (FILE *dump_file, const char *s)
   cgraph_node *node;
   FOR_EACH_FUNCTION (node)
     {
-      funct_state fs = get_function_state (node);
+      funct_state fs = funct_state_summaries->get_create (node);
       malloc_state_e state = fs->malloc_state;
       fprintf (dump_file, "%s: %s\n", node->name (), malloc_state_names[state]);
     }
@@ -1907,12 +1861,10 @@  propagate_malloc (void)
   FOR_EACH_FUNCTION (node)
     {
       if (DECL_IS_MALLOC (node->decl))
-	if (!has_function_state (node))
+	if (!funct_state_summaries->exists (node))
 	  {
-	    funct_state l = XCNEW (struct funct_state_d);
-	    *l = varying_state;
-	    l->malloc_state = STATE_MALLOC;
-	    set_function_state (node, l);
+	    funct_state fs = funct_state_summaries->get_create (node);
+	    fs->malloc_state = STATE_MALLOC;
 	  }
     }
 
@@ -1931,10 +1883,10 @@  propagate_malloc (void)
 	  cgraph_node *node = order[i];
 	  if (node->alias
 	      || !node->definition
-	      || !has_function_state (node))
+	      || !funct_state_summaries->exists (node))
 	    continue;
 
-	  funct_state l = get_function_state (node);
+	  funct_state l = funct_state_summaries->get_create (node);
 
 	  /* FIXME: add support for indirect-calls.  */
 	  if (node->indirect_calls)
@@ -1964,12 +1916,13 @@  propagate_malloc (void)
 	  for (unsigned j = 0; j < callees.length (); j++)
 	    {
 	      cgraph_node *callee = callees[j];
-	      if (!has_function_state (callee))
+	      if (!funct_state_summaries->exists (node))
 		{
 		  new_state = STATE_MALLOC_BOTTOM;
 		  break;
 		}
-	      malloc_state_e callee_state = get_function_state (callee)->malloc_state;
+	      malloc_state_e callee_state
+		= funct_state_summaries->get_create (callee)->malloc_state;
 	      if (new_state < callee_state)
 		new_state = callee_state;
 	    }
@@ -1982,9 +1935,9 @@  propagate_malloc (void)
     }
 
   FOR_EACH_DEFINED_FUNCTION (node)
-    if (has_function_state (node))
+    if (funct_state_summaries->exists (node))
       {
-	funct_state l = get_function_state (node);
+	funct_state l = funct_state_summaries->get_create (node);
 	if (!node->alias
 	    && l->malloc_state == STATE_MALLOC
 	    && !node->global.inlined_to)
@@ -2012,24 +1965,15 @@  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 ();
   propagate_malloc ();
   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;
 }
 
@@ -2050,12 +1994,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)