Inline hints

Jan Hubicka hubicka@ucw.cz
Sun Aug 19 05:44:00 GMT 2012


Hi,
this patch implements infrastructure for inline hints. They provide way to pass info
down from inline-analysis to the inline heuristic implementation that does not fit the
current size/time model.  Inline hints are simple bitmask of individual hints that are
interprested by the heuristics as fit.

The patch implement only one hint that is to prioritize inlining of function
when devirtualization or indirect call removal will happen.

We will need bit expriments on how to interpret these hints. Currently for
autoinined functions we bypass inline-insns-auto limit and for functions declared
inline we bypass inline-insns-single limit. Also badness is decreased by factor of 8.
This was my first try and it works pretty well in practice.

On Mozilla this increase number of devirutalization from 160 to 2080, that is non-zero
precentage of overalll 66000 virtual calls.  This does not translate exactly into
decarese of indirect calls in mozill abinary that goes down by only about 500.
Still it is a lot better than anticipated and for a fist time we devirtualize non-joke
number of calls.

I intend to follow with more hints. The followng are ones I experimented with so far:
 1) to penalize inlining within strongly connected component since it usually cause
    complex cgraphs/cfgs (to help povray)
 2) to enable more inlining when loop bounds become known (to help fortran)
 3) to enable more inlining when loop stride become known (also for fortran mostly)
 4) to enable more inlining when  when caller/callee is known to be hot
    (by profile or attribute)

Bootstrapped/regtested x86_64-linux, will commit it shortly.

Honza

	* gcc.dg/ipa/iinline-1.c: Update testcase to test inline hints.
	
	* ipa-inline.c (want_inline_small_function_p): Bypass
	inline limits for hinted functions.
	(edge_badness): Dump hints; decrease badness for hinted funcitons.
	* ipa-inline.h (enum inline_hints_vals): New enum.
	(inline_hints): New type.
	(edge_growth_cache_entry): Add hints.
	(dump_inline_summary): Update.
	(dump_inline_hints): Declare.
	(do_estimate_edge_hints): Declare.
	(estimate_edge_hints): New inline function.
	(reset_edge_growth_cache): Update.
	* predict.c (cgraph_maybe_hot_edge_p): Do not ice on indirect edges.
	* ipa-inline-analysis.c (dump_inline_hints): New function.
	(estimate_edge_devirt_benefit): Return true when function should be
	hinted.
	(estimate_calls_size_and_time): New hints argument; set it when
	devritualization happens.
	(estimate_node_size_and_time): New hints argument.
	(do_estimate_edge_time): Cache hints.
	(do_estimate_edge_growth): Update.	
	(do_estimate_edge_hints): New function
Index: testsuite/gcc.dg/ipa/iinline-1.c
===================================================================
*** testsuite/gcc.dg/ipa/iinline-1.c	(revision 190508)
--- testsuite/gcc.dg/ipa/iinline-1.c	(working copy)
***************
*** 1,7 ****
  /* Verify that simple indirect calls are inlined even without early
     inlining..  */
  /* { dg-do compile } */
! /* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining"  } */
  
  extern void non_existent(int);
  
--- 1,7 ----
  /* Verify that simple indirect calls are inlined even without early
     inlining..  */
  /* { dg-do compile } */
! /* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp"  } */
  
  extern void non_existent(int);
  
*************** int test (void)
*** 22,26 ****
--- 22,27 ----
    return 0;
  }
  
+ /* { dg-final { scan-ipa-dump "indirect_call"  "inline"  } } */
  /* { dg-final { scan-ipa-dump "hooray\[^\\n\]*inline copy in test"  "inline"  } } */
  /* { dg-final { cleanup-ipa-dump "inline" } } */
