diff mbox

[4/4] Data structure is used for inline_summary struct.

Message ID 54660D21.3030200@suse.cz
State New
Headers show

Commit Message

Martin Liška Nov. 14, 2014, 2:09 p.m. UTC
On 11/13/2014 05:04 PM, Jan Hubicka wrote:
>> +  if (!inline_summary_summary)
>> +    inline_summary_summary = (inline_summary_cgraph_summary *) inline_summary_cgraph_summary::create_ggc (symtab);
>
> Hehe, this is funny naming scheme.
> Peraps inline_summary_d and inline_summary_t for the data and type?

Hello.

I adopted suggested naming scheme.

>> -
>> -static void
>> -inline_node_duplication_hook (struct cgraph_node *src,
>> -			      struct cgraph_node *dst,
>> -			      ATTRIBUTE_UNUSED void *data)
>> +void
>> +inline_summary_cgraph_summary::duplication_hook (cgraph_node *src,
>> +			      cgraph_node *dst,
>> +			      inline_summary *,
>> +			      inline_summary *info)
>
> Becuase those are no longer "hooks" but virtual function, I guess we could call them
> simply duplicate/insert/remove.

Agree with the change.

>
> In a way I would like to see these to be methods of the underlying type rather than
> virtual methods of the summary, becuase these are operations on the data themselves.
> I was thinking to model these by specual constructor and copy constructor
> (taking the extra node pointer parameters) and standard destructor.  I am not sure this
> would be more understandable this way?

Motivation for this implementation is:
a) it's useful to have an access to cgraph_node that is associated with a sumary
b) with GTY, we cannot call destructors

>> -/* Need a typedef for inline_summary because of inline function
>> -   'inline_summary' below.  */
>> -typedef struct inline_summary inline_summary_t;
>> -extern GTY(()) vec<inline_summary_t, va_gc> *inline_summary_vec;
>> +class GTY((user)) inline_summary_cgraph_summary: public cgraph_summary <inline_summary *>
>> +{
>> +public:
>> +  inline_summary_cgraph_summary (symbol_table *symtab, bool ggc):
>> +    cgraph_summary <inline_summary *> (symtab, ggc) {}
>> +
>> +  static inline_summary_cgraph_summary *create_ggc (symbol_table *symtab)
>> +  {
>> +    inline_summary_cgraph_summary *summary = new (ggc_cleared_alloc <inline_summary_cgraph_summary> ()) inline_summary_cgraph_summary(symtab, true);
>> +    summary->disable_insertion_hook ();
>> +    return summary;
>> +  }
>> +
>> +
>> +  virtual void insertion_hook (cgraph_node *, inline_summary *);
>> +  virtual void removal_hook (cgraph_node *node, inline_summary *);
>> +  virtual void duplication_hook (cgraph_node *src, cgraph_node *dst, inline_summary *src_data, inline_summary *dst_data);
>> +};
>> +
>> +extern GTY(()) cgraph_summary <inline_summary *> *inline_summary_summary;
>
> All in all it looks better than original code.  If we moved insert/
>>
>>   /* Information kept about parameter of call site.  */
>>   struct inline_param_summary
>> @@ -249,10 +265,10 @@ void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *,
>>   extern int ncalls_inlined;
>>   extern int nfunctions_inlined;
>>
>> -static inline struct inline_summary *
>> -inline_summary (struct cgraph_node *node)
>> +static inline inline_summary *
>> +get_inline_summary (const struct cgraph_node *node)
>>   {
>> -  return &(*inline_summary_vec)[node->uid];
>> +  return (*inline_summary_summary)[node->summary_uid];
>
> Hmm, i guess there is no way to avoid the (*...)? Otherwise it would be cleaner
> to use inline_summary[...] instead of get_inline_summary IMO.

I added function_summary::get method, where the usage looks cleaner:
inline_summary_d->get (node).

Thanks,
Martin
  
> Thanks for working on this!
> Honza
>

Comments

Jan Hubicka Nov. 14, 2014, 4:06 p.m. UTC | #1
> >
> >In a way I would like to see these to be methods of the underlying type rather than
> >virtual methods of the summary, becuase these are operations on the data themselves.
> >I was thinking to model these by specual constructor and copy constructor
> >(taking the extra node pointer parameters) and standard destructor.  I am not sure this
> >would be more understandable this way?
> 
> Motivation for this implementation is:
> a) it's useful to have an access to cgraph_node that is associated with a sumary

Yep, one would have node addition
 ctor (symtab_node *); (or cgraph/varpool nodes for cgraph/varpool annotations)
that would default to ctor for implementations that do not care about node.
And node duplication ctor
 ctor (summary &, symtab_node *, symtab_node *)
that would default to copy constructor for data that do not need to be copied.

I would say that main advantage (in addition to have a way to provide resonable
defaults) is to make ctors/dtors of the embedded classes working well, so one can
for example embedd pointer_map and not care about its construction/destruction.

> b) with GTY, we cannot call destructor

Everything in symbol table is expecitely memory managed (i.e. enver left
to be freed by garbage collector). It resists in GTY only to allow linking
garbage collected object from them and to get PCH working.

This is however quite cosmetic issue I would preffer our C++ guys to comment on.  We can
tweak this incrementally.
> +void
> +inline_summary_t::duplicate (cgraph_node *src,
> +			     cgraph_node *dst,
> +			     inline_summary *,
> +			     inline_summary *info)

Also we should have a way to say that the annotation do not need to be duplicated (for example
when we do not want to annotate inline clones). Probably by adding duplicate_p predicate that
is called before the actual duplication happens?

The updated patch is OK, I will take a look on the main patch.

