public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Better time/size estimates for ipa-cp
@ 2011-05-09  0:34 Jan Hubicka
  0 siblings, 0 replies; only message in thread
From: Jan Hubicka @ 2011-05-09  0:34 UTC (permalink / raw)
  To: gcc-patches, mjambor

Hi,
this patch adds neccesary support into ipa-inline-analysis to make it useable
for ipa-cp. I.e. in the following testcase:
int test (int a)
{ 
  if (a>10)
    {  
       e();
       e();
       e();
       e();
       e();
       e();
       e();
       e();
    }
}
main2()
{ 
  test(1);
  test(1);
  test(1);
  test(1);
  test(1);
  test(1);
}

We now work out that size of ipcp clone of test is 3 (that is what we account
for size of empty function) and time 2 (that is time of return statement)
We also work out that all calls are optimized out in the clone:

Inline summary for test.constprop.0/3 inlinable versionable
  self time:       2
  global time:     2
  self size:       3
  global size:     3
  self stack:      0
  global stack:    0
    size:0.000000, time:0.000000, predicate:(true)
    size:2.000000, time:0.000000, predicate:(not inlined)
    size:1.000000, time:2.000000, predicate:(op0 <= 10) && (not inlined)
  calls:
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)
    e/2 function body not available
      loop depth: 0 freq:   0 size: 1 time: 10 callee size: 0 stack: 0 predicate: (false)

(the op0<=10 is completely pointless predicate, but we don't really care).

New function estimate_ipcp_clone_size_and_time is exported that allows ipa-cp
to query the estimates before transformation is done.  IPA-cp don't really use
it now in any wise way, it is up to Martin's planned rewrite of the pass for
partial specialization to do so.

Main extra work is in updating virtual clone summaries based on their tree_map
info. It is similar to one already done in inliner, just it don't need to actually
merge the summaries, just work out what clauses are false now.

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

Honza
	* cgraph.c (cgraph_clone_node): Add call_duplication_hook parameter.
	(cgraph_create_virtual_clone): Call hooks once virtual clone is finished.
	* cgraph.h (cgraph_clone_node): Update prototype.
	* ipa-cp.c (ipcp_estimate_growth): Use estimate_ipcp_clone_size_and_time.
	* ipa-inline-transform.c (clone_inlined_nodes): Update.
	* lto-cgraph.c (input_node): Update.
	* ipa-inline.c (recursive_inlining): Update.
	* ipa-inline.h (estimate_ipcp_clone_size_and_time): New function.
	(evaluate_conditions_for_known_args): Break out from ...
	(evaluate_conditions_for_edge): ... here.
	(evaluate_conditions_for_ipcp_clone): New function.
	(inline_node_duplication_hook): Update clone summary based
	on parameter map.
	(estimate_callee_size_and_time): Rename to ...
	(estimate_node_size_and_time): take NODE instead of EDGE;
	take POSSIBLE_TRUTHS as argument.
	(estimate_callee_size_and_time): Update.
	(estimate_ipcp_clone_size_and_time): New function.
	(do_estimate_edge_time): Update.
	
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 173549)
--- cgraph.c	(working copy)
*************** cgraph_clone_edge (struct cgraph_edge *e
*** 2128,2133 ****
--- 2128,2134 ----
    return new_edge;
  }
  
+ 
  /* Create node representing clone of N executed COUNT times.  Decrease
     the execution counts from original node too.
     The new clone will have decl set to DECL that may or may not be the same
*************** cgraph_clone_edge (struct cgraph_edge *e
*** 2135,2145 ****
  
     When UPDATE_ORIGINAL is true, the counts are subtracted from the original
     function's profile to reflect the fact that part of execution is handled
!    by node.  */
  struct cgraph_node *
  cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq,
  		   bool update_original,
