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; }