Honza
>  {
> -  struct inline_summary *info;
>    inline_summary_alloc ();
> -  info = inline_summary (dst);
> -  memcpy (info, inline_summary (src), sizeof (struct inline_summary));
> +  memcpy (info, inline_summary_d->get (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);
> @@ -1328,7 +1309,7 @@ free_growth_caches (void)
>  
>  static void
>  dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node,
> -			  struct inline_summary *info)
> +			  inline_summary *info)
>  {
>    struct cgraph_edge *edge;
>    for (edge = node->callees; edge; edge = edge->next_callee)
> @@ -1345,8 +1326,8 @@ 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_summary (callee)->size / INLINE_SIZE_SCALE,
> -	       (int) inline_summary (callee)->estimated_stack_size);
> +	       (int) inline_summary_d->get (callee)->size / INLINE_SIZE_SCALE,
> +	       (int) inline_summary_d->get (callee)->estimated_stack_size);
>  
>        if (es->predicate)
>  	{
> @@ -1372,9 +1353,9 @@ 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_summary (callee)->stack_frame_offset,
> -		   (int) inline_summary (callee)->estimated_self_stack_size,
> -		   (int) inline_summary (callee)->estimated_stack_size);
> +		   (int) inline_summary_d->get (callee)->stack_frame_offset,
> +		   (int) inline_summary_d->get (callee)->estimated_self_stack_size,
> +		   (int) inline_summary_d->get (callee)->estimated_stack_size);
>  	  dump_inline_edge_summary (f, indent + 2, callee, info);
>  	}
>      }
> @@ -1402,7 +1383,7 @@ dump_inline_summary (FILE *f, struct cgraph_node *node)
>  {
>    if (node->definition)
>      {
> -      struct inline_summary *s = inline_summary (node);
> +      inline_summary *s = inline_summary_d->get (node);
>        size_time_entry *e;
>        int i;
>        fprintf (f, "Inline summary for %s/%i", node->name (),
> @@ -1725,7 +1706,7 @@ eliminated_by_inlining_prob (gimple stmt)
>  
>  static void
>  set_cond_stmt_execution_predicate (struct ipa_node_params *info,
> -				   struct inline_summary *summary,
> +				   inline_summary *summary,
>  				   basic_block bb)
>  {
>    gimple last;
> @@ -1810,7 +1791,7 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
>  
>  static void
>  set_switch_stmt_execution_predicate (struct ipa_node_params *info,
> -				     struct inline_summary *summary,
> +				     inline_summary *summary,
>  				     basic_block bb)
>  {
>    gimple last;
> @@ -1871,7 +1852,7 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
>  static void
>  compute_bb_predicates (struct cgraph_node *node,
>  		       struct ipa_node_params *parms_info,
> -		       struct inline_summary *summary)
> +		       inline_summary *summary)
>  {
>    struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
>    bool done = false;
> @@ -1950,7 +1931,7 @@ typedef struct predicate predicate_t;
>  
>  static struct predicate
>  will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
> -				    struct inline_summary *summary,
> +				    inline_summary *summary,
>  				    tree expr,
>  				    vec<predicate_t> nonconstant_names)
>  {
> @@ -2013,7 +1994,7 @@ will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
>  
>  static struct predicate
>  will_be_nonconstant_predicate (struct ipa_node_params *info,
> -			       struct inline_summary *summary,
> +			       inline_summary *summary,
>  			       gimple stmt,
>  			       vec<predicate_t> nonconstant_names)
>  {
> @@ -2215,7 +2196,7 @@ param_change_prob (gimple stmt, int i)
>  
>  static bool
>  phi_result_unknown_predicate (struct ipa_node_params *info,
> -			      struct inline_summary *summary, basic_block bb,
> +			      inline_summary *summary, basic_block bb,
>  			      struct predicate *p,
>  			      vec<predicate_t> nonconstant_names)
>  {
> @@ -2274,7 +2255,7 @@ phi_result_unknown_predicate (struct ipa_node_params *info,
>     NONCONSTANT_NAMES, if possible.  */
>  
>  static void
> -predicate_for_phi_result (struct inline_summary *summary, gimple phi,
> +predicate_for_phi_result (inline_summary *summary, gimple phi,
>  			  struct predicate *p,
>  			  vec<predicate_t> nonconstant_names)
>  {
> @@ -2304,7 +2285,7 @@ predicate_for_phi_result (struct inline_summary *summary, gimple phi,
>  /* Return predicate specifying when array index in access OP becomes non-constant.  */
>  
>  static struct predicate
> -array_index_predicate (struct inline_summary *info,
> +array_index_predicate (inline_summary *info,
>  		       vec< predicate_t> nonconstant_names, tree op)
>  {
>    struct predicate p = false_predicate ();
> @@ -2460,7 +2441,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>    gimple_stmt_iterator bsi;
>    struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
>    int freq;
> -  struct inline_summary *info = inline_summary (node);
> +  inline_summary *info = inline_summary_d->get (node);
>    struct predicate bb_predicate;
>    struct ipa_node_params *parms_info = NULL;
>    vec<predicate_t> nonconstant_names = vNULL;
> @@ -2702,7 +2683,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>  	    }
>  	}
>      }
> -  set_hint_predicate (&inline_summary (node)->array_index, array_index);
> +  set_hint_predicate (&inline_summary_d->get (node)->array_index, array_index);
>    time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
>    if (time > MAX_TIME)
>      time = MAX_TIME;
> @@ -2790,9 +2771,9 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>  	    }
>  	  free (body);
>  	}
> -      set_hint_predicate (&inline_summary (node)->loop_iterations,
> +      set_hint_predicate (&inline_summary_d->get (node)->loop_iterations,
>  			  loop_iterations);
> -      set_hint_predicate (&inline_summary (node)->loop_stride, loop_stride);
> +      set_hint_predicate (&inline_summary_d->get (node)->loop_stride, loop_stride);
>        scev_finalize ();
>      }
>    FOR_ALL_BB_FN (bb, my_function)
> @@ -2810,8 +2791,8 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>  	  e->aux = NULL;
>  	}
>      }
> -  inline_summary (node)->self_time = time;
> -  inline_summary (node)->self_size = size;
> +  inline_summary_d->get (node)->self_time = time;
> +  inline_summary_d->get (node)->self_size = size;
>    nonconstant_names.release ();
>    if (optimize && !early)
>      {
> @@ -2834,14 +2815,14 @@ compute_inline_parameters (struct cgraph_node *node, bool early)
>  {
>    HOST_WIDE_INT self_stack_size;
>    struct cgraph_edge *e;
> -  struct inline_summary *info;
> +  inline_summary *info;
>  
>    gcc_assert (!node->global.inlined_to);
>  
>    inline_summary_alloc ();
>  
> -  info = inline_summary (node);
> -  reset_inline_summary (node);
> +  info = inline_summary_d->get (node);
> +  reset_inline_summary (node, info);
>  
>    /* FIXME: Thunks are inlinable, but tree-inline don't know how to do that.
>       Once this happen, we will need to more curefully predict call
> @@ -2982,7 +2963,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
>  {
>    tree target;
>    struct cgraph_node *callee;
> -  struct inline_summary *isummary;
> +  inline_summary *isummary;
>    enum availability avail;
>  
>    if (!known_vals.exists () && !known_binfos.exists ())
> @@ -3007,7 +2988,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
>    callee = callee->function_symbol (&avail);
>    if (avail < AVAIL_AVAILABLE)
>      return false;
> -  isummary = inline_summary (callee);
> +  isummary = inline_summary_d->get (callee);
>    return isummary->inlinable;
>  }
>  
> @@ -3120,7 +3101,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
>  			     vec<inline_param_summary>
>  			     inline_param_summary)
>  {
> -  struct inline_summary *info = inline_summary (node);
> +  inline_summary *info = inline_summary_d->get (node);
>    size_time_entry *e;
>    int size = 0;
>    int time = 0;
> @@ -3246,8 +3227,8 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
>     for other purposes).  */
>  
>  static struct predicate
> -remap_predicate (struct inline_summary *info,
> -		 struct inline_summary *callee_info,
> +remap_predicate (inline_summary *info,
> +		 inline_summary *callee_info,
>  		 struct predicate *p,
>  		 vec<int> operand_map,
>  		 vec<int> offset_map,
> @@ -3336,8 +3317,8 @@ static void
>  inline_update_callee_summaries (struct cgraph_node *node, int depth)
>  {
>    struct cgraph_edge *e;
> -  struct inline_summary *callee_info = inline_summary (node);
> -  struct inline_summary *caller_info = inline_summary (node->callers->caller);
> +  inline_summary *callee_info = inline_summary_d->get (node);
> +  inline_summary *caller_info = inline_summary_d->get (node->callers->caller);
>    HOST_WIDE_INT peak;
>  
>    callee_info->stack_frame_offset
> @@ -3345,8 +3326,8 @@ 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_summary (node->global.inlined_to)->estimated_stack_size < peak)
> -      inline_summary (node->global.inlined_to)->estimated_stack_size = peak;
> +  if (inline_summary_d->get (node->global.inlined_to)->estimated_stack_size < peak)
> +      inline_summary_d->get (node->global.inlined_to)->estimated_stack_size = peak;
>    ipa_propagate_frequency (node);
>    for (e = node->callees; e; e = e->next_callee)
>      {
> @@ -3407,8 +3388,8 @@ remap_edge_change_prob (struct cgraph_edge *inlined_edge,
>  static void
>  remap_edge_summaries (struct cgraph_edge *inlined_edge,
>  		      struct cgraph_node *node,
> -		      struct inline_summary *info,
> -		      struct inline_summary *callee_info,
> +		      inline_summary *info,
> +		      inline_summary *callee_info,
>  		      vec<int> operand_map,
>  		      vec<int> offset_map,
>  		      clause_t possible_truths,
> @@ -3476,8 +3457,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
>  /* Same as remap_predicate, but set result into hint *HINT.  */
>  
>  static void
> -remap_hint_predicate (struct inline_summary *info,
> -		      struct inline_summary *callee_info,
> +remap_hint_predicate (inline_summary *info,
> +		      inline_summary *callee_info,
>  		      struct predicate **hint,
>  		      vec<int> operand_map,
>  		      vec<int> offset_map,
> @@ -3506,10 +3487,10 @@ remap_hint_predicate (struct inline_summary *info,
>  void
>  inline_merge_summary (struct cgraph_edge *edge)
>  {
> -  struct inline_summary *callee_info = inline_summary (edge->callee);
> +  inline_summary *callee_info = inline_summary_d->get (edge->callee);
>    struct cgraph_node *to = (edge->caller->global.inlined_to
>  			    ? edge->caller->global.inlined_to : edge->caller);
> -  struct inline_summary *info = inline_summary (to);
> +  inline_summary *info = inline_summary_d->get (to);
>    clause_t clause = 0;		/* not_inline is known to be false.  */
>    size_time_entry *e;
>    vec<int> operand_map = vNULL;
> @@ -3618,7 +3599,7 @@ inline_merge_summary (struct cgraph_edge *edge)
>  void
>  inline_update_overall_summary (struct cgraph_node *node)
>  {
> -  struct inline_summary *info = inline_summary (node);
> +  inline_summary *info = inline_summary_d->get (node);
>    size_time_entry *e;
>    int i;
>  
> @@ -3645,8 +3626,8 @@ simple_edge_hints (struct cgraph_edge *edge)
>    int hints = 0;
>    struct cgraph_node *to = (edge->caller->global.inlined_to
>  			    ? edge->caller->global.inlined_to : edge->caller);
> -  if (inline_summary (to)->scc_no
> -      && inline_summary (to)->scc_no == inline_summary (edge->callee)->scc_no
> +  if (inline_summary_d->get (to)->scc_no
> +      && inline_summary_d->get (to)->scc_no == inline_summary_d->get (edge->callee)->scc_no
>        && !edge->recursive_p ())
>      hints |= INLINE_HINT_same_scc;
>  
> @@ -3706,7 +3687,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
>    /* When caching, update the cache entry.  */
>    if (edge_growth_cache.exists ())
>      {
> -      inline_summary (edge->callee)->min_size = min_size;
> +      inline_summary_d->get (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);
> @@ -3808,14 +3789,14 @@ estimate_time_after_inlining (struct cgraph_node *node,
>    if (!es->predicate || !false_predicate_p (es->predicate))
>      {
>        gcov_type time =
> -	inline_summary (node)->time + estimate_edge_time (edge);
> +	inline_summary_d->get (node)->time + estimate_edge_time (edge);
>        if (time < 0)
>  	time = 0;
>        if (time > MAX_TIME)
>  	time = MAX_TIME;
>        return time;
>      }
> -  return inline_summary (node)->time;
> +  return inline_summary_d->get (node)->time;
>  }
>  
>  
> @@ -3829,11 +3810,11 @@ estimate_size_after_inlining (struct cgraph_node *node,
>    struct inline_edge_summary *es = inline_edge_summary (edge);
>    if (!es->predicate || !false_predicate_p (es->predicate))
>      {
> -      int size = inline_summary (node)->size + estimate_edge_growth (edge);
> +      int size = inline_summary_d->get (node)->size + estimate_edge_growth (edge);
>        gcc_assert (size >= 0);
>        return size;
>      }
> -  return inline_summary (node)->size;
> +  return inline_summary_d->get (node)->size;
>  }
>  
>  
> @@ -3873,7 +3854,7 @@ int
>  do_estimate_growth (struct cgraph_node *node)
>  {
>    struct growth_data d = { node, 0, false };
> -  struct inline_summary *info = inline_summary (node);
> +  inline_summary *info = inline_summary_d->get (node);
>  
>    node->call_for_symbol_thunks_and_aliases (do_estimate_growth_1, &d, true);
>  
> @@ -3946,7 +3927,7 @@ growth_likely_positive (struct cgraph_node *node, int edge_growth ATTRIBUTE_UNUS
>        && (!DECL_COMDAT (node->decl)
>  	  || !node->can_remove_if_no_direct_calls_p ()))
>      return true;
> -  max_callers = inline_summary (node)->size * 4 / edge_growth + 2;
> +  max_callers = inline_summary_d->get (node)->size * 4 / edge_growth + 2;
>  
>    for (e = node->callers; e; e = e->next_caller)
>      {
> @@ -4009,13 +3990,12 @@ inline_analyze_function (struct cgraph_node *node)
>  
>  /* Called when new function is inserted to callgraph late.  */
>  
> -static void
> -add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
> +void
> +inline_summary_t::insert (cgraph_node *node, inline_summary *)
>  {
>    inline_analyze_function (node);
>  }
>  
> -
>  /* Note function body size.  */
>  
>  void
> @@ -4028,8 +4008,10 @@ inline_generate_summary (void)
>    if (!optimize && !flag_lto && !flag_wpa)
>      return;
>  
> -  function_insertion_hook_holder =
> -    symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
> +  if (!inline_summary_d)
> +    inline_summary_d = (inline_summary_t*) inline_summary_t::create_ggc (symtab);
> +
> +  inline_summary_d->enable_insertion_hook ();
>  
>    ipa_register_cgraph_hooks ();
>    inline_free_summary ();
> @@ -4113,7 +4095,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
>      {
>        unsigned int index;
>        struct cgraph_node *node;
> -      struct inline_summary *info;
> +      inline_summary *info;
>        lto_symtab_encoder_t encoder;
>        struct bitpack_d bp;
>        struct cgraph_edge *e;
> @@ -4123,7 +4105,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_summary (node);
> +      info = inline_summary_d->get (node);
>  
>        info->estimated_stack_size
>  	= info->estimated_self_stack_size = streamer_read_uhwi (&ib);
> @@ -4212,8 +4194,9 @@ inline_read_summary (void)
>        if (!flag_ipa_cp)
>  	ipa_prop_read_jump_functions ();
>      }
> -  function_insertion_hook_holder =
> -    symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
> +
> +  gcc_assert (inline_summary_d);
> +  inline_summary_d->enable_insertion_hook ();
>  }
>  
>  
> @@ -4279,7 +4262,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_summary (node);
> +	  inline_summary *info = inline_summary_d->get (node);
>  	  struct bitpack_d bp;
>  	  struct cgraph_edge *edge;
>  	  int i;
> @@ -4344,23 +4327,15 @@ inline_free_summary (void)
>      return;
>    FOR_EACH_DEFINED_FUNCTION (node)
>      if (!node->alias)
> -      reset_inline_summary (node);
> -  if (function_insertion_hook_holder)
> -    symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
> -  function_insertion_hook_holder = NULL;
> -  if (node_removal_hook_holder)
> -    symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
> -  node_removal_hook_holder = NULL;
> +      reset_inline_summary (node, inline_summary_d->get (node));
>    if (edge_removal_hook_holder)
>      symtab->remove_edge_removal_hook (edge_removal_hook_holder);
>    edge_removal_hook_holder = NULL;
> -  if (node_duplication_hook_holder)
> -    symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
> -  node_duplication_hook_holder = NULL;
>    if (edge_duplication_hook_holder)
>      symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
>    edge_duplication_hook_holder = NULL;
> -  vec_free (inline_summary_vec);
> +  inline_summary_d->destroy ();
> +  inline_summary_d = NULL;
>    inline_edge_summary_vec.release ();
>    if (edge_predicate_pool)
>      free_alloc_pool (edge_predicate_pool);
> diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
> index 49c2679..841af60 100644
> --- a/gcc/ipa-inline-transform.c
> +++ b/gcc/ipa-inline-transform.c
> @@ -200,7 +200,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
>  	  if (e->callee->definition && !DECL_EXTERNAL (e->callee->decl))
>  	    {
>  	      if (overall_size)
> -	        *overall_size -= inline_summary (e->callee)->size;
> +	        *overall_size -= inline_summary_d->get (e->callee)->size;
>  	      nfunctions_inlined++;
>  	    }
>  	  duplicate = false;
> @@ -309,13 +309,13 @@ inline_call (struct cgraph_edge *e, bool update_original,
>  
>    gcc_assert (curr->callee->global.inlined_to == to);
>  
> -  old_size = inline_summary (to)->size;
> +  old_size = inline_summary_d->get (to)->size;
>    inline_merge_summary (e);
>    if (optimize)
>      new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges);
>    if (update_overall_summary)
>     inline_update_overall_summary (to);
> -  new_size = inline_summary (to)->size;
> +  new_size = inline_summary_d->get (to)->size;
>  
>    if (callee->calls_comdat_local)
>      to->calls_comdat_local = true;
> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
> index a8e94e2..73fb286 100644
> --- a/gcc/ipa-inline.c
> +++ b/gcc/ipa-inline.c
> @@ -167,7 +167,7 @@ caller_growth_limits (struct cgraph_edge *e)
>    int newsize;
>    int limit = 0;
>    HOST_WIDE_INT stack_size_limit = 0, inlined_stack;
> -  struct inline_summary *info, *what_info, *outer_info = inline_summary (to);
> +  inline_summary *info, *what_info, *outer_info = inline_summary_d->get (to);
>  
>    /* Look for function e->caller is inlined to.  While doing
>       so work out the largest function body on the way.  As
> @@ -179,7 +179,7 @@ caller_growth_limits (struct cgraph_edge *e)
>       too much in order to prevent compiler from exploding".  */
>    while (true)
>      {
> -      info = inline_summary (to);
> +      info = inline_summary_d->get (to);
>        if (limit < info->self_size)
>  	limit = info->self_size;
>        if (stack_size_limit < info->estimated_self_stack_size)
> @@ -190,7 +190,7 @@ caller_growth_limits (struct cgraph_edge *e)
>  	break;
>      }
>  
> -  what_info = inline_summary (what);
> +  what_info = inline_summary_d->get (what);
>  
>    if (limit < what_info->self_size)
>      limit = what_info->self_size;
> @@ -304,7 +304,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
>        e->inline_failed = CIF_USES_COMDAT_LOCAL;
>        inlinable = false;
>      }
> -  else if (!inline_summary (callee)->inlinable 
> +  else if (!inline_summary_d->get (callee)->inlinable 
>  	   || (caller_fun && fn_contains_cilk_spawn_p (caller_fun)))
>      {
>        e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
> @@ -458,7 +458,7 @@ want_early_inline_function_p (struct cgraph_edge *e)
>  
>    if (DECL_DISREGARD_INLINE_LIMITS (callee->decl))
>      ;
> -  /* For AutoFDO, we need to make sure that before profile annotation, all
> +  /* For AutoFDO, we need to make sure that before profile summary, all
>       hot paths' IR look exactly the same as profiled binary. As a result,
>       in einliner, we will disregard size limit and inline those callsites
>       that are:
> @@ -524,13 +524,12 @@ want_early_inline_function_p (struct cgraph_edge *e)
>     does not happen.  */
>  
>  inline gcov_type
> -compute_uninlined_call_time (struct inline_summary *callee_info,
> -			     struct cgraph_edge *edge)
> +compute_uninlined_call_time (inline_summary *callee_info, cgraph_edge *edge)
>  {
>    gcov_type uninlined_call_time =
>      RDIV ((gcov_type)callee_info->time * MAX (edge->frequency, 1),
>  	  CGRAPH_FREQ_BASE);
> -  gcov_type caller_time = inline_summary (edge->caller->global.inlined_to
> +  gcov_type caller_time = inline_summary_d->get (edge->caller->global.inlined_to
>  				          ? edge->caller->global.inlined_to
>  				          : edge->caller)->time;
>    return uninlined_call_time + caller_time;
> @@ -543,7 +542,7 @@ inline gcov_type
>  compute_inlined_call_time (struct cgraph_edge *edge,
>  			   int edge_time)
>  {
> -  gcov_type caller_time = inline_summary (edge->caller->global.inlined_to
> +  gcov_type caller_time = inline_summary_d->get (edge->caller->global.inlined_to
>  					  ? edge->caller->global.inlined_to
>  					  : edge->caller)->time;
>    gcov_type time = (caller_time
> @@ -563,7 +562,7 @@ compute_inlined_call_time (struct cgraph_edge *edge,
>  static bool
>  big_speedup_p (struct cgraph_edge *e)
>  {
> -  gcov_type time = compute_uninlined_call_time (inline_summary (e->callee),
> +  gcov_type time = compute_uninlined_call_time (inline_summary_d->get (e->callee),
>  					  	e);
>    gcov_type inlined_time = compute_inlined_call_time (e,
>  					              estimate_edge_time (e));
> @@ -596,7 +595,7 @@ 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_summary (callee)->min_size
> +	   && inline_summary_d->get (callee)->min_size
>  		- inline_edge_summary (e)->call_stmt_size
>  	      > MAX (MAX_INLINE_INSNS_SINGLE, MAX_INLINE_INSNS_AUTO))
>      {
> @@ -604,7 +603,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
>        want_inline = false;
>      }
>    else if ((DECL_DECLARED_INLINE_P (callee->decl) || e->count)
> -	   && inline_summary (callee)->min_size
> +	   && inline_summary_d->get (callee)->min_size
>  		- inline_edge_summary (e)->call_stmt_size
>  	      > 16 * MAX_INLINE_INSNS_SINGLE)
>      {
> @@ -867,8 +866,8 @@ want_inline_function_to_all_callers_p (struct cgraph_node *node, bool cold)
>     1...RELATIVE_TIME_BENEFIT_RANGE  */
>  
>  static inline int
> -relative_time_benefit (struct inline_summary *callee_info,
> -		       struct cgraph_edge *edge,
> +relative_time_benefit (inline_summary *callee_info,
> +		       cgraph_edge *edge,
>  		       int edge_time)
>  {
>    gcov_type relbenefit;
> @@ -913,7 +912,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
>    gcov_type badness;
>    int growth, edge_time;
>    struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
> -  struct inline_summary *callee_info = inline_summary (callee);
> +  inline_summary *callee_info = inline_summary_d->get (callee);
>    inline_hints hints;
>  
>    if (DECL_DISREGARD_INLINE_LIMITS (callee->decl))
> @@ -1188,7 +1187,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
>    struct cgraph_edge *edge;
>    struct ipa_ref *ref;
>  
> -  if ((!node->alias && !inline_summary (node)->inlinable)
> +  if ((!node->alias && !inline_summary_d->get (node)->inlinable)
>        || node->global.inlined_to)
>      return;
>    if (!bitmap_set_bit (updated_nodes, node->uid))
> @@ -1246,7 +1245,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
>             don't need updating.  */
>  	if (e->inline_failed
>  	    && (callee = e->callee->ultimate_alias_target (&avail))
> -	    && inline_summary (callee)->inlinable
> +	    && inline_summary_d->get (callee)->inlinable
>  	    && avail >= AVAIL_AVAILABLE
>  	    && !bitmap_bit_p (updated_nodes, callee->uid))
>  	  {
> @@ -1424,8 +1423,8 @@ 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_summary (master_clone)->size, inline_summary (node)->size,
> -	     inline_summary (master_clone)->time, inline_summary (node)->time);
> +	     inline_summary_d->get (master_clone)->size, inline_summary_d->get (node)->size,
> +	     inline_summary_d->get (master_clone)->time, inline_summary_d->get (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
> @@ -1599,8 +1598,8 @@ inline_small_functions (void)
>  	if (node->has_gimple_body_p ()
>  	    || node->thunk.thunk_p)
>  	  {
> -	    struct inline_summary *info = inline_summary (node);
> -	    struct ipa_dfs_info *dfs = (struct ipa_dfs_info *) node->aux;
> +	    inline_summary *info = inline_summary_d->get (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.  */
> @@ -1610,12 +1609,12 @@ inline_small_functions (void)
>  	    info->growth = estimate_growth (node);
>  	    if (dfs && dfs->next_cycle)
>  	      {
> -		struct cgraph_node *n2;
> +		cgraph_node *n2;
>  		int id = dfs->scc_no + 1;
>  		for (n2 = node; n2;
>  		     n2 = ((struct ipa_dfs_info *) node->aux)->next_cycle)
>  		  {
> -		    struct inline_summary *info2 = inline_summary (n2);
> +		    inline_summary *info2 = inline_summary_d->get (n2);
>  		    if (info2->scc_no)
>  		      break;
>  		    info2->scc_no = id;
> @@ -1735,7 +1734,7 @@ inline_small_functions (void)
>  	  fprintf (dump_file,
>  		   "\nConsidering %s/%i with %i size\n",
>  		   callee->name (), callee->order,
> -		   inline_summary (callee)->size);
> +		   inline_summary_d->get (callee)->size);
>  	  fprintf (dump_file,
>  		   " to be inlined into %s/%i in %s:%i\n"
>  		   " Estimated badness is %i, frequency %.2f.\n",
> @@ -1853,8 +1852,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_summary (edge->caller)->time,
> -		   inline_summary (edge->caller)->size,
> +		   inline_summary_d->get (edge->caller)->time,
> +		   inline_summary_d->get (edge->caller)->size,
>  		   overall_size - old_size);
>  	}
>        if (min_size > overall_size)
> @@ -1992,11 +1991,11 @@ inline_to_all_callers (struct cgraph_node *node, void *data)
>  	  fprintf (dump_file,
>  		   "\nInlining %s size %i.\n",
>  		   node->name (),
> -		   inline_summary (node)->size);
> +		   inline_summary_d->get (node)->size);
>  	  fprintf (dump_file,
>  		   " Called once from %s %i insns.\n",
>  		   node->callers->caller->name (),
> -		   inline_summary (node->callers->caller)->size);
> +		   inline_summary_d->get (node->callers->caller)->size);
>  	}
>  
>        inline_call (node->callers, true, NULL, NULL, true, &callee_removed);
> @@ -2004,7 +2003,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_summary (caller)->size);
> +		 inline_summary_d->get (caller)->size);
>        if (!(*num_calls)--)
>  	{
>  	  if (dump_file)
> @@ -2028,7 +2027,7 @@ dump_overall_stats (void)
>      if (!node->global.inlined_to
>  	&& !node->alias)
>        {
> -	int time = inline_summary (node)->time;
> +	int time = inline_summary_d->get (node)->time;
>  	sum += time;
>  	sum_weighted += time * node->count;
>        }
> @@ -2345,7 +2344,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_summary (callee)->inlinable
> +      if (!inline_summary_d->get (callee)->inlinable
>  	  || !e->inline_failed)
>  	continue;
>  
> diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h
> index 2ac6e4e..7a939f4 100644
> --- a/gcc/ipa-inline.h
> +++ b/gcc/ipa-inline.h
> @@ -162,10 +162,28 @@ struct GTY(()) inline_summary
>    int scc_no;
>  };
>  
> -/* Need a typedef for inline_summary because of inline function
> -   'inline_summary' below.  */
> -typedef struct inline_summary inline_summary_t;
> -extern GTY(()) vec<inline_summary_t, va_gc> *inline_summary_vec;
> +class GTY((user)) inline_summary_t: public function_summary <inline_summary *>
> +{
> +public:
> +  inline_summary_t (symbol_table *symtab, bool ggc):
> +    function_summary <inline_summary *> (symtab, ggc) {}
> +
> +  static inline_summary_t *create_ggc (symbol_table *symtab)
> +  {
> +    inline_summary_t *summary = new (ggc_cleared_alloc <inline_summary_t> ())
> +      inline_summary_t(symtab, true);
> +    summary->disable_insertion_hook ();
> +    return summary;
> +  }
> +
> +
> +  virtual void insert (cgraph_node *, inline_summary *);
> +  virtual void remove (cgraph_node *node, inline_summary *);
> +  virtual void duplicate (cgraph_node *src, cgraph_node *dst,
> +			  inline_summary *src_data, inline_summary *dst_data);
> +};
> +
> +extern GTY(()) function_summary <inline_summary *> *inline_summary_d;
>  
>  /* Information kept about parameter of call site.  */
>  struct inline_param_summary
> @@ -249,12 +267,6 @@ void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *,
>  extern int ncalls_inlined;
>  extern int nfunctions_inlined;
>  
> -static inline struct inline_summary *
> -inline_summary (struct cgraph_node *node)
> -{
> -  return &(*inline_summary_vec)[node->uid];
> -}
> -
>  static inline struct inline_edge_summary *
>  inline_edge_summary (struct cgraph_edge *edge)
>  {
> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
> index 5e25fd8..387209b 100644
> --- a/gcc/ipa-prop.h
> +++ b/gcc/ipa-prop.h
> @@ -514,7 +514,7 @@ ipa_get_ith_polymorhic_call_context (struct ipa_edge_args *args, int i)
>    return &(*args->polymorphic_call_contexts)[i];
>  }
>  
> -/* Callgraph summary for ipa_node_params.  */
> +/* Function summary for ipa_node_params.  */
>  class ipa_node_params_t: public function_summary <ipa_node_params *>
>  {
>  public:
> @@ -537,7 +537,7 @@ extern GTY(()) vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
>  
>  /* Return the associated parameter/argument info corresponding to the given
>     node/edge.  */
> -#define IPA_NODE_REF(NODE) ((*ipa_node_params_d)[NODE])
> +#define IPA_NODE_REF(NODE) (ipa_node_params_d->get (NODE))
>  #define IPA_EDGE_REF(EDGE) (&(*ipa_edge_args_vector)[(EDGE)->uid])
>  /* This macro checks validity of index returned by
>     ipa_get_param_decl_index function.  */
> diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
> index 16684e2..80c3aac 100644
> --- a/gcc/ipa-split.c
> +++ b/gcc/ipa-split.c
> @@ -1669,7 +1669,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_summary (node)->inlinable)
> +      && !inline_summary_d->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 80b8561..a873635 100644
> --- a/gcc/ipa.c
> +++ b/gcc/ipa.c
> @@ -224,7 +224,7 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
>                                 target->order);
>  	    }
>  	  edge = edge->make_direct (target);
> -	  if (inline_summary_vec)
> +	  if (inline_summary_d)
>  	    inline_update_overall_summary (node);
>  	  else if (edge->call_stmt)
>  	    {
> diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
> index 3a2f9ed..343cd83 100644
> --- a/gcc/lto/lto-partition.c
> +++ b/gcc/lto/lto-partition.c
> @@ -165,7 +165,7 @@ add_symbol_to_partition_1 (ltrans_partition part, symtab_node *node)
>      {
>        struct cgraph_edge *e;
>        if (!node->alias)
> -        part->insns += inline_summary (cnode)->self_size;
> +        part->insns += inline_summary_d->get (cnode)->self_size;
>  
>        /* Add all inline clones and callees that are duplicated.  */
>        for (e = cnode->callees; e; e = e->next_callee)
> @@ -274,7 +274,7 @@ undo_partition (ltrans_partition partition, unsigned int n_nodes)
>        partition->initializers_visited = NULL;
>  
>        if (!node->alias && (cnode = dyn_cast <cgraph_node *> (node)))
> -        partition->insns -= inline_summary (cnode)->self_size;
> +        partition->insns -= inline_summary_d->get (cnode)->self_size;
>        lto_symtab_encoder_delete_node (partition->encoder, node);
>        node->aux = (void *)((size_t)node->aux - 1);
>      }
> @@ -477,7 +477,7 @@ lto_balanced_map (int n_lto_partitions)
>  	else
>  	  order[n_nodes++] = node;
>  	if (!node->alias)
> -	  total_size += inline_summary (node)->size;
> +	  total_size += inline_summary_d->get (node)->size;
>        }
>  
>    /* Streaming works best when the source units do not cross partition
> @@ -534,14 +534,14 @@ lto_balanced_map (int n_lto_partitions)
>  	     && noreorder[noreorder_pos]->order < current_order)
>  	{
>  	  if (!noreorder[noreorder_pos]->alias)
> -	    total_size -= inline_summary (noreorder[noreorder_pos])->size;
> +	    total_size -= inline_summary_d->get (noreorder[noreorder_pos])->size;
>  	  next_nodes.safe_push (noreorder[noreorder_pos++]);
>  	}
>        add_sorted_nodes (next_nodes, partition);
>  
>        add_symbol_to_partition (partition, order[i]);
>        if (!order[i]->alias)
> -        total_size -= inline_summary (order[i])->size;
> +        total_size -= inline_summary_d->get (order[i])->size;
>  	  
>  
>        /* Once we added a new node to the partition, we also want to add
> diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
> index e0c375d..980a97b 100644
> --- a/gcc/tree-sra.c
> +++ b/gcc/tree-sra.c
> @@ -4991,7 +4991,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
>      }
>  
>    if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
> -      && inline_summary (node)->size >= MAX_INLINE_INSNS_AUTO)
> +      && inline_summary_d->get (node)->size >= MAX_INLINE_INSNS_AUTO)
>      {
>        if (dump_file)
>  	fprintf (dump_file, "Function too big to be made truly local.\n");
> -- 
> 2.1.2
>
Martin Jambor Nov. 14, 2014, 6:07 p.m. UTC | #2
On Fri, Nov 14, 2014 at 05:06:44PM +0100, Jan Hubicka wrote:
> > >
> > >In a way I would like to see these to be methods of the underlying type rather than
> > >virtual methods of the summary, becuase these are operations on the data themselves.
> > >I was thinking to model these by specual constructor and copy constructor
> > >(taking the extra node pointer parameters) and standard destructor.  I am not sure this
> > >would be more understandable this way?
> > 
> > Motivation for this implementation is:
> > a) it's useful to have an access to cgraph_node that is associated with a sumary
> 
> Yep, one would have node addition
>  ctor (symtab_node *); (or cgraph/varpool nodes for cgraph/varpool annotations)
> that would default to ctor for implementations that do not care about node.
> And node duplication ctor
>  ctor (summary &, symtab_node *, symtab_node *)
> that would default to copy constructor for data that do not need to be copied.
> 
> I would say that main advantage (in addition to have a way to provide resonable
> defaults) is to make ctors/dtors of the embedded classes working well, so one can
> for example embedd pointer_map and not care about its construction/destruction.

It was actually me who suggested virtual methods instead of
constructors.  My idea was to make the summaries very light-weight and
usable even for simple types.  For example, during IPA-CP propagation
phase, I use an (edge) summary that is basically only a pointer to
cgraph_edge.  I'd even prefer that the default duplication hook would
just do an assignment or a memcpy.

> 
> > b) with GTY, we cannot call destructor
> 
> Everything in symbol table is expecitely memory managed (i.e. enver left
> to be freed by garbage collector). It resists in GTY only to allow linking
> garbage collected object from them and to get PCH working.
> 

Well, if I understand the intent correctly, summaries are for stuff
that is not in the symbol table.  For example jump functions are a
vector of structures possibly containing trees, so everything has to
be in garbage collected memory.

When an edge is removed, it is necessary to be notified about it
immediately, for example to decrement rdesc_refcount (you might argue
that that should be done in a separate hook and not from within a
summary class but then you start to rely on hook invocation ordering
so I think it is better to eventually use the summaries for it too).

Thanks,

Martin
Jan Hubicka Nov. 14, 2014, 7:59 p.m. UTC | #3
> > I would say that main advantage (in addition to have a way to provide resonable
> > defaults) is to make ctors/dtors of the embedded classes working well, so one can
> > for example embedd pointer_map and not care about its construction/destruction.
> 
> It was actually me who suggested virtual methods instead of
> constructors.  My idea was to make the summaries very light-weight and
> usable even for simple types.  For example, during IPA-CP propagation
> phase, I use an (edge) summary that is basically only a pointer to
> cgraph_edge.  I'd even prefer that the default duplication hook would
> just do an assignment or a memcpy.

Yep, I would hope there is a vairant that makes simple types easy but still
allows to put non-PODs into the summaries (or is that possible with current code?)

Perhaps we can have a base class that provides default implementation of the
insertion/duplication ctor via the default ctor/copy ctor?  That would still
require to wrap your pointer in a trivial class, but you would not need to write
any methods.

The container is template anyway, so one would not need virtual methods for
the maintainance?

> 
> > 
> > > b) with GTY, we cannot call destructor
> > 
> > Everything in symbol table is expecitely memory managed (i.e. enver left
> > to be freed by garbage collector). It resists in GTY only to allow linking
> > garbage collected object from them and to get PCH working.
> > 
> 
> Well, if I understand the intent correctly, summaries are for stuff
> that is not in the symbol table.  For example jump functions are a
Correct.
> vector of structures possibly containing trees, so everything has to
> be in garbage collected memory.
> 
> When an edge is removed, it is necessary to be notified about it
> immediately, for example to decrement rdesc_refcount (you might argue
> that that should be done in a separate hook and not from within a
> summary class but then you start to rely on hook invocation ordering
> so I think it is better to eventually use the summaries for it too).

I do not see why ctors/dtors can not do the reference counting. In fact
this is how refcounting is done usually anyway?

Well, I will read the actual implementation and of our C++ guys are fine
with the current form, I think we can give it a try. Refining the "hooks"
part of the API incrementally should be easy.

Honza
> 
> Thanks,
> 
> Martin
Martin Liška Nov. 18, 2014, 10:33 a.m. UTC | #4
On 11/14/2014 05:06 PM, Jan Hubicka wrote:
>>>
>>> In a way I would like to see these to be methods of the underlying type rather than
>>> virtual methods of the summary, becuase these are operations on the data themselves.
>>> I was thinking to model these by specual constructor and copy constructor
>>> (taking the extra node pointer parameters) and standard destructor.  I am not sure this
>>> would be more understandable this way?
>>
>> Motivation for this implementation is:
>> a) it's useful to have an access to cgraph_node that is associated with a sumary
>
> Yep, one would have node addition
>   ctor (symtab_node *); (or cgraph/varpool nodes for cgraph/varpool annotations)
> that would default to ctor for implementations that do not care about node.
> And node duplication ctor
>   ctor (summary &, symtab_node *, symtab_node *)
> that would default to copy constructor for data that do not need to be copied.

Hello.

I have no problem with such construction and destruction, we can also provide
base implementation.

> I would say that main advantage (in addition to have a way to provide resonable
> defaults) is to make ctors/dtors of the embedded classes working well, so one can
> for example embedd pointer_map and not care about its construction/destruction.
>
>> b) with GTY, we cannot call destructor
>
> Everything in symbol table is expecitely memory managed (i.e. enver left
> to be freed by garbage collector). It resists in GTY only to allow linking
> garbage collected object from them and to get PCH working.

However GTY types need to be allocated by ggc_alloc and one can't call dtor.
This was main motivation for providing hooks instead of ctor/dtor API.
Maybe I miss something?

Thanks,
Martin

>
> This is however quite cosmetic issue I would preffer our C++ guys to comment on.  We can
> tweak this incrementally.
>> +void
>> +inline_summary_t::duplicate (cgraph_node *src,
>> +			     cgraph_node *dst,
>> +			     inline_summary *,
>> +			     inline_summary *info)
>
> Also we should have a way to say that the annotation do not need to be duplicated (for example
> when we do not want to annotate inline clones). Probably by adding duplicate_p predicate that
> is called before the actual duplication happens?
>
> The updated patch is OK, I will take a look on the main patch.
>
> Honza
>>   {
>> -  struct inline_summary *info;
>>     inline_summary_alloc ();
>> -  info = inline_summary (dst);
>> -  memcpy (info, inline_summary (src), sizeof (struct inline_summary));
>> +  memcpy (info, inline_summary_d->get (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);
>> @@ -1328,7 +1309,7 @@ free_growth_caches (void)
>>
>>   static void
>>   dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node,
>> -			  struct inline_summary *info)
>> +			  inline_summary *info)
>>   {
>>     struct cgraph_edge *edge;
>>     for (edge = node->callees; edge; edge = edge->next_callee)
>> @@ -1345,8 +1326,8 @@ 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_summary (callee)->size / INLINE_SIZE_SCALE,
>> -	       (int) inline_summary (callee)->estimated_stack_size);
>> +	       (int) inline_summary_d->get (callee)->size / INLINE_SIZE_SCALE,
>> +	       (int) inline_summary_d->get (callee)->estimated_stack_size);
>>
>>         if (es->predicate)
>>   	{
>> @@ -1372,9 +1353,9 @@ 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_summary (callee)->stack_frame_offset,
>> -		   (int) inline_summary (callee)->estimated_self_stack_size,
>> -		   (int) inline_summary (callee)->estimated_stack_size);
>> +		   (int) inline_summary_d->get (callee)->stack_frame_offset,
>> +		   (int) inline_summary_d->get (callee)->estimated_self_stack_size,
>> +		   (int) inline_summary_d->get (callee)->estimated_stack_size);
>>   	  dump_inline_edge_summary (f, indent + 2, callee, info);
>>   	}
>>       }
>> @@ -1402,7 +1383,7 @@ dump_inline_summary (FILE *f, struct cgraph_node *node)
>>   {
>>     if (node->definition)
>>       {
>> -      struct inline_summary *s = inline_summary (node);
>> +      inline_summary *s = inline_summary_d->get (node);
>>         size_time_entry *e;
>>         int i;
>>         fprintf (f, "Inline summary for %s/%i", node->name (),
>> @@ -1725,7 +1706,7 @@ eliminated_by_inlining_prob (gimple stmt)
>>
>>   static void
>>   set_cond_stmt_execution_predicate (struct ipa_node_params *info,
>> -				   struct inline_summary *summary,
>> +				   inline_summary *summary,
>>   				   basic_block bb)
>>   {
>>     gimple last;
>> @@ -1810,7 +1791,7 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info,
>>
>>   static void
>>   set_switch_stmt_execution_predicate (struct ipa_node_params *info,
>> -				     struct inline_summary *summary,
>> +				     inline_summary *summary,
>>   				     basic_block bb)
>>   {
>>     gimple last;
>> @@ -1871,7 +1852,7 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info,
>>   static void
>>   compute_bb_predicates (struct cgraph_node *node,
>>   		       struct ipa_node_params *parms_info,
>> -		       struct inline_summary *summary)
>> +		       inline_summary *summary)
>>   {
>>     struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
>>     bool done = false;
>> @@ -1950,7 +1931,7 @@ typedef struct predicate predicate_t;
>>
>>   static struct predicate
>>   will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
>> -				    struct inline_summary *summary,
>> +				    inline_summary *summary,
>>   				    tree expr,
>>   				    vec<predicate_t> nonconstant_names)
>>   {
>> @@ -2013,7 +1994,7 @@ will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
>>
>>   static struct predicate
>>   will_be_nonconstant_predicate (struct ipa_node_params *info,
>> -			       struct inline_summary *summary,
>> +			       inline_summary *summary,
>>   			       gimple stmt,
>>   			       vec<predicate_t> nonconstant_names)
>>   {
>> @@ -2215,7 +2196,7 @@ param_change_prob (gimple stmt, int i)
>>
>>   static bool
>>   phi_result_unknown_predicate (struct ipa_node_params *info,
>> -			      struct inline_summary *summary, basic_block bb,
>> +			      inline_summary *summary, basic_block bb,
>>   			      struct predicate *p,
>>   			      vec<predicate_t> nonconstant_names)
>>   {
>> @@ -2274,7 +2255,7 @@ phi_result_unknown_predicate (struct ipa_node_params *info,
>>      NONCONSTANT_NAMES, if possible.  */
>>
>>   static void
>> -predicate_for_phi_result (struct inline_summary *summary, gimple phi,
>> +predicate_for_phi_result (inline_summary *summary, gimple phi,
>>   			  struct predicate *p,
>>   			  vec<predicate_t> nonconstant_names)
>>   {
>> @@ -2304,7 +2285,7 @@ predicate_for_phi_result (struct inline_summary *summary, gimple phi,
>>   /* Return predicate specifying when array index in access OP becomes non-constant.  */
>>
>>   static struct predicate
>> -array_index_predicate (struct inline_summary *info,
>> +array_index_predicate (inline_summary *info,
>>   		       vec< predicate_t> nonconstant_names, tree op)
>>   {
>>     struct predicate p = false_predicate ();
>> @@ -2460,7 +2441,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>>     gimple_stmt_iterator bsi;
>>     struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
>>     int freq;
>> -  struct inline_summary *info = inline_summary (node);
>> +  inline_summary *info = inline_summary_d->get (node);
>>     struct predicate bb_predicate;
>>     struct ipa_node_params *parms_info = NULL;
>>     vec<predicate_t> nonconstant_names = vNULL;
>> @@ -2702,7 +2683,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>>   	    }
>>   	}
>>       }
>> -  set_hint_predicate (&inline_summary (node)->array_index, array_index);
>> +  set_hint_predicate (&inline_summary_d->get (node)->array_index, array_index);
>>     time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
>>     if (time > MAX_TIME)
>>       time = MAX_TIME;
>> @@ -2790,9 +2771,9 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>>   	    }
>>   	  free (body);
>>   	}
>> -      set_hint_predicate (&inline_summary (node)->loop_iterations,
>> +      set_hint_predicate (&inline_summary_d->get (node)->loop_iterations,
>>   			  loop_iterations);
>> -      set_hint_predicate (&inline_summary (node)->loop_stride, loop_stride);
>> +      set_hint_predicate (&inline_summary_d->get (node)->loop_stride, loop_stride);
>>         scev_finalize ();
>>       }
>>     FOR_ALL_BB_FN (bb, my_function)
>> @@ -2810,8 +2791,8 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
>>   	  e->aux = NULL;
>>   	}
>>       }
>> -  inline_summary (node)->self_time = time;
>> -  inline_summary (node)->self_size = size;
>> +  inline_summary_d->get (node)->self_time = time;
>> +  inline_summary_d->get (node)->self_size = size;
>>     nonconstant_names.release ();
>>     if (optimize && !early)
>>       {
>> @@ -2834,14 +2815,14 @@ compute_inline_parameters (struct cgraph_node *node, bool early)
>>   {
>>     HOST_WIDE_INT self_stack_size;
>>     struct cgraph_edge *e;
>> -  struct inline_summary *info;
>> +  inline_summary *info;
>>
>>     gcc_assert (!node->global.inlined_to);
>>
>>     inline_summary_alloc ();
>>
>> -  info = inline_summary (node);
>> -  reset_inline_summary (node);
>> +  info = inline_summary_d->get (node);
>> +  reset_inline_summary (node, info);
>>
>>     /* FIXME: Thunks are inlinable, but tree-inline don't know how to do that.
>>        Once this happen, we will need to more curefully predict call
>> @@ -2982,7 +2963,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
>>   {
>>     tree target;
>>     struct cgraph_node *callee;
>> -  struct inline_summary *isummary;
>> +  inline_summary *isummary;
>>     enum availability avail;
>>
>>     if (!known_vals.exists () && !known_binfos.exists ())
>> @@ -3007,7 +2988,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
>>     callee = callee->function_symbol (&avail);
>>     if (avail < AVAIL_AVAILABLE)
>>       return false;
>> -  isummary = inline_summary (callee);
>> +  isummary = inline_summary_d->get (callee);
>>     return isummary->inlinable;
>>   }
>>
>> @@ -3120,7 +3101,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
>>   			     vec<inline_param_summary>
>>   			     inline_param_summary)
>>   {
>> -  struct inline_summary *info = inline_summary (node);
>> +  inline_summary *info = inline_summary_d->get (node);
>>     size_time_entry *e;
>>     int size = 0;
>>     int time = 0;
>> @@ -3246,8 +3227,8 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
>>      for other purposes).  */
>>
>>   static struct predicate
>> -remap_predicate (struct inline_summary *info,
>> -		 struct inline_summary *callee_info,
>> +remap_predicate (inline_summary *info,
>> +		 inline_summary *callee_info,
>>   		 struct predicate *p,
>>   		 vec<int> operand_map,
>>   		 vec<int> offset_map,
>> @@ -3336,8 +3317,8 @@ static void
>>   inline_update_callee_summaries (struct cgraph_node *node, int depth)
>>   {
>>     struct cgraph_edge *e;
>> -  struct inline_summary *callee_info = inline_summary (node);
>> -  struct inline_summary *caller_info = inline_summary (node->callers->caller);
>> +  inline_summary *callee_info = inline_summary_d->get (node);
>> +  inline_summary *caller_info = inline_summary_d->get (node->callers->caller);
>>     HOST_WIDE_INT peak;
>>
>>     callee_info->stack_frame_offset
>> @@ -3345,8 +3326,8 @@ 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_summary (node->global.inlined_to)->estimated_stack_size < peak)
>> -      inline_summary (node->global.inlined_to)->estimated_stack_size = peak;
>> +  if (inline_summary_d->get (node->global.inlined_to)->estimated_stack_size < peak)
>> +      inline_summary_d->get (node->global.inlined_to)->estimated_stack_size = peak;
>>     ipa_propagate_frequency (node);
>>     for (e = node->callees; e; e = e->next_callee)
>>       {
>> @@ -3407,8 +3388,8 @@ remap_edge_change_prob (struct cgraph_edge *inlined_edge,
>>   static void
>>   remap_edge_summaries (struct cgraph_edge *inlined_edge,
>>   		      struct cgraph_node *node,
>> -		      struct inline_summary *info,
>> -		      struct inline_summary *callee_info,
>> +		      inline_summary *info,
>> +		      inline_summary *callee_info,
>>   		      vec<int> operand_map,
>>   		      vec<int> offset_map,
>>   		      clause_t possible_truths,
>> @@ -3476,8 +3457,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
>>   /* Same as remap_predicate, but set result into hint *HINT.  */
>>
>>   static void
>> -remap_hint_predicate (struct inline_summary *info,
>> -		      struct inline_summary *callee_info,
>> +remap_hint_predicate (inline_summary *info,
>> +		      inline_summary *callee_info,
>>   		      struct predicate **hint,
>>   		      vec<int> operand_map,
>>   		      vec<int> offset_map,
>> @@ -3506,10 +3487,10 @@ remap_hint_predicate (struct inline_summary *info,
>>   void
>>   inline_merge_summary (struct cgraph_edge *edge)
>>   {
>> -  struct inline_summary *callee_info = inline_summary (edge->callee);
>> +  inline_summary *callee_info = inline_summary_d->get (edge->callee);
>>     struct cgraph_node *to = (edge->caller->global.inlined_to
>>   			    ? edge->caller->global.inlined_to : edge->caller);
>> -  struct inline_summary *info = inline_summary (to);
>> +  inline_summary *info = inline_summary_d->get (to);
>>     clause_t clause = 0;		/* not_inline is known to be false.  */
>>     size_time_entry *e;
>>     vec<int> operand_map = vNULL;
>> @@ -3618,7 +3599,7 @@ inline_merge_summary (struct cgraph_edge *edge)
>>   void
>>   inline_update_overall_summary (struct cgraph_node *node)
>>   {
>> -  struct inline_summary *info = inline_summary (node);
>> +  inline_summary *info = inline_summary_d->get (node);
>>     size_time_entry *e;
>>     int i;
>>
>> @@ -3645,8 +3626,8 @@ simple_edge_hints (struct cgraph_edge *edge)
>>     int hints = 0;
>>     struct cgraph_node *to = (edge->caller->global.inlined_to
>>   			    ? edge->caller->global.inlined_to : edge->caller);
>> -  if (inline_summary (to)->scc_no
>> -      && inline_summary (to)->scc_no == inline_summary (edge->callee)->scc_no
>> +  if (inline_summary_d->get (to)->scc_no
>> +      && inline_summary_d->get (to)->scc_no == inline_summary_d->get (edge->callee)->scc_no
>>         && !edge->recursive_p ())
>>       hints |= INLINE_HINT_same_scc;
>>
>> @@ -3706,7 +3687,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
>>     /* When caching, update the cache entry.  */
>>     if (edge_growth_cache.exists ())
>>       {
>> -      inline_summary (edge->callee)->min_size = min_size;
>> +      inline_summary_d->get (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);
>> @@ -3808,14 +3789,14 @@ estimate_time_after_inlining (struct cgraph_node *node,
>>     if (!es->predicate || !false_predicate_p (es->predicate))
>>       {
>>         gcov_type time =
>> -	inline_summary (node)->time + estimate_edge_time (edge);
>> +	inline_summary_d->get (node)->time + estimate_edge_time (edge);
>>         if (time < 0)
>>   	time = 0;
>>         if (time > MAX_TIME)
>>   	time = MAX_TIME;
>>         return time;
>>       }
>> -  return inline_summary (node)->time;
>> +  return inline_summary_d->get (node)->time;
>>   }
>>
>>
>> @@ -3829,11 +3810,11 @@ estimate_size_after_inlining (struct cgraph_node *node,
>>     struct inline_edge_summary *es = inline_edge_summary (edge);
>>     if (!es->predicate || !false_predicate_p (es->predicate))
>>       {
>> -      int size = inline_summary (node)->size + estimate_edge_growth (edge);
>> +      int size = inline_summary_d->get (node)->size + estimate_edge_growth (edge);
>>         gcc_assert (size >= 0);
>>         return size;
>>       }
>> -  return inline_summary (node)->size;
>> +  return inline_summary_d->get (node)->size;
>>   }
>>
>>
>> @@ -3873,7 +3854,7 @@ int
>>   do_estimate_growth (struct cgraph_node *node)
>>   {
>>     struct growth_data d = { node, 0, false };
>> -  struct inline_summary *info = inline_summary (node);
>> +  inline_summary *info = inline_summary_d->get (node);
>>
>>     node->call_for_symbol_thunks_and_aliases (do_estimate_growth_1, &d, true);
>>
>> @@ -3946,7 +3927,7 @@ growth_likely_positive (struct cgraph_node *node, int edge_growth ATTRIBUTE_UNUS
>>         && (!DECL_COMDAT (node->decl)
>>   	  || !node->can_remove_if_no_direct_calls_p ()))
>>       return true;
>> -  max_callers = inline_summary (node)->size * 4 / edge_growth + 2;
>> +  max_callers = inline_summary_d->get (node)->size * 4 / edge_growth + 2;
>>
>>     for (e = node->callers; e; e = e->next_caller)
>>       {
>> @@ -4009,13 +3990,12 @@ inline_analyze_function (struct cgraph_node *node)
>>
>>   /* Called when new function is inserted to callgraph late.  */
>>
>> -static void
>> -add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
>> +void
>> +inline_summary_t::insert (cgraph_node *node, inline_summary *)
>>   {
>>     inline_analyze_function (node);
>>   }
>>
>> -
>>   /* Note function body size.  */
>>
>>   void
>> @@ -4028,8 +4008,10 @@ inline_generate_summary (void)
>>     if (!optimize && !flag_lto && !flag_wpa)
>>       return;
>>
>> -  function_insertion_hook_holder =
>> -    symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
>> +  if (!inline_summary_d)
>> +    inline_summary_d = (inline_summary_t*) inline_summary_t::create_ggc (symtab);
>> +
>> +  inline_summary_d->enable_insertion_hook ();
>>
>>     ipa_register_cgraph_hooks ();
>>     inline_free_summary ();
>> @@ -4113,7 +4095,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
>>       {
>>         unsigned int index;
>>         struct cgraph_node *node;
>> -      struct inline_summary *info;
>> +      inline_summary *info;
>>         lto_symtab_encoder_t encoder;
>>         struct bitpack_d bp;
>>         struct cgraph_edge *e;
>> @@ -4123,7 +4105,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_summary (node);
>> +      info = inline_summary_d->get (node);
>>
>>         info->estimated_stack_size
>>   	= info->estimated_self_stack_size = streamer_read_uhwi (&ib);
>> @@ -4212,8 +4194,9 @@ inline_read_summary (void)
>>         if (!flag_ipa_cp)
>>   	ipa_prop_read_jump_functions ();
>>       }
>> -  function_insertion_hook_holder =
>> -    symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
>> +
>> +  gcc_assert (inline_summary_d);
>> +  inline_summary_d->enable_insertion_hook ();
>>   }
>>
>>
>> @@ -4279,7 +4262,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_summary (node);
>> +	  inline_summary *info = inline_summary_d->get (node);
>>   	  struct bitpack_d bp;
>>   	  struct cgraph_edge *edge;
>>   	  int i;
>> @@ -4344,23 +4327,15 @@ inline_free_summary (void)
>>       return;
>>     FOR_EACH_DEFINED_FUNCTION (node)
>>       if (!node->alias)
>> -      reset_inline_summary (node);
>> -  if (function_insertion_hook_holder)
>> -    symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
>> -  function_insertion_hook_holder = NULL;
>> -  if (node_removal_hook_holder)
>> -    symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
>> -  node_removal_hook_holder = NULL;
>> +      reset_inline_summary (node, inline_summary_d->get (node));
>>     if (edge_removal_hook_holder)
>>       symtab->remove_edge_removal_hook (edge_removal_hook_holder);
>>     edge_removal_hook_holder = NULL;
>> -  if (node_duplication_hook_holder)
>> -    symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
>> -  node_duplication_hook_holder = NULL;
>>     if (edge_duplication_hook_holder)
>>       symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
>>     edge_duplication_hook_holder = NULL;
>> -  vec_free (inline_summary_vec);
>> +  inline_summary_d->destroy ();
>> +  inline_summary_d = NULL;
>>     inline_edge_summary_vec.release ();
>>     if (edge_predicate_pool)
>>       free_alloc_pool (edge_predicate_pool);
>> diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
>> index 49c2679..841af60 100644
>> --- a/gcc/ipa-inline-transform.c
>> +++ b/gcc/ipa-inline-transform.c
>> @@ -200,7 +200,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
>>   	  if (e->callee->definition && !DECL_EXTERNAL (e->callee->decl))
>>   	    {
>>   	      if (overall_size)
>> -	        *overall_size -= inline_summary (e->callee)->size;
>> +	        *overall_size -= inline_summary_d->get (e->callee)->size;
>>   	      nfunctions_inlined++;
>>   	    }
>>   	  duplicate = false;
>> @@ -309,13 +309,13 @@ inline_call (struct cgraph_edge *e, bool update_original,
>>
>>     gcc_assert (curr->callee->global.inlined_to == to);
>>
>> -  old_size = inline_summary (to)->size;
>> +  old_size = inline_summary_d->get (to)->size;
>>     inline_merge_summary (e);
>>     if (optimize)
>>       new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges);
>>     if (update_overall_summary)
>>      inline_update_overall_summary (to);
>> -  new_size = inline_summary (to)->size;
>> +  new_size = inline_summary_d->get (to)->size;
>>
>>     if (callee->calls_comdat_local)
>>       to->calls_comdat_local = true;
>> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
>> index a8e94e2..73fb286 100644
>> --- a/gcc/ipa-inline.c
>> +++ b/gcc/ipa-inline.c
>> @@ -167,7 +167,7 @@ caller_growth_limits (struct cgraph_edge *e)
>>     int newsize;
>>     int limit = 0;
>>     HOST_WIDE_INT stack_size_limit = 0, inlined_stack;
>> -  struct inline_summary *info, *what_info, *outer_info = inline_summary (to);
>> +  inline_summary *info, *what_info, *outer_info = inline_summary_d->get (to);
>>
>>     /* Look for function e->caller is inlined to.  While doing
>>        so work out the largest function body on the way.  As
>> @@ -179,7 +179,7 @@ caller_growth_limits (struct cgraph_edge *e)
>>        too much in order to prevent compiler from exploding".  */
>>     while (true)
>>       {
>> -      info = inline_summary (to);
>> +      info = inline_summary_d->get (to);
>>         if (limit < info->self_size)
>>   	limit = info->self_size;
>>         if (stack_size_limit < info->estimated_self_stack_size)
>> @@ -190,7 +190,7 @@ caller_growth_limits (struct cgraph_edge *e)
>>   	break;
>>       }
>>
>> -  what_info = inline_summary (what);
>> +  what_info = inline_summary_d->get (what);
>>
>>     if (limit < what_info->self_size)
>>       limit = what_info->self_size;
>> @@ -304,7 +304,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
>>         e->inline_failed = CIF_USES_COMDAT_LOCAL;
>>         inlinable = false;
>>       }
>> -  else if (!inline_summary (callee)->inlinable
>> +  else if (!inline_summary_d->get (callee)->inlinable
>>   	   || (caller_fun && fn_contains_cilk_spawn_p (caller_fun)))
>>       {
>>         e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
>> @@ -458,7 +458,7 @@ want_early_inline_function_p (struct cgraph_edge *e)
>>
>>     if (DECL_DISREGARD_INLINE_LIMITS (callee->decl))
>>       ;
>> -  /* For AutoFDO, we need to make sure that before profile annotation, all
>> +  /* For AutoFDO, we need to make sure that before profile summary, all
>>        hot paths' IR look exactly the same as profiled binary. As a result,
>>        in einliner, we will disregard size limit and inline those callsites
>>        that are:
>> @@ -524,13 +524,12 @@ want_early_inline_function_p (struct cgraph_edge *e)
>>      does not happen.  */
>>
>>   inline gcov_type
>> -compute_uninlined_call_time (struct inline_summary *callee_info,
>> -			     struct cgraph_edge *edge)
>> +compute_uninlined_call_time (inline_summary *callee_info, cgraph_edge *edge)
>>   {
>>     gcov_type uninlined_call_time =
>>       RDIV ((gcov_type)callee_info->time * MAX (edge->frequency, 1),
>>   	  CGRAPH_FREQ_BASE);
>> -  gcov_type caller_time = inline_summary (edge->caller->global.inlined_to
>> +  gcov_type caller_time = inline_summary_d->get (edge->caller->global.inlined_to
>>   				          ? edge->caller->global.inlined_to
>>   				          : edge->caller)->time;
>>     return uninlined_call_time + caller_time;
>> @@ -543,7 +542,7 @@ inline gcov_type
>>   compute_inlined_call_time (struct cgraph_edge *edge,
>>   			   int edge_time)
>>   {
>> -  gcov_type caller_time = inline_summary (edge->caller->global.inlined_to
>> +  gcov_type caller_time = inline_summary_d->get (edge->caller->global.inlined_to
>>   					  ? edge->caller->global.inlined_to
>>   					  : edge->caller)->time;
>>     gcov_type time = (caller_time
>> @@ -563,7 +562,7 @@ compute_inlined_call_time (struct cgraph_edge *edge,
>>   static bool
>>   big_speedup_p (struct cgraph_edge *e)
>>   {
>> -  gcov_type time = compute_uninlined_call_time (inline_summary (e->callee),
>> +  gcov_type time = compute_uninlined_call_time (inline_summary_d->get (e->callee),
>>   					  	e);
>>     gcov_type inlined_time = compute_inlined_call_time (e,
>>   					              estimate_edge_time (e));
>> @@ -596,7 +595,7 @@ 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_summary (callee)->min_size
>> +	   && inline_summary_d->get (callee)->min_size
>>   		- inline_edge_summary (e)->call_stmt_size
>>   	      > MAX (MAX_INLINE_INSNS_SINGLE, MAX_INLINE_INSNS_AUTO))
>>       {
>> @@ -604,7 +603,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
>>         want_inline = false;
>>       }
>>     else if ((DECL_DECLARED_INLINE_P (callee->decl) || e->count)
>> -	   && inline_summary (callee)->min_size
>> +	   && inline_summary_d->get (callee)->min_size
>>   		- inline_edge_summary (e)->call_stmt_size
>>   	      > 16 * MAX_INLINE_INSNS_SINGLE)
>>       {
>> @@ -867,8 +866,8 @@ want_inline_function_to_all_callers_p (struct cgraph_node *node, bool cold)
>>      1...RELATIVE_TIME_BENEFIT_RANGE  */
>>
>>   static inline int
>> -relative_time_benefit (struct inline_summary *callee_info,
>> -		       struct cgraph_edge *edge,
>> +relative_time_benefit (inline_summary *callee_info,
>> +		       cgraph_edge *edge,
>>   		       int edge_time)
>>   {
>>     gcov_type relbenefit;
>> @@ -913,7 +912,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
>>     gcov_type badness;
>>     int growth, edge_time;
>>     struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
>> -  struct inline_summary *callee_info = inline_summary (callee);
>> +  inline_summary *callee_info = inline_summary_d->get (callee);
>>     inline_hints hints;
>>
>>     if (DECL_DISREGARD_INLINE_LIMITS (callee->decl))
>> @@ -1188,7 +1187,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
>>     struct cgraph_edge *edge;
>>     struct ipa_ref *ref;
>>
>> -  if ((!node->alias && !inline_summary (node)->inlinable)
>> +  if ((!node->alias && !inline_summary_d->get (node)->inlinable)
>>         || node->global.inlined_to)
>>       return;
>>     if (!bitmap_set_bit (updated_nodes, node->uid))
>> @@ -1246,7 +1245,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
>>              don't need updating.  */
>>   	if (e->inline_failed
>>   	    && (callee = e->callee->ultimate_alias_target (&avail))
>> -	    && inline_summary (callee)->inlinable
>> +	    && inline_summary_d->get (callee)->inlinable
>>   	    && avail >= AVAIL_AVAILABLE
>>   	    && !bitmap_bit_p (updated_nodes, callee->uid))
>>   	  {
>> @@ -1424,8 +1423,8 @@ 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_summary (master_clone)->size, inline_summary (node)->size,
>> -	     inline_summary (master_clone)->time, inline_summary (node)->time);
>> +	     inline_summary_d->get (master_clone)->size, inline_summary_d->get (node)->size,
>> +	     inline_summary_d->get (master_clone)->time, inline_summary_d->get (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
>> @@ -1599,8 +1598,8 @@ inline_small_functions (void)
>>   	if (node->has_gimple_body_p ()
>>   	    || node->thunk.thunk_p)
>>   	  {
>> -	    struct inline_summary *info = inline_summary (node);
>> -	    struct ipa_dfs_info *dfs = (struct ipa_dfs_info *) node->aux;
>> +	    inline_summary *info = inline_summary_d->get (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.  */
>> @@ -1610,12 +1609,12 @@ inline_small_functions (void)
>>   	    info->growth = estimate_growth (node);
>>   	    if (dfs && dfs->next_cycle)
>>   	      {
>> -		struct cgraph_node *n2;
>> +		cgraph_node *n2;
>>   		int id = dfs->scc_no + 1;
>>   		for (n2 = node; n2;
>>   		     n2 = ((struct ipa_dfs_info *) node->aux)->next_cycle)
>>   		  {
>> -		    struct inline_summary *info2 = inline_summary (n2);
>> +		    inline_summary *info2 = inline_summary_d->get (n2);
>>   		    if (info2->scc_no)
>>   		      break;
>>   		    info2->scc_no = id;
>> @@ -1735,7 +1734,7 @@ inline_small_functions (void)
>>   	  fprintf (dump_file,
>>   		   "\nConsidering %s/%i with %i size\n",
>>   		   callee->name (), callee->order,
>> -		   inline_summary (callee)->size);
>> +		   inline_summary_d->get (callee)->size);
>>   	  fprintf (dump_file,
>>   		   " to be inlined into %s/%i in %s:%i\n"
>>   		   " Estimated badness is %i, frequency %.2f.\n",
>> @@ -1853,8 +1852,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_summary (edge->caller)->time,
>> -		   inline_summary (edge->caller)->size,
>> +		   inline_summary_d->get (edge->caller)->time,
>> +		   inline_summary_d->get (edge->caller)->size,
>>   		   overall_size - old_size);
>>   	}
>>         if (min_size > overall_size)
>> @@ -1992,11 +1991,11 @@ inline_to_all_callers (struct cgraph_node *node, void *data)
>>   	  fprintf (dump_file,
>>   		   "\nInlining %s size %i.\n",
>>   		   node->name (),
>> -		   inline_summary (node)->size);
>> +		   inline_summary_d->get (node)->size);
>>   	  fprintf (dump_file,
>>   		   " Called once from %s %i insns.\n",
>>   		   node->callers->caller->name (),
>> -		   inline_summary (node->callers->caller)->size);
>> +		   inline_summary_d->get (node->callers->caller)->size);
>>   	}
>>
>>         inline_call (node->callers, true, NULL, NULL, true, &callee_removed);
>> @@ -2004,7 +2003,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_summary (caller)->size);
>> +		 inline_summary_d->get (caller)->size);
>>         if (!(*num_calls)--)
>>   	{
>>   	  if (dump_file)
>> @@ -2028,7 +2027,7 @@ dump_overall_stats (void)
>>       if (!node->global.inlined_to
>>   	&& !node->alias)
>>         {
>> -	int time = inline_summary (node)->time;
>> +	int time = inline_summary_d->get (node)->time;
>>   	sum += time;
>>   	sum_weighted += time * node->count;
>>         }
>> @@ -2345,7 +2344,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_summary (callee)->inlinable
>> +      if (!inline_summary_d->get (callee)->inlinable
>>   	  || !e->inline_failed)
>>   	continue;
>>
>> diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h
>> index 2ac6e4e..7a939f4 100644
>> --- a/gcc/ipa-inline.h
>> +++ b/gcc/ipa-inline.h
>> @@ -162,10 +162,28 @@ struct GTY(()) inline_summary
>>     int scc_no;
>>   };
>>
>> -/* Need a typedef for inline_summary because of inline function
>> -   'inline_summary' below.  */
>> -typedef struct inline_summary inline_summary_t;
>> -extern GTY(()) vec<inline_summary_t, va_gc> *inline_summary_vec;
>> +class GTY((user)) inline_summary_t: public function_summary <inline_summary *>
>> +{
>> +public:
>> +  inline_summary_t (symbol_table *symtab, bool ggc):
>> +    function_summary <inline_summary *> (symtab, ggc) {}
>> +
>> +  static inline_summary_t *create_ggc (symbol_table *symtab)
>> +  {
>> +    inline_summary_t *summary = new (ggc_cleared_alloc <inline_summary_t> ())
>> +      inline_summary_t(symtab, true);
>> +    summary->disable_insertion_hook ();
>> +    return summary;
>> +  }
>> +
>> +
>> +  virtual void insert (cgraph_node *, inline_summary *);
>> +  virtual void remove (cgraph_node *node, inline_summary *);
>> +  virtual void duplicate (cgraph_node *src, cgraph_node *dst,
>> +			  inline_summary *src_data, inline_summary *dst_data);
>> +};
>> +
>> +extern GTY(()) function_summary <inline_summary *> *inline_summary_d;
>>
>>   /* Information kept about parameter of call site.  */
>>   struct inline_param_summary
>> @@ -249,12 +267,6 @@ void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *,
>>   extern int ncalls_inlined;
>>   extern int nfunctions_inlined;
>>
>> -static inline struct inline_summary *
>> -inline_summary (struct cgraph_node *node)
>> -{
>> -  return &(*inline_summary_vec)[node->uid];
>> -}
>> -
>>   static inline struct inline_edge_summary *
>>   inline_edge_summary (struct cgraph_edge *edge)
>>   {
>> diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
>> index 5e25fd8..387209b 100644
>> --- a/gcc/ipa-prop.h
>> +++ b/gcc/ipa-prop.h
>> @@ -514,7 +514,7 @@ ipa_get_ith_polymorhic_call_context (struct ipa_edge_args *args, int i)
>>     return &(*args->polymorphic_call_contexts)[i];
>>   }
>>
>> -/* Callgraph summary for ipa_node_params.  */
>> +/* Function summary for ipa_node_params.  */
>>   class ipa_node_params_t: public function_summary <ipa_node_params *>
>>   {
>>   public:
>> @@ -537,7 +537,7 @@ extern GTY(()) vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
>>
>>   /* Return the associated parameter/argument info corresponding to the given
>>      node/edge.  */
>> -#define IPA_NODE_REF(NODE) ((*ipa_node_params_d)[NODE])
>> +#define IPA_NODE_REF(NODE) (ipa_node_params_d->get (NODE))
>>   #define IPA_EDGE_REF(EDGE) (&(*ipa_edge_args_vector)[(EDGE)->uid])
>>   /* This macro checks validity of index returned by
>>      ipa_get_param_decl_index function.  */
>> diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
>> index 16684e2..80c3aac 100644
>> --- a/gcc/ipa-split.c
>> +++ b/gcc/ipa-split.c
>> @@ -1669,7 +1669,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_summary (node)->inlinable)
>> +      && !inline_summary_d->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 80b8561..a873635 100644
>> --- a/gcc/ipa.c
>> +++ b/gcc/ipa.c
>> @@ -224,7 +224,7 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
>>                                  target->order);
>>   	    }
>>   	  edge = edge->make_direct (target);
>> -	  if (inline_summary_vec)
>> +	  if (inline_summary_d)
>>   	    inline_update_overall_summary (node);
>>   	  else if (edge->call_stmt)
>>   	    {
>> diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
>> index 3a2f9ed..343cd83 100644
>> --- a/gcc/lto/lto-partition.c
>> +++ b/gcc/lto/lto-partition.c
>> @@ -165,7 +165,7 @@ add_symbol_to_partition_1 (ltrans_partition part, symtab_node *node)
>>       {
>>         struct cgraph_edge *e;
>>         if (!node->alias)
>> -        part->insns += inline_summary (cnode)->self_size;
>> +        part->insns += inline_summary_d->get (cnode)->self_size;
>>
>>         /* Add all inline clones and callees that are duplicated.  */
>>         for (e = cnode->callees; e; e = e->next_callee)
>> @@ -274,7 +274,7 @@ undo_partition (ltrans_partition partition, unsigned int n_nodes)
>>         partition->initializers_visited = NULL;
>>
>>         if (!node->alias && (cnode = dyn_cast <cgraph_node *> (node)))
>> -        partition->insns -= inline_summary (cnode)->self_size;
>> +        partition->insns -= inline_summary_d->get (cnode)->self_size;
>>         lto_symtab_encoder_delete_node (partition->encoder, node);
>>         node->aux = (void *)((size_t)node->aux - 1);
>>       }
>> @@ -477,7 +477,7 @@ lto_balanced_map (int n_lto_partitions)
>>   	else
>>   	  order[n_nodes++] = node;
>>   	if (!node->alias)
>> -	  total_size += inline_summary (node)->size;
>> +	  total_size += inline_summary_d->get (node)->size;
>>         }
>>
>>     /* Streaming works best when the source units do not cross partition
>> @@ -534,14 +534,14 @@ lto_balanced_map (int n_lto_partitions)
>>   	     && noreorder[noreorder_pos]->order < current_order)
>>   	{
>>   	  if (!noreorder[noreorder_pos]->alias)
>> -	    total_size -= inline_summary (noreorder[noreorder_pos])->size;
>> +	    total_size -= inline_summary_d->get (noreorder[noreorder_pos])->size;
>>   	  next_nodes.safe_push (noreorder[noreorder_pos++]);
>>   	}
>>         add_sorted_nodes (next_nodes, partition);
>>
>>         add_symbol_to_partition (partition, order[i]);
>>         if (!order[i]->alias)
>> -        total_size -= inline_summary (order[i])->size;
>> +        total_size -= inline_summary_d->get (order[i])->size;
>>   	
>>
>>         /* Once we added a new node to the partition, we also want to add
>> diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
>> index e0c375d..980a97b 100644
>> --- a/gcc/tree-sra.c
>> +++ b/gcc/tree-sra.c
>> @@ -4991,7 +4991,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
>>       }
>>
>>     if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
>> -      && inline_summary (node)->size >= MAX_INLINE_INSNS_AUTO)
>> +      && inline_summary_d->get (node)->size >= MAX_INLINE_INSNS_AUTO)
>>       {
>>         if (dump_file)
>>   	fprintf (dump_file, "Function too big to be made truly local.\n");
>> --
>> 2.1.2
>>
>
>
Martin Jambor Nov. 18, 2014, 12:39 p.m. UTC | #5
On Fri, Nov 14, 2014 at 08:59:10PM +0100, Jan Hubicka wrote:
> > > 
> > > > b) with GTY, we cannot call destructor
> > > 
> > > Everything in symbol table is expecitely memory managed (i.e. enver left
> > > to be freed by garbage collector). It resists in GTY only to allow linking
> > > garbage collected object from them and to get PCH working.
> > > 
> > 
> > Well, if I understand the intent correctly, summaries are for stuff
> > that is not in the symbol table.  For example jump functions are a
> Correct.
> > vector of structures possibly containing trees, so everything has to
> > be in garbage collected memory.
> > 
> > When an edge is removed, it is necessary to be notified about it
> > immediately, for example to decrement rdesc_refcount (you might argue
> > that that should be done in a separate hook and not from within a
> > summary class but then you start to rely on hook invocation ordering
> > so I think it is better to eventually use the summaries for it too).
> 
> I do not see why ctors/dtors can not do the reference counting. In fact
> this is how refcounting is done usually anyway?
> 

Well, when there is no garbage collection involved then yes, that is
how you normally do it but in the GC case, there is the question of
what is the appropriate time to call destructor on garbage collected
data (like jump functions)?

Martin
Jan Hubicka Nov. 18, 2014, 3:39 p.m. UTC | #6
> On Fri, Nov 14, 2014 at 08:59:10PM +0100, Jan Hubicka wrote:
> > > > 
> > > > > b) with GTY, we cannot call destructor
> > > > 
> > > > Everything in symbol table is expecitely memory managed (i.e. enver left
> > > > to be freed by garbage collector). It resists in GTY only to allow linking
> > > > garbage collected object from them and to get PCH working.
> > > > 
> > > 
> > > Well, if I understand the intent correctly, summaries are for stuff
> > > that is not in the symbol table.  For example jump functions are a
> > Correct.
> > > vector of structures possibly containing trees, so everything has to
> > > be in garbage collected memory.
> > > 
> > > When an edge is removed, it is necessary to be notified about it
> > > immediately, for example to decrement rdesc_refcount (you might argue
> > > that that should be done in a separate hook and not from within a
> > > summary class but then you start to rely on hook invocation ordering
> > > so I think it is better to eventually use the summaries for it too).
> > 
> > I do not see why ctors/dtors can not do the reference counting. In fact
> > this is how refcounting is done usually anyway?
> > 
> 
> Well, when there is no garbage collection involved then yes, that is
> how you normally do it but in the GC case, there is the question of
> what is the appropriate time to call destructor on garbage collected
> data (like jump functions)?

I still fail to see problem here.  Summaries are explicitly managed- they are
constructed at summary construction time or when new callgarph node is
introduced/duplicated.  They are destroyed when callgarph node is destroyed or
whole summary is ddestroyed.  It is job of the summary datastructure to call
proper ctors/dtors, not job of garbage collector that provides the underlying
memory management.

If you have datastructure that points to something that is not explicitly
managed (i.e. tree expression), you just can not have non-trivial constructor
on that datastructure, because that is freed transparently by gty that don't do
destruction...

Honza
Martin Jambor Nov. 18, 2014, 5:40 p.m. UTC | #7
Hi,

On Tue, Nov 18, 2014 at 04:39:00PM +0100, Jan Hubicka wrote:
> > On Fri, Nov 14, 2014 at 08:59:10PM +0100, Jan Hubicka wrote:
> > > > > 
> > > > > > b) with GTY, we cannot call destructor
> > > > > 
> > > > > Everything in symbol table is expecitely memory managed (i.e. enver left
> > > > > to be freed by garbage collector). It resists in GTY only to allow linking
> > > > > garbage collected object from them and to get PCH working.
> > > > > 
> > > > 
> > > > Well, if I understand the intent correctly, summaries are for stuff
> > > > that is not in the symbol table.  For example jump functions are a
> > > Correct.
> > > > vector of structures possibly containing trees, so everything has to
> > > > be in garbage collected memory.
> > > > 
> > > > When an edge is removed, it is necessary to be notified about it
> > > > immediately, for example to decrement rdesc_refcount (you might argue
> > > > that that should be done in a separate hook and not from within a
> > > > summary class but then you start to rely on hook invocation ordering
> > > > so I think it is better to eventually use the summaries for it too).
> > > 
> > > I do not see why ctors/dtors can not do the reference counting. In fact
> > > this is how refcounting is done usually anyway?
> > > 
> > 
> > Well, when there is no garbage collection involved then yes, that is
> > how you normally do it but in the GC case, there is the question of
> > what is the appropriate time to call destructor on garbage collected
> > data (like jump functions)?
> 
> I still fail to see problem here.  Summaries are explicitly managed- they are
> constructed at summary construction time or when new callgarph node is
> introduced/duplicated.  They are destroyed when callgarph node is destroyed or
> whole summary is ddestroyed.  It is job of the summary datastructure to call
> proper ctors/dtors, not job of garbage collector that provides the underlying
> memory management.

I do not think that all summaries (in the meaning of a description of
one particular symbol table node or call graph edge) are explicitely
managed.  For example ipa_edge_args or ipa_agg_replacement_value
(which my alignment patch changes to ipcp_transformation_summary) are
allocated in GC memory because they contain trees.

> 
> If you have datastructure that points to something that is not
> explicitly managed (i.e. tree expression), you just can not have
> non-trivial constructor on that datastructure, because that is freed
> transparently by gty that don't do destruction...

I admit to not being particularly bright today but that seems to be
exactly my point.

Martin
Jan Hubicka Nov. 18, 2014, 6:59 p.m. UTC | #8
> Hi,
> 
> On Tue, Nov 18, 2014 at 04:39:00PM +0100, Jan Hubicka wrote:
> > > On Fri, Nov 14, 2014 at 08:59:10PM +0100, Jan Hubicka wrote:
> > > > > > 
> > > > > > > b) with GTY, we cannot call destructor
> > > > > > 
> > > > > > Everything in symbol table is expecitely memory managed (i.e. enver left
> > > > > > to be freed by garbage collector). It resists in GTY only to allow linking
> > > > > > garbage collected object from them and to get PCH working.
> > > > > > 
> > > > > 
> > > > > Well, if I understand the intent correctly, summaries are for stuff
> > > > > that is not in the symbol table.  For example jump functions are a
> > > > Correct.
> > > > > vector of structures possibly containing trees, so everything has to
> > > > > be in garbage collected memory.
> > > > > 
> > > > > When an edge is removed, it is necessary to be notified about it
> > > > > immediately, for example to decrement rdesc_refcount (you might argue
> > > > > that that should be done in a separate hook and not from within a
> > > > > summary class but then you start to rely on hook invocation ordering
> > > > > so I think it is better to eventually use the summaries for it too).
> > > > 
> > > > I do not see why ctors/dtors can not do the reference counting. In fact
> > > > this is how refcounting is done usually anyway?
> > > > 
> > > 
> > > Well, when there is no garbage collection involved then yes, that is
> > > how you normally do it but in the GC case, there is the question of
> > > what is the appropriate time to call destructor on garbage collected
> > > data (like jump functions)?
> > 
> > I still fail to see problem here.  Summaries are explicitly managed- they are
> > constructed at summary construction time or when new callgarph node is
> > introduced/duplicated.  They are destroyed when callgarph node is destroyed or
> > whole summary is ddestroyed.  It is job of the summary datastructure to call
> > proper ctors/dtors, not job of garbage collector that provides the underlying
> > memory management.
> 
> I do not think that all summaries (in the meaning of a description of
> one particular symbol table node or call graph edge) are explicitely
> managed.  For example ipa_edge_args or ipa_agg_replacement_value
> (which my alignment patch changes to ipcp_transformation_summary) are
> allocated in GC memory because they contain trees.
> 
> > 
> > If you have datastructure that points to something that is not
> > explicitly managed (i.e. tree expression), you just can not have
> > non-trivial constructor on that datastructure, because that is freed
> > transparently by gty that don't do destruction...
> 
> I admit to not being particularly bright today but that seems to be
> exactly my point.

Well, in your case you have datastructure jump_function that contain a pointer
to tree (EXPR).  What I am trying to explain is that I see no reson why
jump_function needs to be POD. The tree pointed to by EXPR pointer can not
have a dtor by itself because GGC will not call it upon freeing.

It is true that jump_function lives in GGC memory (to make pointer to expr
work) but it never gets removed by ggc_collect because it is always pointed to
by the summary datastructure.  There are two ways to free the jump_function
datastructure.
  1) removing the symbol node it is attached to.
     Here the symtab code will call removal hook that was registered by container
     template. The container will call destructor of jump_function and the ggc_free
     its memory
  2) removing the summary.  In this case I would again expect the container
     template to walk all summaries and free them.

So even if your structure lives in GGC memory it is not really garbage
collected and thus the lack of machinery to call dtors at a time ggc decides to
free something is not a problem?

In fact looking at struct default_hashmap_traits, I see:

  /* Called to dispose of the key and value before marking the entry as
     deleted.  */

  template<typename T> static void remove (T &v) { v.~T (); }

This trait gets called by the underlying hash table so if you have explicitly
managed hashmap (in GGC memory or not), things just work.  Only catch is that
if you let your hashmap to be garbage collected, then your dtor is not called.

So probably the dtors are working same way with Martin's summaries?
I guess we can follow same scheme here, have summary_traits that default
to calling correspondin ctors/dtors. 

Honza

> 
> Martin
Martin Jambor Nov. 18, 2014, 10:25 p.m. UTC | #9
On Tue, Nov 18, 2014 at 07:59:26PM +0100, Jan Hubicka wrote:
> > Hi,
> > 
> > On Tue, Nov 18, 2014 at 04:39:00PM +0100, Jan Hubicka wrote:
> > > > On Fri, Nov 14, 2014 at 08:59:10PM +0100, Jan Hubicka wrote:
> > > > > > > 
> > > > > > > > b) with GTY, we cannot call destructor
> > > > > > > 
> > > > > > > Everything in symbol table is expecitely memory managed (i.e. enver left
> > > > > > > to be freed by garbage collector). It resists in GTY only to allow linking
> > > > > > > garbage collected object from them and to get PCH working.
> > > > > > > 
> > > > > > 
> > > > > > Well, if I understand the intent correctly, summaries are for stuff
> > > > > > that is not in the symbol table.  For example jump functions are a
> > > > > Correct.
> > > > > > vector of structures possibly containing trees, so everything has to
> > > > > > be in garbage collected memory.
> > > > > > 
> > > > > > When an edge is removed, it is necessary to be notified about it
> > > > > > immediately, for example to decrement rdesc_refcount (you might argue
> > > > > > that that should be done in a separate hook and not from within a
> > > > > > summary class but then you start to rely on hook invocation ordering
> > > > > > so I think it is better to eventually use the summaries for it too).
> > > > > 
> > > > > I do not see why ctors/dtors can not do the reference counting. In fact
> > > > > this is how refcounting is done usually anyway?
> > > > > 
> > > > 
> > > > Well, when there is no garbage collection involved then yes, that is
> > > > how you normally do it but in the GC case, there is the question of
> > > > what is the appropriate time to call destructor on garbage collected
> > > > data (like jump functions)?
> > > 
> > > I still fail to see problem here.  Summaries are explicitly managed- they are
> > > constructed at summary construction time or when new callgarph node is
> > > introduced/duplicated.  They are destroyed when callgarph node is destroyed or
> > > whole summary is ddestroyed.  It is job of the summary datastructure to call
> > > proper ctors/dtors, not job of garbage collector that provides the underlying
> > > memory management.
> > 
> > I do not think that all summaries (in the meaning of a description of
> > one particular symbol table node or call graph edge) are explicitely
> > managed.  For example ipa_edge_args or ipa_agg_replacement_value
> > (which my alignment patch changes to ipcp_transformation_summary) are
> > allocated in GC memory because they contain trees.
> > 
> > > 
> > > If you have datastructure that points to something that is not
> > > explicitly managed (i.e. tree expression), you just can not have
> > > non-trivial constructor on that datastructure, because that is freed
> > > transparently by gty that don't do destruction...
> > 
> > I admit to not being particularly bright today but that seems to be
> > exactly my point.
> 
> Well, in your case you have datastructure jump_function that contain a pointer
> to tree (EXPR).  What I am trying to explain is that I see no reson why
> jump_function needs to be POD.

I never said that the summary object needs to be a POD, I only said I
liked the possibility of storing very simple objects (without wrapping
them in classes with constructors and destructors).  That is of course
nothing more than my personal preference.

> The tree pointed to by EXPR pointer can not
> have a dtor by itself because GGC will not call it upon freeing.
> 
> It is true that jump_function lives in GGC memory (to make pointer to expr
> work) but it never gets removed by ggc_collect because it is always pointed to
> by the summary datastructure.  There are two ways to free the jump_function
> datastructure.
>   1) removing the symbol node it is attached to.
>      Here the symtab code will call removal hook that was registered by container
>      template. The container will call destructor of jump_function and the ggc_free
>      its memory
>   2) removing the summary.  In this case I would again expect the container
>      template to walk all summaries and free them.
> 
> So even if your structure lives in GGC memory it is not really garbage
> collected and thus the lack of machinery to call dtors at a time ggc decides to
> free something is not a problem?
> 
> In fact looking at struct default_hashmap_traits, I see:
> 
>   /* Called to dispose of the key and value before marking the entry as
>      deleted.  */
> 
>   template<typename T> static void remove (T &v) { v.~T (); }

Now I see, I should have read your previous email more carefully, by
explicitely managed you mean that destructors will be called
explicitely by the summary infrastructure.  I was wondering how you
wanted to rip the summaries out of GGC memory.

Well, I suppose that would work, and since explicit calls to
destructors are basically the counterpart of placement new that we
already plan to use, it might be actually be the proper C++ thing to
do.

(I am not sure I like it though, for all other purposes the summary
objects will look like managed by the garbage collector and only we
who read this thread will know that the lifetime of the object would
be decoupled from the allocation-span of its memory).

Thanks for the clarification,

Martin

> 
> This trait gets called by the underlying hash table so if you have explicitly
> managed hashmap (in GGC memory or not), things just work.  Only catch is that
> if you let your hashmap to be garbage collected, then your dtor is not called.
> 
> So probably the dtors are working same way with Martin's summaries?
> I guess we can follow same scheme here, have summary_traits that default
> to calling correspondin ctors/dtors. 
> 
> Honza
> 
> > 
> > Martin
Trevor Saunders Nov. 19, 2014, 12:15 a.m. UTC | #10
On Tue, Nov 18, 2014 at 07:59:26PM +0100, Jan Hubicka wrote:
> > Hi,
> > 
> > On Tue, Nov 18, 2014 at 04:39:00PM +0100, Jan Hubicka wrote:
> > > > On Fri, Nov 14, 2014 at 08:59:10PM +0100, Jan Hubicka wrote:
> > > > > > > 
> > > > > > > > b) with GTY, we cannot call destructor
> > > > > > > 
> > > > > > > Everything in symbol table is expecitely memory managed (i.e. enver left
> > > > > > > to be freed by garbage collector). It resists in GTY only to allow linking
> > > > > > > garbage collected object from them and to get PCH working.
> > > > > > > 
> > > > > > 
> > > > > > Well, if I understand the intent correctly, summaries are for stuff
> > > > > > that is not in the symbol table.  For example jump functions are a
> > > > > Correct.
> > > > > > vector of structures possibly containing trees, so everything has to
> > > > > > be in garbage collected memory.
> > > > > > 
> > > > > > When an edge is removed, it is necessary to be notified about it
> > > > > > immediately, for example to decrement rdesc_refcount (you might argue
> > > > > > that that should be done in a separate hook and not from within a
> > > > > > summary class but then you start to rely on hook invocation ordering
> > > > > > so I think it is better to eventually use the summaries for it too).
> > > > > 
> > > > > I do not see why ctors/dtors can not do the reference counting. In fact
> > > > > this is how refcounting is done usually anyway?
> > > > > 
> > > > 
> > > > Well, when there is no garbage collection involved then yes, that is
> > > > how you normally do it but in the GC case, there is the question of
> > > > what is the appropriate time to call destructor on garbage collected
> > > > data (like jump functions)?
> > > 
> > > I still fail to see problem here.  Summaries are explicitly managed- they are
> > > constructed at summary construction time or when new callgarph node is
> > > introduced/duplicated.  They are destroyed when callgarph node is destroyed or
> > > whole summary is ddestroyed.  It is job of the summary datastructure to call
> > > proper ctors/dtors, not job of garbage collector that provides the underlying
> > > memory management.
> > 
> > I do not think that all summaries (in the meaning of a description of
> > one particular symbol table node or call graph edge) are explicitely
> > managed.  For example ipa_edge_args or ipa_agg_replacement_value
> > (which my alignment patch changes to ipcp_transformation_summary) are
> > allocated in GC memory because they contain trees.
> > 
> > > 
> > > If you have datastructure that points to something that is not
> > > explicitly managed (i.e. tree expression), you just can not have
> > > non-trivial constructor on that datastructure, because that is freed
> > > transparently by gty that don't do destruction...
> > 
> > I admit to not being particularly bright today but that seems to be
> > exactly my point.
> 
> Well, in your case you have datastructure jump_function that contain a pointer
> to tree (EXPR).  What I am trying to explain is that I see no reson why
> jump_function needs to be POD. The tree pointed to by EXPR pointer can not
> have a dtor by itself because GGC will not call it upon freeing.

ggc does call dtors when it is about to sweep an object.  however if you
explicitly call ggc_free on an object with a dtor you need to call the
dtor manually I believe.

> It is true that jump_function lives in GGC memory (to make pointer to expr
> work) but it never gets removed by ggc_collect because it is always pointed to
> by the summary datastructure.  There are two ways to free the jump_function
> datastructure.

assuming it doesn't need to go into pch, and I would really think it
never does there's no real reason it has to live on the heap, you could
iterate over all the summaries and mark all the trees they point at
"manually".

>   1) removing the symbol node it is attached to.
>      Here the symtab code will call removal hook that was registered by container
>      template. The container will call destructor of jump_function and the ggc_free
>      its memory
>   2) removing the summary.  In this case I would again expect the container
>      template to walk all summaries and free them.
> 
> So even if your structure lives in GGC memory it is not really garbage
> collected and thus the lack of machinery to call dtors at a time ggc decides to
> free something is not a problem?
> 
> In fact looking at struct default_hashmap_traits, I see:
> 
>   /* Called to dispose of the key and value before marking the entry as
>      deleted.  */
> 
>   template<typename T> static void remove (T &v) { v.~T (); }
> 
> This trait gets called by the underlying hash table so if you have explicitly
> managed hashmap (in GGC memory or not), things just work.  Only catch is that
> if you let your hashmap to be garbage collected, then your dtor is not called.

actually I think it should be, ggc tracks when objects with non trivial
dtors are allocated and sets up finalizers for them to run the dtor.

Trev

> So probably the dtors are working same way with Martin's summaries?
> I guess we can follow same scheme here, have summary_traits that default
> to calling correspondin ctors/dtors. 
> 
> Honza
> 
> > 
> > Martin
Martin Liška Nov. 19, 2014, 12:46 p.m. UTC | #11
On 11/18/2014 11:25 PM, Martin Jambor wrote:
> On Tue, Nov 18, 2014 at 07:59:26PM +0100, Jan Hubicka wrote:
>>> Hi,
>>>
>>> On Tue, Nov 18, 2014 at 04:39:00PM +0100, Jan Hubicka wrote:
>>>>> On Fri, Nov 14, 2014 at 08:59:10PM +0100, Jan Hubicka wrote:
>>>>>>>>
>>>>>>>>> b) with GTY, we cannot call destructor
>>>>>>>>
>>>>>>>> Everything in symbol table is expecitely memory managed (i.e. enver left
>>>>>>>> to be freed by garbage collector). It resists in GTY only to allow linking
>>>>>>>> garbage collected object from them and to get PCH working.
>>>>>>>>
>>>>>>>
>>>>>>> Well, if I understand the intent correctly, summaries are for stuff
>>>>>>> that is not in the symbol table.  For example jump functions are a
>>>>>> Correct.
>>>>>>> vector of structures possibly containing trees, so everything has to
>>>>>>> be in garbage collected memory.
>>>>>>>
>>>>>>> When an edge is removed, it is necessary to be notified about it
>>>>>>> immediately, for example to decrement rdesc_refcount (you might argue
>>>>>>> that that should be done in a separate hook and not from within a
>>>>>>> summary class but then you start to rely on hook invocation ordering
>>>>>>> so I think it is better to eventually use the summaries for it too).
>>>>>>
>>>>>> I do not see why ctors/dtors can not do the reference counting. In fact
>>>>>> this is how refcounting is done usually anyway?
>>>>>>
>>>>>
>>>>> Well, when there is no garbage collection involved then yes, that is
>>>>> how you normally do it but in the GC case, there is the question of
>>>>> what is the appropriate time to call destructor on garbage collected
>>>>> data (like jump functions)?
>>>>
>>>> I still fail to see problem here.  Summaries are explicitly managed- they are
>>>> constructed at summary construction time or when new callgarph node is
>>>> introduced/duplicated.  They are destroyed when callgarph node is destroyed or
>>>> whole summary is ddestroyed.  It is job of the summary datastructure to call
>>>> proper ctors/dtors, not job of garbage collector that provides the underlying
>>>> memory management.
>>>
>>> I do not think that all summaries (in the meaning of a description of
>>> one particular symbol table node or call graph edge) are explicitely
>>> managed.  For example ipa_edge_args or ipa_agg_replacement_value
>>> (which my alignment patch changes to ipcp_transformation_summary) are
>>> allocated in GC memory because they contain trees.
>>>
>>>>
>>>> If you have datastructure that points to something that is not
>>>> explicitly managed (i.e. tree expression), you just can not have
>>>> non-trivial constructor on that datastructure, because that is freed
>>>> transparently by gty that don't do destruction...
>>>
>>> I admit to not being particularly bright today but that seems to be
>>> exactly my point.
>>
>> Well, in your case you have datastructure jump_function that contain a pointer
>> to tree (EXPR).  What I am trying to explain is that I see no reson why
>> jump_function needs to be POD.
>
> I never said that the summary object needs to be a POD, I only said I
> liked the possibility of storing very simple objects (without wrapping
> them in classes with constructors and destructors).  That is of course
> nothing more than my personal preference.
>
>> The tree pointed to by EXPR pointer can not
>> have a dtor by itself because GGC will not call it upon freeing.
>>
>> It is true that jump_function lives in GGC memory (to make pointer to expr
>> work) but it never gets removed by ggc_collect because it is always pointed to
>> by the summary datastructure.  There are two ways to free the jump_function
>> datastructure.
>>    1) removing the symbol node it is attached to.
>>       Here the symtab code will call removal hook that was registered by container
>>       template. The container will call destructor of jump_function and the ggc_free
>>       its memory
>>    2) removing the summary.  In this case I would again expect the container
>>       template to walk all summaries and free them.
>>
>> So even if your structure lives in GGC memory it is not really garbage
>> collected and thus the lack of machinery to call dtors at a time ggc decides to
>> free something is not a problem?
>>
>> In fact looking at struct default_hashmap_traits, I see:
>>
>>    /* Called to dispose of the key and value before marking the entry as
>>       deleted.  */
>>
>>    template<typename T> static void remove (T &v) { v.~T (); }
>
> Now I see, I should have read your previous email more carefully, by
> explicitely managed you mean that destructors will be called
> explicitely by the summary infrastructure.  I was wondering how you
> wanted to rip the summaries out of GGC memory.
>
> Well, I suppose that would work, and since explicit calls to
> destructors are basically the counterpart of placement new that we
> already plan to use, it might be actually be the proper C++ thing to
> do.
>
> (I am not sure I like it though, for all other purposes the summary
> objects will look like managed by the garbage collector and only we
> who read this thread will know that the lifetime of the object would
> be decoupled from the allocation-span of its memory).
>
> Thanks for the clarification,
>
> Martin

Hello.

I tried to come up with ctor/dtor solution for types passes to symbol_summary
template class.

Example:
struct inline_summary
{
   inline_summary (cgraph_node *node);
   inline_summary (inline_summary &data, cgraph_node *node, cgraph_node *node2);
   ~inline_summary ();
}

There's no technical problem, but two practical I noticed:

1) current implementation of reset_inline_summary calls reset_inline_summary(cgraph_node *).
In inline_summary::~inline_summary we are not given cgraph_node. This implies need of a new
method called 'release' which will be called before summary's dtor.

2) current implementation of add_new_function calls inline_analyze_function which
calls compute_inline_parameters. This function invokes inline_summary (inline_summary_d::get) and
this creates infinite loop because inline_summary ctor hasn't finished and the summary
is not stored within function_summary yet.

I think current implementation can be ported to suggested approach (ctors/dtors API), but
I consider this approach very cumbersome.

Thanks,
Martin

>
>>
>> This trait gets called by the underlying hash table so if you have explicitly
>> managed hashmap (in GGC memory or not), things just work.  Only catch is that
>> if you let your hashmap to be garbage collected, then your dtor is not called.
>>
>> So probably the dtors are working same way with Martin's summaries?
>> I guess we can follow same scheme here, have summary_traits that default
>> to calling correspondin ctors/dtors.
>>
>> Honza
>>
>>>
>>> Martin
diff mbox

Patch

From 6e8531d8d3659524e337c7c1d96596952c3ff0e8 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Fri, 14 Nov 2014 14:54:12 +0100
Subject: [PATCH 3/3] Data structure is used for inline_summary struct.

gcc/ChangeLog:

2014-11-12  Martin Liska  <mliska@suse.cz>

	* cgraphunit.c (symbol_table::process_new_functions):
	inline_summary_vec is replaced with inline_summary_t.
	* ipa-cp.c (ipcp_cloning_candidate_p): Usage of inline_summary_d::get.
	(devirtualization_time_bonus): Likewise.
	(estimate_local_effects): Likewise.
	(ipcp_propagate_stage): Likewise.
	* ipa-inline-analysis.c (evaluate_conditions_for_known_args): Likewise.
	(evaluate_properties_for_edge): Likewise.
	(inline_summary_alloc): Deletion of old hook holders.
	(reset_inline_summary): inline_summary is added as argument.
	(inline_summary_cgraph_summary::removal_hook): New function.
	(inline_summary_cgraph_summary::duplication_hook): Likewise.
	(dump_inline_edge_summary): Struct keyword removed.
	(dump_inline_summary): Likewise.
	(estimate_function_body_sizes): Usage of inline_summary_d::get.
	(compute_inline_parameters): Likewise.
	(estimate_edge_devirt_benefit): Struct keyword removed.
	(estimate_node_size_and_time): Likewise.
	(inline_update_callee_summaries): Likewise.
	(inline_merge_summary): Usage of inline_summary_d::get.
	(inline_update_overall_summary): Likewise.
	(simple_edge_hints): Likewise.
	(do_estimate_edge_time): Likewise.
	(estimate_time_after_inlining): Likewise.
	(estimate_size_after_inlining): Likewise.
	(do_estimate_growth): Likewise.
	(growth_likely_positive): Likewise.
	(inline_generate_summary): inline_summary_t is registered.
	(inline_read_section): Struct keyword removed.
	(inline_read_summary): Likewise.
	(inline_write_summary): Likewise.
	(inline_free_summary): Removal of old hook holders.
	* ipa-inline-transform.c (clone_inlined_nodes): Usage of
	inline_summary_d::get.
	(inline_call): Likewise.
	* ipa-inline.c (caller_growth_limits): Struct keyword is removed.
	(can_inline_edge_p): Usage of inline_summary_d::get.
	(want_early_inline_function_p): Struct keyword removed.
	(compute_uninlined_call_time): Usage of inline_summary_d::get.
	(compute_inlined_call_time): Likewise.
	(big_speedup_p): Likewise.
	(want_inline_small_function_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.
	* ipa-inline.h (inline_summary_d::get): New function.
	* ipa-split.c (execute_split_functions): Usage of inline_summary_d::get.
	* ipa.c (walk_polymorphic_call_targets): inline_summary_vec is replaced with inline_summary_t.
	* tree-sra.c (ipa_sra_preliminary_function_checks): Usage of inline_summary_d::get.

gcc/lto/ChangeLog:

2014-11-12  Martin Liska  <mliska@suse.cz>

	* lto-partition.c (add_symbol_to_partition_1): Usage of
	inline_summary_d::get.
	(undo_partition): Likewise.
	(lto_balanced_map): Likewise.
---
 gcc/cgraphunit.c           |   2 +-
 gcc/ipa-cp.c               |  10 +--
 gcc/ipa-inline-analysis.c  | 193 ++++++++++++++++++++-------------------------
 gcc/ipa-inline-transform.c |   6 +-
 gcc/ipa-inline.c           |  61 +++++++-------
 gcc/ipa-inline.h           |  32 +++++---
 gcc/ipa-prop.h             |   4 +-
 gcc/ipa-split.c            |   2 +-
 gcc/ipa.c                  |   2 +-
 gcc/lto/lto-partition.c    |  10 +--
 gcc/tree-sra.c             |   2 +-
 11 files changed, 155 insertions(+), 169 deletions(-)

diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 93f8d91..7486f2a 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -338,7 +338,7 @@  symbol_table::process_new_functions (void)
 	  if (state == IPA_SSA
 	      && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
 	    g->get_passes ()->execute_early_local_passes ();
-	  else if (inline_summary_vec != NULL)
+	  else if (inline_summary_d != NULL)
 	    compute_inline_parameters (node, true);
 	  free_dominance_info (CDI_POST_DOMINATORS);
 	  free_dominance_info (CDI_DOMINATORS);
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 56d1ae9..14684de 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -552,7 +552,7 @@  ipcp_cloning_candidate_p (struct cgraph_node *node)
   init_caller_stats (&stats);
   node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, false);
 
-  if (inline_summary (node)->self_size < stats.n_calls)
+  if (inline_summary_d->get (node)->self_size < stats.n_calls)
     {
       if (dump_file)
         fprintf (dump_file, "Considering %s for cloning; code might shrink.\n",
@@ -1718,7 +1718,7 @@  devirtualization_time_bonus (struct cgraph_node *node,
   for (ie = node->indirect_calls; ie; ie = ie->next_callee)
     {
       struct cgraph_node *callee;
-      struct inline_summary *isummary;
+      inline_summary *isummary;
       enum availability avail;
       tree target;
 
@@ -1735,7 +1735,7 @@  devirtualization_time_bonus (struct cgraph_node *node,
       callee = callee->function_symbol (&avail);
       if (avail < AVAIL_AVAILABLE)
 	continue;
-      isummary = inline_summary (callee);
+      isummary = inline_summary_d->get (callee);
       if (!isummary->inlinable)
 	continue;
 
@@ -1945,7 +1945,7 @@  estimate_local_effects (struct cgraph_node *node)
   vec<ipa_agg_jump_function> known_aggs;
   vec<ipa_agg_jump_function_p> known_aggs_ptrs;
   bool always_const;
-  int base_time = inline_summary (node)->time;
+  int base_time = inline_summary_d->get (node)->time;
   int removable_params_cost;
 
   if (!count || !ipcp_versionable_function_p (node))
@@ -2357,7 +2357,7 @@  ipcp_propagate_stage (struct ipa_topo_info *topo)
 	initialize_node_lattices (node);
       }
     if (node->definition && !node->alias)
-      overall_size += inline_summary (node)->self_size;
+      overall_size += inline_summary_d->get (node)->self_size;
     if (node->count > max_count)
       max_count = node->count;
   }
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index 84da4dc..f0a343a 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -148,21 +148,15 @@  enum predicate_conditions
 #define CHANGED IDENTIFIER_NODE
 
 /* Holders of ipa cgraph hooks: */
-static struct cgraph_node_hook_list *function_insertion_hook_holder;
-static struct cgraph_node_hook_list *node_removal_hook_holder;
-static struct cgraph_2node_hook_list *node_duplication_hook_holder;
 static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
 static struct cgraph_edge_hook_list *edge_removal_hook_holder;
-static void inline_node_removal_hook (struct cgraph_node *, void *);
-static void inline_node_duplication_hook (struct cgraph_node *,
-					  struct cgraph_node *, void *);
 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.  */
-vec<inline_summary_t, va_gc> *inline_summary_vec;
+function_summary <inline_summary *> *inline_summary_d;
 vec<inline_edge_summary_t> inline_edge_summary_vec;
 
 /* Cached node/edge growths.  */
@@ -699,7 +693,7 @@  dump_inline_hints (FILE *f, inline_hints hints)
 /* Record SIZE and TIME under condition PRED into the inline summary.  */
 
 static void
-account_size_time (struct inline_summary *summary, int size, int time,
+account_size_time (inline_summary *summary, int size, int time,
 		   struct predicate *pred)
 {
   size_time_entry *e;
@@ -829,7 +823,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_summary (node);
+  inline_summary *info = inline_summary_d->get (node);
   int i;
   struct condition *c;
 
@@ -900,7 +894,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_summary (callee);
+  inline_summary *info = inline_summary_d->get (callee);
   vec<tree> known_vals = vNULL;
   vec<ipa_agg_jump_function_p> known_aggs = vNULL;
 
@@ -974,21 +968,16 @@  evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 static void
 inline_summary_alloc (void)
 {
-  if (!node_removal_hook_holder)
-    node_removal_hook_holder =
-      symtab->add_cgraph_removal_hook (&inline_node_removal_hook, NULL);
   if (!edge_removal_hook_holder)
     edge_removal_hook_holder =
       symtab->add_edge_removal_hook (&inline_edge_removal_hook, NULL);
-  if (!node_duplication_hook_holder)
-    node_duplication_hook_holder =
-      symtab->add_cgraph_duplication_hook (&inline_node_duplication_hook, NULL);
   if (!edge_duplication_hook_holder)
     edge_duplication_hook_holder =
       symtab->add_edge_duplication_hook (&inline_edge_duplication_hook, NULL);
 
-  if (vec_safe_length (inline_summary_vec) <= (unsigned) symtab->cgraph_max_uid)
-    vec_safe_grow_cleared (inline_summary_vec, symtab->cgraph_max_uid + 1);
+  if (!inline_summary_d)
+    inline_summary_d = (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);
   if (!edge_predicate_pool)
@@ -1018,9 +1007,9 @@  reset_inline_edge_summary (struct cgraph_edge *e)
    data from previous run so they are not cumulated.  */
 
 static void
-reset_inline_summary (struct cgraph_node *node)
+reset_inline_summary (const struct cgraph_node *node,
+		      inline_summary *info)
 {
-  struct inline_summary *info = inline_summary (node);
   struct cgraph_edge *e;
 
   info->self_size = info->self_time = 0;
@@ -1056,16 +1045,10 @@  reset_inline_summary (struct cgraph_node *node)
 
 /* Hook that is called by cgraph.c when a node is removed.  */
 
-static void
-inline_node_removal_hook (struct cgraph_node *node,
-			  void *data ATTRIBUTE_UNUSED)
+void
+inline_summary_t::remove (cgraph_node *node, inline_summary *info)
 {
-  struct inline_summary *info;
-  if (vec_safe_length (inline_summary_vec) <= (unsigned) node->uid)
-    return;
-  info = inline_summary (node);
-  reset_inline_summary (node);
-  memset (info, 0, sizeof (inline_summary_t));
+  reset_inline_summary (node, info);
 }
 
 /* Remap predicate P of former function to be predicate of duplicated function.
@@ -1075,7 +1058,7 @@  inline_node_removal_hook (struct cgraph_node *node,
 static struct predicate
 remap_predicate_after_duplication (struct predicate *p,
 				   clause_t possible_truths,
-				   struct inline_summary *info)
+				   inline_summary *info)
 {
   struct predicate new_predicate = true_predicate ();
   int j;
@@ -1099,7 +1082,7 @@  remap_predicate_after_duplication (struct predicate *p,
 static void
 remap_hint_predicate_after_duplication (struct predicate **p,
 					clause_t possible_truths,
-					struct inline_summary *info)
+					inline_summary *info)
 {
   struct predicate new_predicate;
 
@@ -1115,16 +1098,14 @@  remap_hint_predicate_after_duplication (struct predicate **p,
 
 
 /* Hook that is called by cgraph.c when a node is duplicated.  */
-
-static void
-inline_node_duplication_hook (struct cgraph_node *src,
-			      struct cgraph_node *dst,
-			      ATTRIBUTE_UNUSED void *data)
+void
+inline_summary_t::duplicate (cgraph_node *src,
+			     cgraph_node *dst,
+			     inline_summary *,
+			     inline_summary *info)
 {
-  struct inline_summary *info;
   inline_summary_alloc ();
-  info = inline_summary (dst);
-  memcpy (info, inline_summary (src), sizeof (struct inline_summary));
+  memcpy (info, inline_summary_d->get (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);
@@ -1328,7 +1309,7 @@  free_growth_caches (void)
 
 static void
 dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node,
-			  struct inline_summary *info)
+			  inline_summary *info)
 {
   struct cgraph_edge *edge;
   for (edge = node->callees; edge; edge = edge->next_callee)
@@ -1345,8 +1326,8 @@  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_summary (callee)->size / INLINE_SIZE_SCALE,
-	       (int) inline_summary (callee)->estimated_stack_size);
+	       (int) inline_summary_d->get (callee)->size / INLINE_SIZE_SCALE,
+	       (int) inline_summary_d->get (callee)->estimated_stack_size);
 
       if (es->predicate)
 	{
@@ -1372,9 +1353,9 @@  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_summary (callee)->stack_frame_offset,
-		   (int) inline_summary (callee)->estimated_self_stack_size,
-		   (int) inline_summary (callee)->estimated_stack_size);
+		   (int) inline_summary_d->get (callee)->stack_frame_offset,
+		   (int) inline_summary_d->get (callee)->estimated_self_stack_size,
+		   (int) inline_summary_d->get (callee)->estimated_stack_size);
 	  dump_inline_edge_summary (f, indent + 2, callee, info);
 	}
     }
@@ -1402,7 +1383,7 @@  dump_inline_summary (FILE *f, struct cgraph_node *node)
 {
   if (node->definition)
     {
-      struct inline_summary *s = inline_summary (node);
+      inline_summary *s = inline_summary_d->get (node);
       size_time_entry *e;
       int i;
       fprintf (f, "Inline summary for %s/%i", node->name (),
@@ -1725,7 +1706,7 @@  eliminated_by_inlining_prob (gimple stmt)
 
 static void
 set_cond_stmt_execution_predicate (struct ipa_node_params *info,
-				   struct inline_summary *summary,
+				   inline_summary *summary,
 				   basic_block bb)
 {
   gimple last;
@@ -1810,7 +1791,7 @@  set_cond_stmt_execution_predicate (struct ipa_node_params *info,
 
 static void
 set_switch_stmt_execution_predicate (struct ipa_node_params *info,
-				     struct inline_summary *summary,
+				     inline_summary *summary,
 				     basic_block bb)
 {
   gimple last;
@@ -1871,7 +1852,7 @@  set_switch_stmt_execution_predicate (struct ipa_node_params *info,
 static void
 compute_bb_predicates (struct cgraph_node *node,
 		       struct ipa_node_params *parms_info,
-		       struct inline_summary *summary)
+		       inline_summary *summary)
 {
   struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
   bool done = false;
@@ -1950,7 +1931,7 @@  typedef struct predicate predicate_t;
 
 static struct predicate
 will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
-				    struct inline_summary *summary,
+				    inline_summary *summary,
 				    tree expr,
 				    vec<predicate_t> nonconstant_names)
 {
@@ -2013,7 +1994,7 @@  will_be_nonconstant_expr_predicate (struct ipa_node_params *info,
 
 static struct predicate
 will_be_nonconstant_predicate (struct ipa_node_params *info,
-			       struct inline_summary *summary,
+			       inline_summary *summary,
 			       gimple stmt,
 			       vec<predicate_t> nonconstant_names)
 {
@@ -2215,7 +2196,7 @@  param_change_prob (gimple stmt, int i)
 
 static bool
 phi_result_unknown_predicate (struct ipa_node_params *info,
-			      struct inline_summary *summary, basic_block bb,
+			      inline_summary *summary, basic_block bb,
 			      struct predicate *p,
 			      vec<predicate_t> nonconstant_names)
 {
@@ -2274,7 +2255,7 @@  phi_result_unknown_predicate (struct ipa_node_params *info,
    NONCONSTANT_NAMES, if possible.  */
 
 static void
-predicate_for_phi_result (struct inline_summary *summary, gimple phi,
+predicate_for_phi_result (inline_summary *summary, gimple phi,
 			  struct predicate *p,
 			  vec<predicate_t> nonconstant_names)
 {
@@ -2304,7 +2285,7 @@  predicate_for_phi_result (struct inline_summary *summary, gimple phi,
 /* Return predicate specifying when array index in access OP becomes non-constant.  */
 
 static struct predicate
-array_index_predicate (struct inline_summary *info,
+array_index_predicate (inline_summary *info,
 		       vec< predicate_t> nonconstant_names, tree op)
 {
   struct predicate p = false_predicate ();
@@ -2460,7 +2441,7 @@  estimate_function_body_sizes (struct cgraph_node *node, bool early)
   gimple_stmt_iterator bsi;
   struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
   int freq;
-  struct inline_summary *info = inline_summary (node);
+  inline_summary *info = inline_summary_d->get (node);
   struct predicate bb_predicate;
   struct ipa_node_params *parms_info = NULL;
   vec<predicate_t> nonconstant_names = vNULL;
@@ -2702,7 +2683,7 @@  estimate_function_body_sizes (struct cgraph_node *node, bool early)
 	    }
 	}
     }
-  set_hint_predicate (&inline_summary (node)->array_index, array_index);
+  set_hint_predicate (&inline_summary_d->get (node)->array_index, array_index);
   time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
   if (time > MAX_TIME)
     time = MAX_TIME;
@@ -2790,9 +2771,9 @@  estimate_function_body_sizes (struct cgraph_node *node, bool early)
 	    }
 	  free (body);
 	}
-      set_hint_predicate (&inline_summary (node)->loop_iterations,
+      set_hint_predicate (&inline_summary_d->get (node)->loop_iterations,
 			  loop_iterations);
-      set_hint_predicate (&inline_summary (node)->loop_stride, loop_stride);
+      set_hint_predicate (&inline_summary_d->get (node)->loop_stride, loop_stride);
       scev_finalize ();
     }
   FOR_ALL_BB_FN (bb, my_function)
@@ -2810,8 +2791,8 @@  estimate_function_body_sizes (struct cgraph_node *node, bool early)
 	  e->aux = NULL;
 	}
     }
-  inline_summary (node)->self_time = time;
-  inline_summary (node)->self_size = size;
+  inline_summary_d->get (node)->self_time = time;
+  inline_summary_d->get (node)->self_size = size;
   nonconstant_names.release ();
   if (optimize && !early)
     {
@@ -2834,14 +2815,14 @@  compute_inline_parameters (struct cgraph_node *node, bool early)
 {
   HOST_WIDE_INT self_stack_size;
   struct cgraph_edge *e;
-  struct inline_summary *info;
+  inline_summary *info;
 
   gcc_assert (!node->global.inlined_to);
 
   inline_summary_alloc ();
 
-  info = inline_summary (node);
-  reset_inline_summary (node);
+  info = inline_summary_d->get (node);
+  reset_inline_summary (node, info);
 
   /* FIXME: Thunks are inlinable, but tree-inline don't know how to do that.
      Once this happen, we will need to more curefully predict call
@@ -2982,7 +2963,7 @@  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
 {
   tree target;
   struct cgraph_node *callee;
-  struct inline_summary *isummary;
+  inline_summary *isummary;
   enum availability avail;
 
   if (!known_vals.exists () && !known_binfos.exists ())
@@ -3007,7 +2988,7 @@  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
   callee = callee->function_symbol (&avail);
   if (avail < AVAIL_AVAILABLE)
     return false;
-  isummary = inline_summary (callee);
+  isummary = inline_summary_d->get (callee);
   return isummary->inlinable;
 }
 
@@ -3120,7 +3101,7 @@  estimate_node_size_and_time (struct cgraph_node *node,
 			     vec<inline_param_summary>
 			     inline_param_summary)
 {
-  struct inline_summary *info = inline_summary (node);
+  inline_summary *info = inline_summary_d->get (node);
   size_time_entry *e;
   int size = 0;
   int time = 0;
@@ -3246,8 +3227,8 @@  estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
    for other purposes).  */
 
 static struct predicate
-remap_predicate (struct inline_summary *info,
-		 struct inline_summary *callee_info,
+remap_predicate (inline_summary *info,
+		 inline_summary *callee_info,
 		 struct predicate *p,
 		 vec<int> operand_map,
 		 vec<int> offset_map,
@@ -3336,8 +3317,8 @@  static void
 inline_update_callee_summaries (struct cgraph_node *node, int depth)
 {
   struct cgraph_edge *e;
-  struct inline_summary *callee_info = inline_summary (node);
-  struct inline_summary *caller_info = inline_summary (node->callers->caller);
+  inline_summary *callee_info = inline_summary_d->get (node);
+  inline_summary *caller_info = inline_summary_d->get (node->callers->caller);
   HOST_WIDE_INT peak;
 
   callee_info->stack_frame_offset
@@ -3345,8 +3326,8 @@  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_summary (node->global.inlined_to)->estimated_stack_size < peak)
-      inline_summary (node->global.inlined_to)->estimated_stack_size = peak;
+  if (inline_summary_d->get (node->global.inlined_to)->estimated_stack_size < peak)
+      inline_summary_d->get (node->global.inlined_to)->estimated_stack_size = peak;
   ipa_propagate_frequency (node);
   for (e = node->callees; e; e = e->next_callee)
     {
@@ -3407,8 +3388,8 @@  remap_edge_change_prob (struct cgraph_edge *inlined_edge,
 static void
 remap_edge_summaries (struct cgraph_edge *inlined_edge,
 		      struct cgraph_node *node,
-		      struct inline_summary *info,
-		      struct inline_summary *callee_info,
+		      inline_summary *info,
+		      inline_summary *callee_info,
 		      vec<int> operand_map,
 		      vec<int> offset_map,
 		      clause_t possible_truths,
@@ -3476,8 +3457,8 @@  remap_edge_summaries (struct cgraph_edge *inlined_edge,
 /* Same as remap_predicate, but set result into hint *HINT.  */
 
 static void
-remap_hint_predicate (struct inline_summary *info,
-		      struct inline_summary *callee_info,
+remap_hint_predicate (inline_summary *info,
+		      inline_summary *callee_info,
 		      struct predicate **hint,
 		      vec<int> operand_map,
 		      vec<int> offset_map,
@@ -3506,10 +3487,10 @@  remap_hint_predicate (struct inline_summary *info,
 void
 inline_merge_summary (struct cgraph_edge *edge)
 {
-  struct inline_summary *callee_info = inline_summary (edge->callee);
+  inline_summary *callee_info = inline_summary_d->get (edge->callee);
   struct cgraph_node *to = (edge->caller->global.inlined_to
 			    ? edge->caller->global.inlined_to : edge->caller);
-  struct inline_summary *info = inline_summary (to);
+  inline_summary *info = inline_summary_d->get (to);
   clause_t clause = 0;		/* not_inline is known to be false.  */
   size_time_entry *e;
   vec<int> operand_map = vNULL;
@@ -3618,7 +3599,7 @@  inline_merge_summary (struct cgraph_edge *edge)
 void
 inline_update_overall_summary (struct cgraph_node *node)
 {
-  struct inline_summary *info = inline_summary (node);
+  inline_summary *info = inline_summary_d->get (node);
   size_time_entry *e;
   int i;
 
@@ -3645,8 +3626,8 @@  simple_edge_hints (struct cgraph_edge *edge)
   int hints = 0;
   struct cgraph_node *to = (edge->caller->global.inlined_to
 			    ? edge->caller->global.inlined_to : edge->caller);
-  if (inline_summary (to)->scc_no
-      && inline_summary (to)->scc_no == inline_summary (edge->callee)->scc_no
+  if (inline_summary_d->get (to)->scc_no
+      && inline_summary_d->get (to)->scc_no == inline_summary_d->get (edge->callee)->scc_no
       && !edge->recursive_p ())
     hints |= INLINE_HINT_same_scc;
 
@@ -3706,7 +3687,7 @@  do_estimate_edge_time (struct cgraph_edge *edge)
   /* When caching, update the cache entry.  */
   if (edge_growth_cache.exists ())
     {
-      inline_summary (edge->callee)->min_size = min_size;
+      inline_summary_d->get (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);
@@ -3808,14 +3789,14 @@  estimate_time_after_inlining (struct cgraph_node *node,
   if (!es->predicate || !false_predicate_p (es->predicate))
     {
       gcov_type time =
-	inline_summary (node)->time + estimate_edge_time (edge);
+	inline_summary_d->get (node)->time + estimate_edge_time (edge);
       if (time < 0)
 	time = 0;
       if (time > MAX_TIME)
 	time = MAX_TIME;
       return time;
     }
-  return inline_summary (node)->time;
+  return inline_summary_d->get (node)->time;
 }
 
 
@@ -3829,11 +3810,11 @@  estimate_size_after_inlining (struct cgraph_node *node,
   struct inline_edge_summary *es = inline_edge_summary (edge);
   if (!es->predicate || !false_predicate_p (es->predicate))
     {
-      int size = inline_summary (node)->size + estimate_edge_growth (edge);
+      int size = inline_summary_d->get (node)->size + estimate_edge_growth (edge);
       gcc_assert (size >= 0);
       return size;
     }
-  return inline_summary (node)->size;
+  return inline_summary_d->get (node)->size;
 }
 
 
@@ -3873,7 +3854,7 @@  int
 do_estimate_growth (struct cgraph_node *node)
 {
   struct growth_data d = { node, 0, false };
-  struct inline_summary *info = inline_summary (node);
+  inline_summary *info = inline_summary_d->get (node);
 
   node->call_for_symbol_thunks_and_aliases (do_estimate_growth_1, &d, true);
 
@@ -3946,7 +3927,7 @@  growth_likely_positive (struct cgraph_node *node, int edge_growth ATTRIBUTE_UNUS
       && (!DECL_COMDAT (node->decl)
 	  || !node->can_remove_if_no_direct_calls_p ()))
     return true;
-  max_callers = inline_summary (node)->size * 4 / edge_growth + 2;
+  max_callers = inline_summary_d->get (node)->size * 4 / edge_growth + 2;
 
   for (e = node->callers; e; e = e->next_caller)
     {
@@ -4009,13 +3990,12 @@  inline_analyze_function (struct cgraph_node *node)
 
 /* Called when new function is inserted to callgraph late.  */
 
-static void
-add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+inline_summary_t::insert (cgraph_node *node, inline_summary *)
 {
   inline_analyze_function (node);
 }
 
-
 /* Note function body size.  */
 
 void
@@ -4028,8 +4008,10 @@  inline_generate_summary (void)
   if (!optimize && !flag_lto && !flag_wpa)
     return;
 
-  function_insertion_hook_holder =
-    symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
+  if (!inline_summary_d)
+    inline_summary_d = (inline_summary_t*) inline_summary_t::create_ggc (symtab);
+
+  inline_summary_d->enable_insertion_hook ();
 
   ipa_register_cgraph_hooks ();
   inline_free_summary ();
@@ -4113,7 +4095,7 @@  inline_read_section (struct lto_file_decl_data *file_data, const char *data,
     {
       unsigned int index;
       struct cgraph_node *node;
-      struct inline_summary *info;
+      inline_summary *info;
       lto_symtab_encoder_t encoder;
       struct bitpack_d bp;
       struct cgraph_edge *e;
@@ -4123,7 +4105,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_summary (node);
+      info = inline_summary_d->get (node);
 
       info->estimated_stack_size
 	= info->estimated_self_stack_size = streamer_read_uhwi (&ib);
@@ -4212,8 +4194,9 @@  inline_read_summary (void)
       if (!flag_ipa_cp)
 	ipa_prop_read_jump_functions ();
     }
-  function_insertion_hook_holder =
-    symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
+
+  gcc_assert (inline_summary_d);
+  inline_summary_d->enable_insertion_hook ();
 }
 
 
@@ -4279,7 +4262,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_summary (node);
+	  inline_summary *info = inline_summary_d->get (node);
 	  struct bitpack_d bp;
 	  struct cgraph_edge *edge;
 	  int i;
@@ -4344,23 +4327,15 @@  inline_free_summary (void)
     return;
   FOR_EACH_DEFINED_FUNCTION (node)
     if (!node->alias)
-      reset_inline_summary (node);
-  if (function_insertion_hook_holder)
-    symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
-  function_insertion_hook_holder = NULL;
-  if (node_removal_hook_holder)
-    symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
-  node_removal_hook_holder = NULL;
+      reset_inline_summary (node, inline_summary_d->get (node));
   if (edge_removal_hook_holder)
     symtab->remove_edge_removal_hook (edge_removal_hook_holder);
   edge_removal_hook_holder = NULL;
-  if (node_duplication_hook_holder)
-    symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
-  node_duplication_hook_holder = NULL;
   if (edge_duplication_hook_holder)
     symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
   edge_duplication_hook_holder = NULL;
-  vec_free (inline_summary_vec);
+  inline_summary_d->destroy ();
+  inline_summary_d = NULL;
   inline_edge_summary_vec.release ();
   if (edge_predicate_pool)
     free_alloc_pool (edge_predicate_pool);
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index 49c2679..841af60 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -200,7 +200,7 @@  clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
 	  if (e->callee->definition && !DECL_EXTERNAL (e->callee->decl))
 	    {
 	      if (overall_size)
-	        *overall_size -= inline_summary (e->callee)->size;
+	        *overall_size -= inline_summary_d->get (e->callee)->size;
 	      nfunctions_inlined++;
 	    }
 	  duplicate = false;
@@ -309,13 +309,13 @@  inline_call (struct cgraph_edge *e, bool update_original,
 
   gcc_assert (curr->callee->global.inlined_to == to);
 
-  old_size = inline_summary (to)->size;
+  old_size = inline_summary_d->get (to)->size;
   inline_merge_summary (e);
   if (optimize)
     new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges);
   if (update_overall_summary)
    inline_update_overall_summary (to);
-  new_size = inline_summary (to)->size;
+  new_size = inline_summary_d->get (to)->size;
 
   if (callee->calls_comdat_local)
     to->calls_comdat_local = true;
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index a8e94e2..73fb286 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -167,7 +167,7 @@  caller_growth_limits (struct cgraph_edge *e)
   int newsize;
   int limit = 0;
   HOST_WIDE_INT stack_size_limit = 0, inlined_stack;
-  struct inline_summary *info, *what_info, *outer_info = inline_summary (to);
+  inline_summary *info, *what_info, *outer_info = inline_summary_d->get (to);
 
   /* Look for function e->caller is inlined to.  While doing
      so work out the largest function body on the way.  As
@@ -179,7 +179,7 @@  caller_growth_limits (struct cgraph_edge *e)
      too much in order to prevent compiler from exploding".  */
   while (true)
     {
-      info = inline_summary (to);
+      info = inline_summary_d->get (to);
       if (limit < info->self_size)
 	limit = info->self_size;
       if (stack_size_limit < info->estimated_self_stack_size)
@@ -190,7 +190,7 @@  caller_growth_limits (struct cgraph_edge *e)
 	break;
     }
 
-  what_info = inline_summary (what);
+  what_info = inline_summary_d->get (what);
 
   if (limit < what_info->self_size)
     limit = what_info->self_size;
@@ -304,7 +304,7 @@  can_inline_edge_p (struct cgraph_edge *e, bool report,
       e->inline_failed = CIF_USES_COMDAT_LOCAL;
       inlinable = false;
     }
-  else if (!inline_summary (callee)->inlinable 
+  else if (!inline_summary_d->get (callee)->inlinable 
 	   || (caller_fun && fn_contains_cilk_spawn_p (caller_fun)))
     {
       e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
@@ -458,7 +458,7 @@  want_early_inline_function_p (struct cgraph_edge *e)
 
   if (DECL_DISREGARD_INLINE_LIMITS (callee->decl))
     ;
-  /* For AutoFDO, we need to make sure that before profile annotation, all
+  /* For AutoFDO, we need to make sure that before profile summary, all
      hot paths' IR look exactly the same as profiled binary. As a result,
      in einliner, we will disregard size limit and inline those callsites
      that are:
@@ -524,13 +524,12 @@  want_early_inline_function_p (struct cgraph_edge *e)
    does not happen.  */
 
 inline gcov_type
-compute_uninlined_call_time (struct inline_summary *callee_info,
-			     struct cgraph_edge *edge)
+compute_uninlined_call_time (inline_summary *callee_info, cgraph_edge *edge)
 {
   gcov_type uninlined_call_time =
     RDIV ((gcov_type)callee_info->time * MAX (edge->frequency, 1),
 	  CGRAPH_FREQ_BASE);
-  gcov_type caller_time = inline_summary (edge->caller->global.inlined_to
+  gcov_type caller_time = inline_summary_d->get (edge->caller->global.inlined_to
 				          ? edge->caller->global.inlined_to
 				          : edge->caller)->time;
   return uninlined_call_time + caller_time;
@@ -543,7 +542,7 @@  inline gcov_type
 compute_inlined_call_time (struct cgraph_edge *edge,
 			   int edge_time)
 {
-  gcov_type caller_time = inline_summary (edge->caller->global.inlined_to
+  gcov_type caller_time = inline_summary_d->get (edge->caller->global.inlined_to
 					  ? edge->caller->global.inlined_to
 					  : edge->caller)->time;
   gcov_type time = (caller_time
@@ -563,7 +562,7 @@  compute_inlined_call_time (struct cgraph_edge *edge,
 static bool
 big_speedup_p (struct cgraph_edge *e)
 {
-  gcov_type time = compute_uninlined_call_time (inline_summary (e->callee),
+  gcov_type time = compute_uninlined_call_time (inline_summary_d->get (e->callee),
 					  	e);
   gcov_type inlined_time = compute_inlined_call_time (e,
 					              estimate_edge_time (e));
@@ -596,7 +595,7 @@  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_summary (callee)->min_size
+	   && inline_summary_d->get (callee)->min_size
 		- inline_edge_summary (e)->call_stmt_size
 	      > MAX (MAX_INLINE_INSNS_SINGLE, MAX_INLINE_INSNS_AUTO))
     {
@@ -604,7 +603,7 @@  want_inline_small_function_p (struct cgraph_edge *e, bool report)
       want_inline = false;
     }
   else if ((DECL_DECLARED_INLINE_P (callee->decl) || e->count)
-	   && inline_summary (callee)->min_size
+	   && inline_summary_d->get (callee)->min_size
 		- inline_edge_summary (e)->call_stmt_size
 	      > 16 * MAX_INLINE_INSNS_SINGLE)
     {
@@ -867,8 +866,8 @@  want_inline_function_to_all_callers_p (struct cgraph_node *node, bool cold)
    1...RELATIVE_TIME_BENEFIT_RANGE  */
 
 static inline int
-relative_time_benefit (struct inline_summary *callee_info,
-		       struct cgraph_edge *edge,
+relative_time_benefit (inline_summary *callee_info,
+		       cgraph_edge *edge,
 		       int edge_time)
 {
   gcov_type relbenefit;
@@ -913,7 +912,7 @@  edge_badness (struct cgraph_edge *edge, bool dump)
   gcov_type badness;
   int growth, edge_time;
   struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
-  struct inline_summary *callee_info = inline_summary (callee);
+  inline_summary *callee_info = inline_summary_d->get (callee);
   inline_hints hints;
 
   if (DECL_DISREGARD_INLINE_LIMITS (callee->decl))
@@ -1188,7 +1187,7 @@  update_caller_keys (fibheap_t heap, struct cgraph_node *node,
   struct cgraph_edge *edge;
   struct ipa_ref *ref;
 
-  if ((!node->alias && !inline_summary (node)->inlinable)
+  if ((!node->alias && !inline_summary_d->get (node)->inlinable)
       || node->global.inlined_to)
     return;
   if (!bitmap_set_bit (updated_nodes, node->uid))
@@ -1246,7 +1245,7 @@  update_callee_keys (fibheap_t heap, struct cgraph_node *node,
            don't need updating.  */
 	if (e->inline_failed
 	    && (callee = e->callee->ultimate_alias_target (&avail))
-	    && inline_summary (callee)->inlinable
+	    && inline_summary_d->get (callee)->inlinable
 	    && avail >= AVAIL_AVAILABLE
 	    && !bitmap_bit_p (updated_nodes, callee->uid))
 	  {
@@ -1424,8 +1423,8 @@  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_summary (master_clone)->size, inline_summary (node)->size,
-	     inline_summary (master_clone)->time, inline_summary (node)->time);
+	     inline_summary_d->get (master_clone)->size, inline_summary_d->get (node)->size,
+	     inline_summary_d->get (master_clone)->time, inline_summary_d->get (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
@@ -1599,8 +1598,8 @@  inline_small_functions (void)
 	if (node->has_gimple_body_p ()
 	    || node->thunk.thunk_p)
 	  {
-	    struct inline_summary *info = inline_summary (node);
-	    struct ipa_dfs_info *dfs = (struct ipa_dfs_info *) node->aux;
+	    inline_summary *info = inline_summary_d->get (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.  */
@@ -1610,12 +1609,12 @@  inline_small_functions (void)
 	    info->growth = estimate_growth (node);
 	    if (dfs && dfs->next_cycle)
 	      {
-		struct cgraph_node *n2;
+		cgraph_node *n2;
 		int id = dfs->scc_no + 1;
 		for (n2 = node; n2;
 		     n2 = ((struct ipa_dfs_info *) node->aux)->next_cycle)
 		  {
-		    struct inline_summary *info2 = inline_summary (n2);
+		    inline_summary *info2 = inline_summary_d->get (n2);
 		    if (info2->scc_no)
 		      break;
 		    info2->scc_no = id;
@@ -1735,7 +1734,7 @@  inline_small_functions (void)
 	  fprintf (dump_file,
 		   "\nConsidering %s/%i with %i size\n",
 		   callee->name (), callee->order,
-		   inline_summary (callee)->size);
+		   inline_summary_d->get (callee)->size);
 	  fprintf (dump_file,
 		   " to be inlined into %s/%i in %s:%i\n"
 		   " Estimated badness is %i, frequency %.2f.\n",
@@ -1853,8 +1852,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_summary (edge->caller)->time,
-		   inline_summary (edge->caller)->size,
+		   inline_summary_d->get (edge->caller)->time,
+		   inline_summary_d->get (edge->caller)->size,
 		   overall_size - old_size);
 	}
       if (min_size > overall_size)
@@ -1992,11 +1991,11 @@  inline_to_all_callers (struct cgraph_node *node, void *data)
 	  fprintf (dump_file,
 		   "\nInlining %s size %i.\n",
 		   node->name (),
-		   inline_summary (node)->size);
+		   inline_summary_d->get (node)->size);
 	  fprintf (dump_file,
 		   " Called once from %s %i insns.\n",
 		   node->callers->caller->name (),
-		   inline_summary (node->callers->caller)->size);
+		   inline_summary_d->get (node->callers->caller)->size);
 	}
 
       inline_call (node->callers, true, NULL, NULL, true, &callee_removed);
@@ -2004,7 +2003,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_summary (caller)->size);
+		 inline_summary_d->get (caller)->size);
       if (!(*num_calls)--)
 	{
 	  if (dump_file)
@@ -2028,7 +2027,7 @@  dump_overall_stats (void)
     if (!node->global.inlined_to
 	&& !node->alias)
       {
-	int time = inline_summary (node)->time;
+	int time = inline_summary_d->get (node)->time;
 	sum += time;
 	sum_weighted += time * node->count;
       }
@@ -2345,7 +2344,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_summary (callee)->inlinable
+      if (!inline_summary_d->get (callee)->inlinable
 	  || !e->inline_failed)
 	continue;
 
diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h
index 2ac6e4e..7a939f4 100644
--- a/gcc/ipa-inline.h
+++ b/gcc/ipa-inline.h
@@ -162,10 +162,28 @@  struct GTY(()) inline_summary
   int scc_no;
 };
 
-/* Need a typedef for inline_summary because of inline function
-   'inline_summary' below.  */
-typedef struct inline_summary inline_summary_t;
-extern GTY(()) vec<inline_summary_t, va_gc> *inline_summary_vec;
+class GTY((user)) inline_summary_t: public function_summary <inline_summary *>
+{
+public:
+  inline_summary_t (symbol_table *symtab, bool ggc):
+    function_summary <inline_summary *> (symtab, ggc) {}
+
+  static inline_summary_t *create_ggc (symbol_table *symtab)
+  {
+    inline_summary_t *summary = new (ggc_cleared_alloc <inline_summary_t> ())
+      inline_summary_t(symtab, true);
+    summary->disable_insertion_hook ();
+    return summary;
+  }
+
+
+  virtual void insert (cgraph_node *, inline_summary *);
+  virtual void remove (cgraph_node *node, inline_summary *);
+  virtual void duplicate (cgraph_node *src, cgraph_node *dst,
+			  inline_summary *src_data, inline_summary *dst_data);
+};
+
+extern GTY(()) function_summary <inline_summary *> *inline_summary_d;
 
 /* Information kept about parameter of call site.  */
 struct inline_param_summary
@@ -249,12 +267,6 @@  void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *,
 extern int ncalls_inlined;
 extern int nfunctions_inlined;
 
-static inline struct inline_summary *
-inline_summary (struct cgraph_node *node)
-{
-  return &(*inline_summary_vec)[node->uid];
-}
-
 static inline struct inline_edge_summary *
 inline_edge_summary (struct cgraph_edge *edge)
 {
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 5e25fd8..387209b 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -514,7 +514,7 @@  ipa_get_ith_polymorhic_call_context (struct ipa_edge_args *args, int i)
   return &(*args->polymorphic_call_contexts)[i];
 }
 
-/* Callgraph summary for ipa_node_params.  */
+/* Function summary for ipa_node_params.  */
 class ipa_node_params_t: public function_summary <ipa_node_params *>
 {
 public:
@@ -537,7 +537,7 @@  extern GTY(()) vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
 
 /* Return the associated parameter/argument info corresponding to the given
    node/edge.  */
-#define IPA_NODE_REF(NODE) ((*ipa_node_params_d)[NODE])
+#define IPA_NODE_REF(NODE) (ipa_node_params_d->get (NODE))
 #define IPA_EDGE_REF(EDGE) (&(*ipa_edge_args_vector)[(EDGE)->uid])
 /* This macro checks validity of index returned by
    ipa_get_param_decl_index function.  */
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index 16684e2..80c3aac 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1669,7 +1669,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_summary (node)->inlinable)
+      && !inline_summary_d->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 80b8561..a873635 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -224,7 +224,7 @@  walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
                                target->order);
 	    }
 	  edge = edge->make_direct (target);
-	  if (inline_summary_vec)
+	  if (inline_summary_d)
 	    inline_update_overall_summary (node);
 	  else if (edge->call_stmt)
 	    {
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 3a2f9ed..343cd83 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -165,7 +165,7 @@  add_symbol_to_partition_1 (ltrans_partition part, symtab_node *node)
     {
       struct cgraph_edge *e;
       if (!node->alias)
-        part->insns += inline_summary (cnode)->self_size;
+        part->insns += inline_summary_d->get (cnode)->self_size;
 
       /* Add all inline clones and callees that are duplicated.  */
       for (e = cnode->callees; e; e = e->next_callee)
@@ -274,7 +274,7 @@  undo_partition (ltrans_partition partition, unsigned int n_nodes)
       partition->initializers_visited = NULL;
 
       if (!node->alias && (cnode = dyn_cast <cgraph_node *> (node)))
-        partition->insns -= inline_summary (cnode)->self_size;
+        partition->insns -= inline_summary_d->get (cnode)->self_size;
       lto_symtab_encoder_delete_node (partition->encoder, node);
       node->aux = (void *)((size_t)node->aux - 1);
     }
@@ -477,7 +477,7 @@  lto_balanced_map (int n_lto_partitions)
 	else
 	  order[n_nodes++] = node;
 	if (!node->alias)
-	  total_size += inline_summary (node)->size;
+	  total_size += inline_summary_d->get (node)->size;
       }
 
   /* Streaming works best when the source units do not cross partition
@@ -534,14 +534,14 @@  lto_balanced_map (int n_lto_partitions)
 	     && noreorder[noreorder_pos]->order < current_order)
 	{
 	  if (!noreorder[noreorder_pos]->alias)
-	    total_size -= inline_summary (noreorder[noreorder_pos])->size;
+	    total_size -= inline_summary_d->get (noreorder[noreorder_pos])->size;
 	  next_nodes.safe_push (noreorder[noreorder_pos++]);
 	}
       add_sorted_nodes (next_nodes, partition);
 
       add_symbol_to_partition (partition, order[i]);
       if (!order[i]->alias)
-        total_size -= inline_summary (order[i])->size;
+        total_size -= inline_summary_d->get (order[i])->size;
 	  
 
       /* Once we added a new node to the partition, we also want to add
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index e0c375d..980a97b 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -4991,7 +4991,7 @@  ipa_sra_preliminary_function_checks (struct cgraph_node *node)
     }
 
   if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
-      && inline_summary (node)->size >= MAX_INLINE_INSNS_AUTO)
+      && inline_summary_d->get (node)->size >= MAX_INLINE_INSNS_AUTO)
     {
       if (dump_file)
 	fprintf (dump_file, "Function too big to be made truly local.\n");
-- 
2.1.2