! 		   VEC(cgraph_edge_p,heap) *redirect_callers)
  {
    struct cgraph_node *new_node = cgraph_create_node_1 ();
    struct cgraph_edge *e;
--- 2136,2150 ----
  
     When UPDATE_ORIGINAL is true, the counts are subtracted from the original
     function's profile to reflect the fact that part of execution is handled
!    by node.  
!    When CALL_DUPLICATOIN_HOOK is true, the ipa passes are acknowledged about
!    the new clone. Otherwise the caller is responsible for doing so later.  */
! 
  struct cgraph_node *
  cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq,
  		   bool update_original,
! 		   VEC(cgraph_edge_p,heap) *redirect_callers,
! 		   bool call_duplication_hook)
  {
    struct cgraph_node *new_node = cgraph_create_node_1 ();
    struct cgraph_edge *e;
*************** cgraph_clone_node (struct cgraph_node *n
*** 2202,2208 ****
    n->clones = new_node;
    new_node->clone_of = n;
  
-   cgraph_call_node_duplication_hooks (n, new_node);
    if (n->decl != decl)
      {
        struct cgraph_node **slot;
--- 2207,2212 ----
*************** cgraph_clone_node (struct cgraph_node *n
*** 2221,2226 ****
--- 2225,2233 ----
  	  *aslot = new_node;
  	}
      }
+ 
+   if (call_duplication_hook)
+     cgraph_call_node_duplication_hooks (n, new_node);
    return new_node;
  }
  
*************** cgraph_create_virtual_clone (struct cgra
*** 2287,2293 ****
  
    new_node = cgraph_clone_node (old_node, new_decl, old_node->count,
  				CGRAPH_FREQ_BASE, false,
! 				redirect_callers);
    /* Update the properties.
       Make clone visible only within this translation unit.  Make sure
       that is not weak also.
--- 2294,2300 ----
  
    new_node = cgraph_clone_node (old_node, new_decl, old_node->count,
  				CGRAPH_FREQ_BASE, false,
! 				redirect_callers, false);
    /* Update the properties.
       Make clone visible only within this translation unit.  Make sure
       that is not weak also.
*************** cgraph_create_virtual_clone (struct cgra
*** 2358,2363 ****
--- 2365,2372 ----
    new_node->lowered = true;
    new_node->reachable = true;
  
+   cgraph_call_node_duplication_hooks (old_node, new_node);
+ 
  
    return new_node;
  }
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 173549)
--- cgraph.h	(working copy)
*************** struct cgraph_edge * cgraph_clone_edge (
*** 506,512 ****
  					struct cgraph_node *, gimple,
  					unsigned, gcov_type, int, bool);
  struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
! 					int, bool, VEC(cgraph_edge_p,heap) *);
  
  void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
  void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
--- 506,513 ----
  					struct cgraph_node *, gimple,
  					unsigned, gcov_type, int, bool);
  struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
! 					int, bool, VEC(cgraph_edge_p,heap) *,
! 					bool);
  
  void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
  void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
Index: ipa-cp.c
===================================================================
*** ipa-cp.c	(revision 173549)
--- ipa-cp.c	(working copy)
*************** ipcp_estimate_growth (struct cgraph_node
*** 1102,1108 ****
       call site.  Precise cost is difficult to get, as our size metric counts
       constants and moves as free.  Generally we are looking for cases that
       small function is called very many times.  */
!   growth = inline_summary (node)->self_size
    	   - removable_args * redirectable_node_callers;
    if (growth < 0)
      return 0;
--- 1102,1109 ----
       call site.  Precise cost is difficult to get, as our size metric counts
       constants and moves as free.  Generally we are looking for cases that
       small function is called very many times.  */
!   estimate_ipcp_clone_size_and_time (node, &growth, NULL);
!   growth = growth
    	   - removable_args * redirectable_node_callers;
    if (growth < 0)
      return 0;
Index: ipa-inline-transform.c
===================================================================
*** ipa-inline-transform.c	(revision 173549)
--- ipa-inline-transform.c	(working copy)
*************** clone_inlined_nodes (struct cgraph_edge 
*** 133,139 ****
  	  struct cgraph_node *n;
  	  n = cgraph_clone_node (e->callee, e->callee->decl,
  				 e->count, e->frequency,
! 				 update_original, NULL);
  	  cgraph_redirect_edge_callee (e, n);
  	}
      }
--- 133,139 ----
  	  struct cgraph_node *n;
  	  n = cgraph_clone_node (e->callee, e->callee->decl,
  				 e->count, e->frequency,
! 				 update_original, NULL, true);
  	  cgraph_redirect_edge_callee (e, n);
  	}
      }