Index: ipa-inline.c
===================================================================
*** ipa-inline.c	(revision 190508)
--- ipa-inline.c	(working copy)
*************** want_inline_small_function_p (struct cgr
*** 472,482 ****
    else
      {
        int growth = estimate_edge_growth (e);
  
        if (growth <= 0)
  	;
        else if (DECL_DECLARED_INLINE_P (callee->symbol.decl)
! 	       && growth >= MAX_INLINE_INSNS_SINGLE)
  	{
            e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
  	  want_inline = false;
--- 472,486 ----
    else
      {
        int growth = estimate_edge_growth (e);
+       inline_hints hints = estimate_edge_hints (e);
  
        if (growth <= 0)
  	;
+       /* Apply MAX_INLINE_INSNS_SINGLE limit.  Do not do so when
+ 	 hints suggests that inlining given function is very profitable.  */
        else if (DECL_DECLARED_INLINE_P (callee->symbol.decl)
! 	       && growth >= MAX_INLINE_INSNS_SINGLE
! 	       && !(hints & INLINE_HINT_indirect_call))
  	{
            e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
  	  want_inline = false;
*************** want_inline_small_function_p (struct cgr
*** 523,530 ****
            e->inline_failed = CIF_NOT_DECLARED_INLINED;
  	  want_inline = false;
  	}
        else if (!DECL_DECLARED_INLINE_P (callee->symbol.decl)
! 	       && growth >= MAX_INLINE_INSNS_AUTO)
  	{
            e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
  	  want_inline = false;
--- 527,540 ----
            e->inline_failed = CIF_NOT_DECLARED_INLINED;
  	  want_inline = false;
  	}
+       /* Apply MAX_INLINE_INSNS_AUTO limit for functions not declared inline
+ 	 Upgrade it to MAX_INLINE_INSNS_SINGLE when hints suggests that
+ 	 inlining given function is very profitable.  */
        else if (!DECL_DECLARED_INLINE_P (callee->symbol.decl)
! 	       && growth >= ((hints & INLINE_HINT_indirect_call)
! 			     ? MAX (MAX_INLINE_INSNS_AUTO,
! 				    MAX_INLINE_INSNS_SINGLE)
! 			     : MAX_INLINE_INSNS_AUTO))
  	{
            e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
  	  want_inline = false;
*************** edge_badness (struct cgraph_edge *edge, 
*** 743,763 ****
    struct cgraph_node *callee = cgraph_function_or_thunk_node (edge->callee,
  							      NULL);
    struct inline_summary *callee_info = inline_summary (callee);
  
    if (DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl))
      return INT_MIN;
  
    growth = estimate_edge_growth (edge);
    time_growth = estimate_edge_time (edge);
  
    if (dump)
      {
        fprintf (dump_file, "    Badness calculation for %s -> %s\n",
  	       xstrdup (cgraph_node_name (edge->caller)),
  	       xstrdup (cgraph_node_name (callee)));
!       fprintf (dump_file, "      size growth %i, time growth %i\n",
  	       growth,
  	       time_growth);
      }
  
    /* Always prefer inlining saving code size.  */
--- 753,777 ----
    struct cgraph_node *callee = cgraph_function_or_thunk_node (edge->callee,
  							      NULL);
    struct inline_summary *callee_info = inline_summary (callee);
+   inline_hints hints;
  
    if (DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl))
      return INT_MIN;
  
    growth = estimate_edge_growth (edge);
    time_growth = estimate_edge_time (edge);
+   hints = estimate_edge_hints (edge);
  
    if (dump)
      {
        fprintf (dump_file, "    Badness calculation for %s -> %s\n",
  	       xstrdup (cgraph_node_name (edge->caller)),
  	       xstrdup (cgraph_node_name (callee)));
!       fprintf (dump_file, "      size growth %i, time growth %i ",
  	       growth,
  	       time_growth);
+       dump_inline_hints (dump_file, hints);
+       fprintf (dump_file, "\n");
      }
  
    /* Always prefer inlining saving code size.  */
*************** edge_badness (struct cgraph_edge *edge, 
*** 849,854 ****
--- 863,870 ----
  	  if (dump)
  	    fprintf (dump_file, "Badness overflow\n");
  	}
+       if (hints & INLINE_HINT_indirect_call)
+ 	badness /= 8;
        if (dump)
  	{
  	  fprintf (dump_file,
Index: ipa-inline.h
===================================================================
*** ipa-inline.h	(revision 190508)
--- ipa-inline.h	(working copy)
*************** typedef struct GTY(()) condition
*** 42,47 ****
--- 42,54 ----
      unsigned by_ref : 1;
    } condition;
  
+ /* Inline hints are reasons why inline heuristics should preffer inlining given function.
+    They are represtented as bitmap of the following values.  */
+ enum inline_hints_vals {
+   INLINE_HINT_indirect_call = 1
+ };
+ typedef int inline_hints;
+ 
  DEF_VEC_O (condition);
  DEF_VEC_ALLOC_O (condition, gc);
  
*************** extern VEC(inline_edge_summary_t,heap) *
*** 158,163 ****
--- 165,171 ----
  typedef struct edge_growth_cache_entry
  {
    int time, size;
+   inline_hints hints;
  } edge_growth_cache_entry;
  DEF_VEC_O(edge_growth_cache_entry);
  DEF_VEC_ALLOC_O(edge_growth_cache_entry,heap);
*************** extern VEC(edge_growth_cache_entry,heap)
*** 168,174 ****
  /* In ipa-inline-analysis.c  */
  void debug_inline_summary (struct cgraph_node *);
  void dump_inline_summaries (FILE *f);
! void dump_inline_summary (FILE * f, struct cgraph_node *node);
  void inline_generate_summary (void);
  void inline_read_summary (void);
  void inline_write_summary (void);
--- 176,183 ----
  /* In ipa-inline-analysis.c  */
  void debug_inline_summary (struct cgraph_node *);
  void dump_inline_summaries (FILE *f);
! void dump_inline_summary (FILE *f, struct cgraph_node *node);
! void dump_inline_hints (FILE *f, inline_hints);
  void inline_generate_summary (void);
  void inline_read_summary (void);
  void inline_write_summary (void);
*************** void inline_merge_summary (struct cgraph
*** 185,190 ****
--- 194,200 ----
  void inline_update_overall_summary (struct cgraph_node *node);
  int do_estimate_edge_growth (struct cgraph_edge *edge);
  int do_estimate_edge_time (struct cgraph_edge *edge);
+ inline_hints do_estimate_edge_hints (struct cgraph_edge *edge);
  void initialize_growth_caches (void);
  void free_growth_caches (void);
  void compute_inline_parameters (struct cgraph_node *, bool);
*************** estimate_edge_time (struct cgraph_edge *
*** 257,262 ****
--- 267,288 ----
  }
  
  
+ /* Return estimated callee runtime increase after inlning
+    EDGE.  */
+ 
+ static inline inline_hints
+ estimate_edge_hints (struct cgraph_edge *edge)
+ {
+   inline_hints ret;
+   if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) <= edge->uid
+       || !(ret = VEC_index (edge_growth_cache_entry,
+ 			    edge_growth_cache,
+ 			    edge->uid).hints))
+     return do_estimate_edge_time (edge);
+   return ret - 1;
+ }
+ 
+ 
  /* Reset cached value for NODE.  */
  
  static inline void
*************** reset_edge_growth_cache (struct cgraph_e
*** 273,279 ****
  {
    if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) > edge->uid)
      {
!       struct edge_growth_cache_entry zero = {0, 0};
        VEC_replace (edge_growth_cache_entry, edge_growth_cache, edge->uid, zero);
      }
  }
--- 299,305 ----
  {
    if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) > edge->uid)
      {
!       struct edge_growth_cache_entry zero = {0, 0, 0};
        VEC_replace (edge_growth_cache_entry, edge_growth_cache, edge->uid, zero);
      }
  }
Index: predict.c
===================================================================
*** predict.c	(revision 190508)
--- predict.c	(working copy)
*************** cgraph_maybe_hot_edge_p (struct cgraph_e
*** 165,174 ****
  	  <= profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
      return false;
    if (edge->caller->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
!       || edge->callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
      return false;
    if (edge->caller->frequency > NODE_FREQUENCY_UNLIKELY_EXECUTED
!       && edge->callee->frequency <= NODE_FREQUENCY_EXECUTED_ONCE)
      return false;
    if (optimize_size)
      return false;
--- 165,176 ----
  	  <= profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
      return false;
    if (edge->caller->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
!       || (edge->callee
! 	  && edge->callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED))
      return false;
    if (edge->caller->frequency > NODE_FREQUENCY_UNLIKELY_EXECUTED
!       && (edge->callee
! 	  && edge->callee->frequency <= NODE_FREQUENCY_EXECUTED_ONCE))
      return false;
    if (optimize_size)
      return false;
Index: ipa-inline-analysis.c
===================================================================
*** ipa-inline-analysis.c	(revision 190508)
--- ipa-inline-analysis.c	(working copy)
*************** dump_predicate (FILE *f, conditions cond
*** 615,620 ****
--- 615,636 ----
  }
  
  
+ /* Dump inline hints.  */
+ void
+ dump_inline_hints (FILE *f, inline_hints hints)
+ {
+   if (!hints)
+     return;
+   fprintf (f, "inline hints:");
+   if (hints & INLINE_HINT_indirect_call)
+     {
+       hints &= ~INLINE_HINT_indirect_call;
+       fprintf (f, " indirect_call");
+     }
+   gcc_assert (!hints);
+ }
+ 
+ 
  /* Record SIZE and TIME under condition PRED into the inline summary.  */
  
  static void
*************** estimate_edge_size_and_time (struct cgra
*** 2302,2308 ****
  /* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS and
     KNOWN_BINFOS.  */
  
! static void
  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
  			      int *size, int *time, int prob,
  			      VEC (tree, heap) *known_vals,
--- 2318,2324 ----
  /* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS and
     KNOWN_BINFOS.  */
  
! static bool
  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
  			      int *size, int *time, int prob,
  			      VEC (tree, heap) *known_vals,
*************** estimate_edge_devirt_benefit (struct cgr
*** 2311,2324 ****
  {
    tree target;
    int time_diff, size_diff;
  
    if (!known_vals && !known_binfos)
!     return;
  
    target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
  					 known_aggs);
    if (!target)
!     return;
  
    /* Account for difference in cost between indirect and direct calls.  */
    size_diff = ((eni_size_weights.indirect_call_cost - eni_size_weights.call_cost)
--- 2327,2342 ----
  {
    tree target;
    int time_diff, size_diff;
+   struct cgraph_node *callee;
+   struct inline_summary *isummary;
  
    if (!known_vals && !known_binfos)
!     return false;
  
    target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
  					 known_aggs);
    if (!target)
!     return false;
  
    /* Account for difference in cost between indirect and direct calls.  */
    size_diff = ((eni_size_weights.indirect_call_cost - eni_size_weights.call_cost)
*************** estimate_edge_devirt_benefit (struct cgr
*** 2328,2367 ****
  	       * INLINE_TIME_SCALE * prob / REG_BR_PROB_BASE);
    *time -= time_diff;
  
-   /* TODO: This code is trying to benefit indirect calls that will be inlined later.
-      The logic however do not belong into local size/time estimates and can not be
-      done here, or the accounting of changes will get wrong and we result with 
-      negative function body sizes.  We need to introduce infrastructure for independent
-      benefits to the inliner.  */
- #if 0
-   struct cgraph_node *callee;
-   struct inline_summary *isummary;
-   int edge_size, edge_time, time_diff, size_diff;
- 
    callee = cgraph_get_node (target);
    if (!callee || !callee->analyzed)
!     return;
    isummary = inline_summary (callee);
!   if (!isummary->inlinable)
!     return;
! 
!   estimate_edge_size_and_time (ie, &edge_size, &edge_time, prob);
! 
!   /* Count benefit only from functions that definitely will be inlined
!      if additional context from NODE's caller were available. 
! 
!      We just account overall size change by inlining.  TODO:
!      we really need to add sort of benefit metrics for these kind of
!      cases. */
!   if (edge_size - size_diff >= isummary->size * INLINE_SIZE_SCALE)
!     {
!       /* Subtract size and time that we added for edge IE.  */
!       *size -= edge_size - size_diff;
! 
!       /* Account inlined call.  */
!       *size += isummary->size * INLINE_SIZE_SCALE;
!     }
! #endif
  }
  
  
--- 2346,2356 ----
  	       * INLINE_TIME_SCALE * prob / REG_BR_PROB_BASE);
    *time -= time_diff;
  
    callee = cgraph_get_node (target);
    if (!callee || !callee->analyzed)
!     return false;
    isummary = inline_summary (callee);
!   return isummary->inlinable;
  }
  
  
*************** estimate_edge_devirt_benefit (struct cgr
*** 2371,2376 ****
--- 2360,2366 ----
  
  static void
  estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
+ 			      inline_hints *hints,
  			      clause_t possible_truths,
  			      VEC (tree, heap) *known_vals,
  			      VEC (tree, heap) *known_binfos,
*************** estimate_calls_size_and_time (struct cgr
*** 2389,2395 ****
  	      estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
  	    }
  	  else
! 	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
  					  known_vals, known_binfos, known_aggs);
  	}
--- 2379,2385 ----
  	      estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
  	    }
  	  else
! 	    estimate_calls_size_and_time (e->callee, size, time, hints,
  					  possible_truths,
  					  known_vals, known_binfos, known_aggs);
  	}
*************** estimate_calls_size_and_time (struct cgr
*** 2400,2407 ****
        if (!es->predicate || evaluate_predicate (es->predicate, possible_truths))
  	{
  	  estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
! 	  estimate_edge_devirt_benefit (e, size, time, REG_BR_PROB_BASE,
! 					known_vals, known_binfos, known_aggs);
  	}
      }
  }
--- 2390,2400 ----
        if (!es->predicate || evaluate_predicate (es->predicate, possible_truths))
  	{
  	  estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
! 	  if (estimate_edge_devirt_benefit (e, size, time, REG_BR_PROB_BASE,
! 					    known_vals, known_binfos, known_aggs)
! 	      && hints
! 	      && cgraph_maybe_hot_edge_p (e))
! 	    *hints |= INLINE_HINT_indirect_call;
  	}
      }
  }
*************** estimate_node_size_and_time (struct cgra
*** 2418,2429 ****
--- 2411,2424 ----
  			     VEC (tree, heap) *known_binfos,
  			     VEC (ipa_agg_jump_function_p, heap) *known_aggs,
  		       	     int *ret_size, int *ret_time,
+ 			     inline_hints *ret_hints,
  			     VEC (inline_param_summary_t, heap)
  			       *inline_param_summary)
  {
    struct inline_summary *info = inline_summary (node);
    size_time_entry *e;
    int size = 0, time = 0;
+   inline_hints hints = 0;
    int i;
  
    if (dump_file
*************** estimate_node_size_and_time (struct cgra
*** 2467,2473 ****
    if (time > MAX_TIME * INLINE_TIME_SCALE)
      time = MAX_TIME * INLINE_TIME_SCALE;
  
!   estimate_calls_size_and_time (node, &size, &time, possible_truths,
  				known_vals, known_binfos, known_aggs);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
--- 2462,2468 ----
    if (time > MAX_TIME * INLINE_TIME_SCALE)
      time = MAX_TIME * INLINE_TIME_SCALE;
  
!   estimate_calls_size_and_time (node, &size, &time, &hints, possible_truths,
  				known_vals, known_binfos, known_aggs);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
*************** estimate_node_size_and_time (struct cgra
*** 2480,2485 ****
--- 2475,2482 ----
      *ret_time = time;
    if (ret_size)
      *ret_size = size;
+   if (ret_hints)
+     *ret_hints = hints;
    return;
  }
  
*************** estimate_ipcp_clone_size_and_time (struc
*** 2499,2505 ****
  
    clause = evaluate_conditions_for_known_args (node, false, known_vals, NULL);
    estimate_node_size_and_time (node, clause, known_vals, known_binfos, NULL,
! 			       ret_size, ret_time,
  			       NULL);
  }
  
--- 2496,2502 ----
  
    clause = evaluate_conditions_for_known_args (node, false, known_vals, NULL);
    estimate_node_size_and_time (node, clause, known_vals, known_binfos, NULL,
! 			       ret_size, ret_time, NULL,
  			       NULL);
  }
  
*************** inline_update_overall_summary (struct cg
*** 2871,2877 ****
    info->time = 0;
    for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++)
      info->size += e->size, info->time += e->time;
!   estimate_calls_size_and_time (node, &info->size, &info->time,
  				~(clause_t)(1 << predicate_false_condition),
  				NULL, NULL, NULL);
    info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
--- 2868,2874 ----
    info->time = 0;
    for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++)
      info->size += e->size, info->time += e->time;
!   estimate_calls_size_and_time (node, &info->size, &info->time, NULL,
  				~(clause_t)(1 << predicate_false_condition),
  				NULL, NULL, NULL);
    info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
*************** do_estimate_edge_time (struct cgraph_edg
*** 2890,2895 ****
--- 2887,2893 ----
  {
    int time;
    int size;
+   inline_hints hints;
    gcov_type ret;
    struct cgraph_node *callee;
    clause_t clause;
*************** do_estimate_edge_time (struct cgraph_edg
*** 2905,2911 ****
  				&clause, &known_vals, &known_binfos,
  				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       known_aggs, &size, &time, es->param);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
--- 2903,2909 ----
  				&clause, &known_vals, &known_binfos,
  				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       known_aggs, &size, &time, &hints, es->param);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
*************** do_estimate_edge_time (struct cgraph_edg
*** 2929,2934 ****
--- 2927,2934 ----
        gcc_checking_assert (es->call_stmt_size);
        VEC_index (edge_growth_cache_entry, edge_growth_cache, edge->uid).size
  	= ret_size + (ret_size >= 0);
+       VEC_index (edge_growth_cache_entry, edge_growth_cache, edge->uid).hints
+ 	= hints + 1;
      }
    return ret;
  }
*************** do_estimate_edge_growth (struct cgraph_e
*** 2967,2973 ****
  				&clause, &known_vals, &known_binfos,
  				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       known_aggs, &size, NULL, NULL);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
--- 2967,2973 ----
  				&clause, &known_vals, &known_binfos,
  				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       known_aggs, &size, NULL, NULL, NULL);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