Index: lto-cgraph.c
===================================================================
*** lto-cgraph.c	(revision 173549)
--- lto-cgraph.c	(working copy)
*************** input_node (struct lto_file_decl_data *f
*** 999,1005 ****
    if (clone_ref != LCC_NOT_FOUND)
      {
        node = cgraph_clone_node (VEC_index (cgraph_node_ptr, nodes, clone_ref), fn_decl,
! 				0, CGRAPH_FREQ_BASE, false, NULL);
      }
    else
      node = cgraph_get_create_node (fn_decl);
--- 999,1005 ----
    if (clone_ref != LCC_NOT_FOUND)
      {
        node = cgraph_clone_node (VEC_index (cgraph_node_ptr, nodes, clone_ref), fn_decl,
! 				0, CGRAPH_FREQ_BASE, false, NULL, false);
      }
    else
      node = cgraph_get_create_node (fn_decl);
Index: ipa-inline.c
===================================================================
*** ipa-inline.c	(revision 173549)
--- ipa-inline.c	(working copy)
*************** recursive_inlining (struct cgraph_edge *
*** 1174,1180 ****
  	  /* We need original clone to copy around.  */
  	  master_clone = cgraph_clone_node (node, node->decl,
  					    node->count, CGRAPH_FREQ_BASE,
! 					    false, NULL);
  	  for (e = master_clone->callees; e; e = e->next_callee)
  	    if (!e->inline_failed)
  	      clone_inlined_nodes (e, true, false, NULL);
--- 1174,1180 ----
  	  /* We need original clone to copy around.  */
  	  master_clone = cgraph_clone_node (node, node->decl,
  					    node->count, CGRAPH_FREQ_BASE,
! 					    false, NULL, true);
  	  for (e = master_clone->callees; e; e = e->next_callee)
  	    if (!e->inline_failed)
  	      clone_inlined_nodes (e, true, false, NULL);
Index: ipa-inline.h
===================================================================
*** ipa-inline.h	(revision 173549)
--- ipa-inline.h	(working copy)
*************** void inline_free_summary (void);
*** 149,154 ****
--- 149,155 ----
  void initialize_inline_failed (struct cgraph_edge *);
  int estimate_time_after_inlining (struct cgraph_node *, struct cgraph_edge *);
  int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *);
+ void estimate_ipcp_clone_size_and_time (struct cgraph_node *, int *, int *);
  int do_estimate_growth (struct cgraph_node *);
  void inline_merge_summary (struct cgraph_edge *edge);
  int do_estimate_edge_growth (struct cgraph_edge *edge);
Index: ipa-inline-analysis.c
===================================================================
*** ipa-inline-analysis.c	(revision 173549)
--- ipa-inline-analysis.c	(working copy)
*************** edge_set_predicate (struct cgraph_edge *
*** 539,544 ****
--- 539,580 ----
  }
  
  
+ /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
+    Return clause of possible truths. When INLINE_P is true, assume that
+    we are inlining.  */
+ 
+ static clause_t
+ evaluate_conditions_for_known_args (struct cgraph_node *node,
+ 				    bool inline_p,
+ 				    VEC (tree, heap) *known_vals)
+ {
+   clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
+   struct inline_summary *info = inline_summary (node);
+   int i;
+   struct condition *c;
+ 
+   for (i = 0; VEC_iterate (condition, info->conds, i, c); i++)
+     {
+       tree val = VEC_index (tree, known_vals, c->operand_num);
+       tree res;
+ 
+       if (!val)
+ 	{
+ 	  clause |= 1 << (i + predicate_first_dynamic_condition);
+ 	  continue;
+ 	}
+       if (c->code == IS_NOT_CONSTANT)
+ 	continue;
+       res = fold_binary_to_constant (c->code, boolean_type_node, val, c->val);
+       if (res
+ 	  && integer_zerop (res))
+ 	continue;
+       clause |= 1 << (i + predicate_first_dynamic_condition);
+     }
+   return clause;
+ }
+ 
+ 
  /* Work out what conditions might be true at invocation of E.  */
  
  static clause_t
*************** evaluate_conditions_for_edge (struct cgr
*** 557,563 ****
        struct ipa_edge_args *args = IPA_EDGE_REF (e);
        int i, count = ipa_get_cs_argument_count (args);
        struct ipcp_lattice lat;
-       struct condition *c;
        VEC (tree, heap) *known_vals = NULL;
  
        if (e->caller->global.inlined_to)
--- 593,598 ----
*************** evaluate_conditions_for_edge (struct cgr
*** 572,595 ****
  	  if (lat.type == IPA_CONST_VALUE)
  	    VEC_replace (tree, known_vals, i, lat.constant);
  	}
!       for (i = 0; VEC_iterate (condition, info->conds, i, c); i++)
! 	{
! 	  tree val = VEC_index (tree, known_vals, c->operand_num);
! 	  tree res;
! 
! 	  if (!val)
! 	    {
! 	      clause |= 1 << (i + predicate_first_dynamic_condition);
! 	      continue;
! 	    }
! 	  if (c->code == IS_NOT_CONSTANT)
! 	    continue;
! 	  res = fold_binary_to_constant (c->code, boolean_type_node, val, c->val);
! 	  if (res
! 	      && integer_zerop (res))
! 	    continue;
! 	  clause |= 1 << (i + predicate_first_dynamic_condition);
! 	}
        VEC_free (tree, heap, known_vals);
      }
    else
--- 607,614 ----
  	  if (lat.type == IPA_CONST_VALUE)
  	    VEC_replace (tree, known_vals, i, lat.constant);
  	}
!       clause = evaluate_conditions_for_known_args (e->callee,
! 						   inline_p, known_vals);
        VEC_free (tree, heap, known_vals);
      }
    else
*************** evaluate_conditions_for_edge (struct cgr
*** 600,605 ****
--- 619,649 ----
  }
  
  
+ /* Work out what conditions might be true at invocation of NODE
+    that is (future) ipa-cp clone.  */
+ 
+ static clause_t
+ evaluate_conditions_for_ipcp_clone (struct cgraph_node *node)
+ {
+   struct ipa_node_params *parms_info = IPA_NODE_REF (node);
+   int i, count = ipa_get_param_count (parms_info);
+   struct ipcp_lattice *lat;
+   VEC (tree, heap) *known_vals = NULL;
+   clause_t clause;
+ 
+   VEC_safe_grow_cleared (tree, heap, known_vals, count);
+   for (i = 0; i < count; i++)
+     {
+       lat = ipa_get_lattice (parms_info, i);
+       if (lat->type == IPA_CONST_VALUE)
+ 	VEC_replace (tree, known_vals, i, lat->constant);
+     }
+   clause = evaluate_conditions_for_known_args (node, false, known_vals);
+   VEC_free (tree, heap, known_vals);
+   return clause;
+ }
+ 
+ 
  /* Allocate the inline summary vector or resize it to cover all cgraph nodes. */
  
  static void
*************** inline_node_duplication_hook (struct cgr
*** 661,668 ****
    info = inline_summary (dst);
    memcpy (info, inline_summary (src),
  	  sizeof (struct inline_summary));
    info->conds = VEC_copy (condition, gc, info->conds);
!   info->entry = VEC_copy (size_time_entry, gc, info->entry);
  }
  
  
--- 705,869 ----
    info = inline_summary (dst);
    memcpy (info, inline_summary (src),
  	  sizeof (struct inline_summary));