*************** do_estimate_edge_growth (struct cgraph_e
*** 2976,2981 ****
--- 2976,3022 ----
  }
  
  
+ /* Estimate the growth of the caller when inlining EDGE.
+    Only to be called via estimate_edge_size.  */
+ 
+ inline_hints
+ do_estimate_edge_hints (struct cgraph_edge *edge)
+ {
+   inline_hints hints;
+   struct cgraph_node *callee;
+   clause_t clause;
+   VEC (tree, heap) *known_vals;
+   VEC (tree, heap) *known_binfos;
+   VEC (ipa_agg_jump_function_p, heap) *known_aggs;
+ 
+   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
+ 
+   if (edge_growth_cache)
+     {
+       do_estimate_edge_time (edge);
+       hints = VEC_index (edge_growth_cache_entry,
+ 			edge_growth_cache,
+ 			edge->uid).hints;
+       gcc_checking_assert (hints);
+       return hints - 1;
+     }
+ 
+   callee = cgraph_function_or_thunk_node (edge->callee, NULL);
+ 
+   /* Early inliner runs without caching, go ahead and do the dirty work.  */
+   gcc_checking_assert (edge->inline_failed);
+   evaluate_properties_for_edge (edge, true,
+ 				&clause, &known_vals, &known_binfos,
+ 				&known_aggs);
+   estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
+ 			       known_aggs, NULL, NULL, &hints, NULL);
+   VEC_free (tree, heap, known_vals);
+   VEC_free (tree, heap, known_binfos);
+   VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
+   return hints;
+ }
+ 
+ 
  /* Estimate self time of the function NODE after inlining EDGE.  */
  
  int



More information about the Gcc-patches mailing list