+   /* TODO: as an optimization, we may avoid copying conditions
+      that are known to be false or true.  */
    info->conds = VEC_copy (condition, gc, info->conds);
! 
!   /* When there are any replacements in the function body, see if we can figure
!      out that something was optimized out.  */
!   if (ipa_node_params_vector && dst->clone.tree_map)
!     {
!       VEC(size_time_entry,gc) *entry = info->entry;
!       /* Use SRC parm info since it may not be copied yet.  */
!       struct ipa_node_params *parms_info = IPA_NODE_REF (src);
!       VEC (tree, heap) *known_vals = NULL;
!       int count = ipa_get_param_count (parms_info);
!       int i,j;
!       clause_t possible_truths;
!       struct predicate true_pred = true_predicate ();
!       size_time_entry *e;
!       int optimized_out_size = 0;
!       gcov_type optimized_out_time = 0;
!       bool inlined_to_p = false;
!       struct cgraph_edge *edge;
! 
!       info->entry = false;
!       VEC_safe_grow_cleared (tree, heap, known_vals, count);
!       for (i = 0; i < count; i++)
!         {
! 	  tree t = ipa_get_param (parms_info, i);
! 	  struct ipa_replace_map *r;
! 
! 	  for (j = 0;
! 	       VEC_iterate (ipa_replace_map_p, dst->clone.tree_map, j, r);
! 	       j++)
! 	    {
! 	      if (r->old_tree == t
! 		  && r->replace_p
! 		  && !r->ref_p)
! 		{
! 		  VEC_replace (tree, known_vals, i, r->new_tree);
! 		  break;
! 		}
! 	    }
! 	}
!       possible_truths = evaluate_conditions_for_known_args (dst,
! 							    false, known_vals);
!       VEC_free (tree, heap, known_vals);
! 
!       account_size_time (info, 0, 0, &true_pred);
! 
!       /* Remap size_time vectors.
! 	 Simplify the predicate by prunning out alternatives that are known
! 	 to be false.
! 	 TODO: as on optimization, we can also eliminate conditions known to be true.  */
!       for (i = 0; VEC_iterate (size_time_entry, entry, i, e); i++)
! 	{
! 	  struct predicate new_predicate = true_predicate ();
! 	  for (j = 0; e->predicate.clause[j]; j++)
! 	    if (!(possible_truths & e->predicate.clause[j]))
! 	      {
! 		new_predicate = false_predicate ();
! 		break;
! 	      }
! 	    else
! 	      add_clause (&new_predicate,
! 			  possible_truths & e->predicate.clause[j]);
! 	  if (false_predicate_p (&new_predicate))
! 	    {
! 	      optimized_out_size += e->size;
! 	      optimized_out_time += e->time;
! 	    }
! 	  else
! 	    account_size_time (info, e->size, e->time, &new_predicate);
! 	}
! 
!       /* Remap edge predicates with the same simplificaiton as above.  */
!       for (edge = dst->callees; edge; edge = edge->next_callee)
! 	{
! 	  struct predicate new_predicate = true_predicate ();
! 	  struct inline_edge_summary *es = inline_edge_summary (edge);
! 
! 	  if (!edge->inline_failed)
! 	    inlined_to_p = true;
! 	  if (!es->predicate)
! 	    continue;
! 	  for (j = 0; es->predicate->clause[j]; j++)
! 	    if (!(possible_truths & es->predicate->clause[j]))
! 	      {
! 		new_predicate = false_predicate ();
! 		break;
! 	      }
! 	    else
! 	      add_clause (&new_predicate,
! 			  possible_truths & es->predicate->clause[j]);
! 	  if (false_predicate_p (&new_predicate)
! 	      && !false_predicate_p (es->predicate))
! 	    {
! 	      optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
! 	      optimized_out_time += (es->call_stmt_time
! 				     * (INLINE_TIME_SCALE / CGRAPH_FREQ_BASE)
! 				     * edge->frequency);
! 	      edge->frequency = 0;
! 	    }
! 	  *es->predicate = new_predicate;
! 	}
! 
!       /* Remap indirect edge predicates with the same simplificaiton as above.  */
!       for (edge = dst->indirect_calls; edge; edge = edge->next_callee)
! 	{
! 	  struct predicate new_predicate = true_predicate ();
! 	  struct inline_edge_summary *es = inline_edge_summary (edge);
! 
! 	  if (!edge->inline_failed)
! 	    inlined_to_p = true;
! 	  if (!es->predicate)
! 	    continue;
! 	  for (j = 0; es->predicate->clause[j]; j++)
! 	    if (!(possible_truths & es->predicate->clause[j]))
! 	      {
! 		new_predicate = false_predicate ();
! 		break;
! 	      }
! 	    else
! 	      add_clause (&new_predicate,
! 			  possible_truths & es->predicate->clause[j]);
! 	  if (false_predicate_p (&new_predicate)
! 	      && !false_predicate_p (es->predicate))
! 	    {
! 	      optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
! 	      optimized_out_time += (es->call_stmt_time
! 				     * (INLINE_TIME_SCALE / CGRAPH_FREQ_BASE)
! 				     * edge->frequency);
! 	      edge->frequency = 0;
! 	    }
! 	  *es->predicate = new_predicate;
! 	}
! 
!       /* If inliner or someone after inliner will ever start producing
! 	 non-trivial clones, we will get trouble with lack of information
! 	 about updating self sizes, because size vectors already contains
! 	 sizes of the calees.  */
!       gcc_assert (!inlined_to_p 
! 		  || (!optimized_out_size && !optimized_out_time));
! 
!       info->size -= optimized_out_size / INLINE_SIZE_SCALE;
!       info->self_size -= optimized_out_size / INLINE_SIZE_SCALE;
!       gcc_assert (info->size > 0);
!       gcc_assert (info->self_size > 0);
! 
!       optimized_out_time /= INLINE_TIME_SCALE;
!       if (optimized_out_time > MAX_TIME)
! 	optimized_out_time = MAX_TIME;
!       info->time -= optimized_out_time;
!       info->self_time -= optimized_out_time;
!       if (info->time < 0)
! 	info->time = 0;
!       if (info->self_time < 0)
! 	info->self_time = 0;
!     }
!   else
!     info->entry = VEC_copy (size_time_entry, gc, info->entry);
  }
  
  
*************** estimate_calls_size_and_time (struct cgr
*** 1565,1581 ****
  }
  
  
! /* Estimate size and time needed to execute callee of EDGE assuming
!    that parameters known to be constant at caller of EDGE are
!    propagated.  If INLINE_P is true, it is assumed that call will
!    be inlined.  */
  
  static void
! estimate_callee_size_and_time (struct cgraph_edge *edge, bool inline_p,
! 		       	       int *ret_size, int *ret_time)
  {
!   struct inline_summary *info = inline_summary (edge->callee);
!   clause_t clause = evaluate_conditions_for_edge (edge, inline_p);
    size_time_entry *e;
    int size = 0, time = 0;
    int i;
--- 1766,1780 ----
  }
  
  
! /* Estimate size and time needed to execute NODE assuming
!    POSSIBLE_TRUTHS clause. */
  
  static void
! estimate_node_size_and_time (struct cgraph_node *node,
! 			     clause_t possible_truths,
! 		       	     int *ret_size, int *ret_time)
  {
!   struct inline_summary *info = inline_summary (node);
    size_time_entry *e;
    int size = 0, time = 0;
    int i;
*************** estimate_callee_size_and_time (struct cg
*** 1584,1598 ****
        && (dump_flags & TDF_DETAILS))
      {
        bool found = false;
!       fprintf (dump_file, "   Estimating callee body: %s/%i\n"
  			  "   Known to be false: ",
! 	       cgraph_node_name (edge->callee),
! 	       edge->callee->uid);
  
        for (i = predicate_not_inlined_condition;
  	   i < (predicate_first_dynamic_condition
  		+ (int)VEC_length (condition, info->conds)); i++)
! 	if (!(clause & (1 << i)))
  	  {
  	    if (found)
  	      fprintf (dump_file, ", ");
--- 1783,1797 ----
        && (dump_flags & TDF_DETAILS))
      {
        bool found = false;
!       fprintf (dump_file, "   Estimating body: %s/%i\n"
  			  "   Known to be false: ",
! 	       cgraph_node_name (node),
! 	       node->uid);
  
        for (i = predicate_not_inlined_condition;
  	   i < (predicate_first_dynamic_condition
  		+ (int)VEC_length (condition, info->conds)); i++)
! 	if (!(possible_truths & (1 << i)))
  	  {
  	    if (found)
  	      fprintf (dump_file, ", ");
*************** estimate_callee_size_and_time (struct cg
*** 1602,1614 ****
      }
  
    for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++)
!     if (evaluate_predicate (&e->predicate, clause))
        time += e->time, size += e->size;
  
    if (time > MAX_TIME * INLINE_TIME_SCALE)
      time = MAX_TIME * INLINE_TIME_SCALE;
  
!   estimate_calls_size_and_time (edge->callee, &size, &time, clause);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
--- 1801,1813 ----
      }
  
    for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++)
!     if (evaluate_predicate (&e->predicate, possible_truths))
        time += e->time, size += e->size;
  
    if (time > MAX_TIME * INLINE_TIME_SCALE)
      time = MAX_TIME * INLINE_TIME_SCALE;
  
!   estimate_calls_size_and_time (node, &size, &time, possible_truths);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
*************** estimate_callee_size_and_time (struct cg
*** 1624,1629 ****
--- 1823,1843 ----
  }
  
  
+ /* Estimate size and time needed to execute callee of EDGE assuming
+    that parameters known to be constant at caller of EDGE are
+    propagated.  If INLINE_P is true, it is assumed that call will
+    be inlined.  */
+ 
+ void
+ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
+ 		                   int *ret_size, int *ret_time)
+ {
+   estimate_node_size_and_time (node,
+ 			       evaluate_conditions_for_ipcp_clone (node),
+ 			       ret_size, ret_time);
+ }
+ 
+ 
  /* Translate all conditions from callee representation into caller representation and
     symbolically evaluate predicate P into new predicate.
  
*************** do_estimate_edge_time (struct cgraph_edg
*** 1872,1878 ****
    struct inline_edge_summary *es = inline_edge_summary (edge);
  
    gcc_checking_assert (edge->inline_failed);
!   estimate_callee_size_and_time (edge, true, &size, &time);
  
    ret = (((gcov_type)time - es->call_stmt_time) * edge->frequency
  	 + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
--- 2086,2094 ----
    struct inline_edge_summary *es = inline_edge_summary (edge);
  
    gcc_checking_assert (edge->inline_failed);
!   estimate_node_size_and_time (edge->callee,
! 			       evaluate_conditions_for_edge (edge, true),
! 			       &size, &time);
  
    ret = (((gcov_type)time - es->call_stmt_time) * edge->frequency
  	 + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
*************** do_estimate_edge_growth (struct cgraph_e
*** 1921,1927 ****
  
    /* Early inliner runs without caching, go ahead and do the dirty work.  */
    gcc_checking_assert (edge->inline_failed);
!   estimate_callee_size_and_time (edge, true, &size, NULL);
    gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
    return size - inline_edge_summary (edge)->call_stmt_size;
  }
--- 2137,2145 ----
  
    /* Early inliner runs without caching, go ahead and do the dirty work.  */
    gcc_checking_assert (edge->inline_failed);
!   estimate_node_size_and_time (edge->callee,
! 			       evaluate_conditions_for_edge (edge, true),
! 			       &size, NULL);
    gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
    return size - inline_edge_summary (edge)->call_stmt_size;
  }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-05-08 17:35 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-09  0:34 Better time/size estimates for ipa-cp Jan Hubicka

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