Hi, this patch finishes the basic predicate infrastructure of ipa-inline by adding predicates to edges. The predicates are combined, so we can work out very simple cases where function call becmes dead after inlining. In tramp3d we get couple hundred cases like that, so it seems to make difference and I can also make quite reliable testcases for testsuite, now.
Bootstrapped/regtested x86_64-linux, will commit it later today. Honza * testsuite/gcc.dg/tree-ssa/inline-9.c: New testcase. * ipa-inline.h (struct inline_edge_summary): Add predicate pointer. * ipa-inline-analysis.c: Include alloc-pool.h. (edge_predicate_pool): New. (trye_predicate_p): New function (false_predicate_p): New function. (add_clause): Sanity check that false clauses are "optimized"; never add clauses to predicate that is already known to be false. (and_predicate): Use flase_predicate_p. (evaulate_predicate): Rename to ... (evaluate_predicate): ... this one; update all callers; assert that false is not listed among possible truths. (dump_predicate): Use true_predicate_p. (account_size_time): Use false_predicate_p. (evaulate_conditions_for_edge): Rename to ... (evaluate_conditions_for_edge) ... this one. (edge_set_predicate): New function. (inline_edge_duplication_hook): Duplicate edge predicates. (inline_edge_removal_hook): Free edge predicates. (dump_inline_edge_summary): Add INFO parameter; dump edge predicates. (dump_inline_summary): Update. (estimate_function_body_sizes): Set edge predicates. (estimate_calls_size_and_time): Handle predicates. (estimate_callee_size_and_time): Update. (remap_predicate): Add toplev_predicate; update comment. (remap_edge_predicates): New function. (inline_merge_summary): Compute toplev predicate; update. (read_predicate): New function. (read_inline_edge_summary): Use it. (inline_read_section): Likewise. (write_predicate): New function. (write_inline_edge_summary): Use it. (inline_write_summary): Likewise. (inline_free_summary): Free alloc pool and edge summary vec. Index: testsuite/gcc.dg/tree-ssa/inline-9.c =================================================================== *** testsuite/gcc.dg/tree-ssa/inline-9.c (revision 0) --- testsuite/gcc.dg/tree-ssa/inline-9.c (revision 0) *************** *** 0 **** --- 1,24 ---- + /* { dg-do compile } */ + /* { dg-options "-Os -fdump-tree-optimized" } */ + + /* When optimizing for size, t should be inlined when it expands to one call only. */ + extern int q(int); + int t(int a) + { + if (a > 12) + { + q(a+5); + q(a+5); + } + else + q(a+10); + } + + main() + { + t(5); + t(20); + } + /* { dg-final { scan-tree-dump-times "q (15)" 1 "optimized" } } */ + /* { dg-final { scan-tree-dump-times "t (20)" 1 "optimized" } } */ + /* { dg-final { cleanup-tree-dump "optimized" } } */ Index: ipa-inline.h =================================================================== *** ipa-inline.h (revision 173018) --- ipa-inline.h (working copy) *************** struct inline_edge_summary *** 120,125 **** --- 120,126 ---- int call_stmt_time; /* Depth of loop nest, 0 means no nesting. */ unsigned short int loop_depth; + struct predicate *predicate; }; typedef struct inline_edge_summary inline_edge_summary_t; Index: ipa-inline-analysis.c =================================================================== *** ipa-inline-analysis.c (revision 173018) --- ipa-inline-analysis.c (working copy) *************** along with GCC; see the file COPYING3. *** 85,90 **** --- 85,91 ---- #include "ipa-prop.h" #include "lto-streamer.h" #include "ipa-inline.h" + #include "alloc-pool.h" /* Estimate runtime of function can easilly run into huge numbers with many nested loops. Be sure we can compute time * INLINE_SIZE_SCALE in integer. *************** VEC(inline_edge_summary_t,heap) *inline_ *** 129,134 **** --- 130,137 ---- VEC(int,heap) *node_growth_cache; VEC(edge_growth_cache_entry,heap) *edge_growth_cache; + /* Edge predicates goes here. */ + static alloc_pool edge_predicate_pool; /* Return true predicate (tautology). We represent it by empty list of clauses. */ *************** false_predicate (void) *** 163,168 **** --- 166,195 ---- } + /* Return true if P is (false). */ + + static inline bool + true_predicate_p (struct predicate *p) + { + return !p->clause[0]; + } + + + /* Return true if P is (false). */ + + static inline bool + false_predicate_p (struct predicate *p) + { + if (p->clause[0] == (1 << predicate_false_condition)) + { + gcc_checking_assert (!p->clause[1] + && p->clause[0] == 1 << predicate_false_condition); + return true; + } + return false; + } + + /* Return predicate that is set true when function is not inlined. */ static inline struct predicate not_inlined_predicate (void) *************** add_clause (struct predicate *p, clause_ *** 207,222 **** { int i; int insert_here = -1; /* True clause. */ if (!clause) return; /* Flase clause makes the whole predicate false. Kill the other variants. */ ! if (clause & (1 << predicate_false_condition)) { p->clause[0] = (1 << predicate_false_condition); p->clause[1] = 0; } for (i = 0; i < MAX_CLAUSES - 1; i++) { if (p->clause[i] == clause) --- 234,254 ---- { int i; int insert_here = -1; + /* True clause. */ if (!clause) return; /* Flase clause makes the whole predicate false. Kill the other variants. */ ! if (clause == (1 << predicate_false_condition)) { p->clause[0] = (1 << predicate_false_condition); p->clause[1] = 0; + return; } + if (false_predicate_p (p)) + return; + gcc_assert (!(clause & (1 << predicate_false_condition))); for (i = 0; i < MAX_CLAUSES - 1; i++) { if (p->clause[i] == clause) *************** and_predicates (struct predicate *p, str *** 247,252 **** --- 279,285 ---- { struct predicate out = *p; int i; + for (i = 0; p2->clause[i]; i++) { gcc_checking_assert (i < MAX_CLAUSES); *************** or_predicates (struct predicate *p, stru *** 263,279 **** { struct predicate out = true_predicate (); int i,j; /* If one of conditions is false, return the other. */ ! if (p2->clause[0] == 1 << predicate_false_condition) ! { ! gcc_checking_assert (!p2->clause[1]); ! return *p; ! } ! if (p->clause[0] == 1 << predicate_false_condition) ! { ! gcc_checking_assert (!p->clause[1]); ! return *p2; ! } for (i = 0; p->clause[i]; i++) for (j = 0; p2->clause[j]; j++) { --- 296,307 ---- { struct predicate out = true_predicate (); int i,j; + /* If one of conditions is false, return the other. */ ! if (false_predicate_p (p2)) ! return *p; ! if (false_predicate_p (p)) ! return *p2; for (i = 0; p->clause[i]; i++) for (j = 0; p2->clause[j]; j++) { *************** predicates_equal_p (struct predicate *p, *** 304,317 **** to be false. */ static bool ! evaulate_predicate (struct predicate *p, clause_t possible_truths) { int i; /* True remains true. */ ! if (!p->clause[0]) return true; /* See if we can find clause we can disprove. */ for (i = 0; p->clause[i]; i++) { --- 332,347 ---- to be false. */ static bool ! evaluate_predicate (struct predicate *p, clause_t possible_truths) { int i; /* True remains true. */ ! if (true_predicate_p (p)) return true; + gcc_assert (!(possible_truths & (1 << predicate_false_condition))); + /* See if we can find clause we can disprove. */ for (i = 0; p->clause[i]; i++) { *************** static void *** 376,382 **** dump_predicate (FILE *f, conditions conds, struct predicate *pred) { int i; ! if (!pred->clause[0]) dump_clause (f, conds, 0); else for (i = 0; pred->clause[i]; i++) --- 406,412 ---- dump_predicate (FILE *f, conditions conds, struct predicate *pred) { int i; ! if (true_predicate_p (pred)) dump_clause (f, conds, 0); else for (i = 0; pred->clause[i]; i++) *************** account_size_time (struct inline_summary *** 398,404 **** bool found = false; int i; ! if (pred->clause[0] == (1 << predicate_false_condition)) return; /* We need to create initial empty unconitional clause, but otherwie --- 428,434 ---- bool found = false; int i; ! if (false_predicate_p (pred)) return; /* We need to create initial empty unconitional clause, but otherwie *************** account_size_time (struct inline_summary *** 448,458 **** } } /* Work out what conditions might be true at invocation of E. */ static clause_t ! evaulate_conditions_for_edge (struct cgraph_edge *e, bool inline_p) { clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition; struct inline_summary *info = inline_summary (e->callee); --- 478,508 ---- } } + /* Set predicate for edge E. */ + + static void + edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate) + { + struct inline_edge_summary *es = inline_edge_summary (e); + if (predicate && !true_predicate_p (predicate)) + { + if (!es->predicate) + es->predicate = (struct predicate *)pool_alloc (edge_predicate_pool); + *es->predicate = *predicate; + } + else + { + if (es->predicate) + pool_free (edge_predicate_pool, es->predicate); + es->predicate = NULL; + } + } + /* Work out what conditions might be true at invocation of E. */ static clause_t ! evaluate_conditions_for_edge (struct cgraph_edge *e, bool inline_p) { clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition; struct inline_summary *info = inline_summary (e->callee); *************** inline_summary_alloc (void) *** 536,541 **** --- 586,594 ---- <= (unsigned) cgraph_edge_max_uid) VEC_safe_grow_cleared (inline_edge_summary_t, heap, inline_edge_summary_vec, cgraph_edge_max_uid + 1); + if (!edge_predicate_pool) + edge_predicate_pool = create_alloc_pool ("edge predicates", sizeof (struct predicate), + 10); } /* Hook that is called by cgraph.c when a node is removed. */ *************** inline_edge_duplication_hook (struct cgr *** 580,589 **** ATTRIBUTE_UNUSED void *data) { struct inline_edge_summary *info; inline_summary_alloc (); info = inline_edge_summary (dst); ! memcpy (info, inline_edge_summary (src), sizeof (struct inline_edge_summary)); } --- 633,646 ---- ATTRIBUTE_UNUSED void *data) { struct inline_edge_summary *info; + struct inline_edge_summary *srcinfo; inline_summary_alloc (); info = inline_edge_summary (dst); ! srcinfo = inline_edge_summary (src); ! memcpy (info, srcinfo, sizeof (struct inline_edge_summary)); + info->predicate = NULL; + edge_set_predicate (dst, srcinfo->predicate); } *************** inline_edge_removal_hook (struct cgraph_ *** 595,601 **** if (edge_growth_cache) reset_edge_growth_cache (edge); if (edge->uid < (int)VEC_length (inline_edge_summary_t, inline_edge_summary_vec)) ! memset (inline_edge_summary (edge), 0, sizeof (struct inline_edge_summary)); } --- 652,661 ---- if (edge_growth_cache) reset_edge_growth_cache (edge); if (edge->uid < (int)VEC_length (inline_edge_summary_t, inline_edge_summary_vec)) ! { ! edge_set_predicate (edge, NULL); ! memset (inline_edge_summary (edge), 0, sizeof (struct inline_edge_summary)); ! } } *************** free_growth_caches (void) *** 628,651 **** Indent by INDENT. */ static void ! dump_inline_edge_summary (FILE * f, int indent, struct cgraph_node *node) { struct cgraph_edge *edge; for (edge = node->callees; edge; edge = edge->next_callee) { struct inline_edge_summary *es = inline_edge_summary (edge); ! fprintf (f, "%*s%s/%i %s\n%*s loop depth:%2i freq:%4i size:%2i time: %2i\n", indent, "", cgraph_node_name (edge->callee), edge->callee->uid, ! edge->inline_failed ? "inlined" : cgraph_inline_failed_string (edge->inline_failed), indent, "", es->loop_depth, edge->frequency, es->call_stmt_size, es->call_stmt_time); if (!edge->inline_failed) ! dump_inline_edge_summary (f, indent+2, edge->callee); } for (edge = node->indirect_calls; edge; edge = edge->next_callee) { --- 688,719 ---- Indent by INDENT. */ static void ! dump_inline_edge_summary (FILE * f, int indent, struct cgraph_node *node, ! struct inline_summary *info) { struct cgraph_edge *edge; for (edge = node->callees; edge; edge = edge->next_callee) { struct inline_edge_summary *es = inline_edge_summary (edge); ! fprintf (f, "%*s%s/%i %s\n%*s loop depth:%2i freq:%4i size:%2i time: %2i", indent, "", cgraph_node_name (edge->callee), edge->callee->uid, ! !edge->inline_failed ? "inlined" : cgraph_inline_failed_string (edge->inline_failed), indent, "", es->loop_depth, edge->frequency, es->call_stmt_size, es->call_stmt_time); + if (es->predicate) + { + fprintf (f, " predicate: "); + dump_predicate (f, info->conds, es->predicate); + } + else + fprintf (f, "\n"); if (!edge->inline_failed) ! dump_inline_edge_summary (f, indent+2, edge->callee, info); } for (edge = node->indirect_calls; edge; edge = edge->next_callee) { *************** dump_inline_edge_summary (FILE * f, int *** 656,661 **** --- 724,736 ---- edge->frequency, es->call_stmt_size, es->call_stmt_time); + if (es->predicate) + { + fprintf (f, "predicate: "); + dump_predicate (f, info->conds, es->predicate); + } + else + fprintf (f, "\n"); } } *************** dump_inline_summary (FILE * f, struct cg *** 696,702 **** dump_predicate (f, s->conds, &e->predicate); } fprintf (f, " calls:\n"); ! dump_inline_edge_summary (f, 4, node); fprintf (f, "\n"); } } --- 771,777 ---- dump_predicate (f, s->conds, &e->predicate); } fprintf (f, " calls:\n"); ! dump_inline_edge_summary (f, 4, node, s); fprintf (f, "\n"); } } *************** estimate_function_body_sizes (struct cgr *** 991,996 **** --- 1066,1072 ---- es->call_stmt_size = this_size; es->call_stmt_time = this_time; es->loop_depth = bb->loop_depth; + edge_set_predicate (edge, &bb_predicate); /* Do not inline calls where we cannot triviall work around mismatches in argument or return types. */ *************** estimate_edge_size_and_time (struct cgra *** 1158,1174 **** /* Increase SIZE and TIME for size and time needed to handle all calls in NODE. */ static void ! estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time) { struct cgraph_edge *e; for (e = node->callees; e; e = e->next_callee) ! if (e->inline_failed) ! estimate_edge_size_and_time (e, size, time); ! else ! estimate_calls_size_and_time (e->callee, size, time); /* TODO: look for devirtualizing oppurtunities. */ for (e = node->indirect_calls; e; e = e->next_callee) ! estimate_edge_size_and_time (e, size, time); } --- 1234,1262 ---- /* Increase SIZE and TIME for size and time needed to handle all calls in NODE. */ static void ! estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time, ! clause_t possible_truths) { struct cgraph_edge *e; for (e = node->callees; e; e = e->next_callee) ! { ! struct inline_edge_summary *es = inline_edge_summary (e); ! if (!es->predicate || evaluate_predicate (es->predicate, possible_truths)) ! { ! if (e->inline_failed) ! estimate_edge_size_and_time (e, size, time); ! else ! estimate_calls_size_and_time (e->callee, size, time, ! possible_truths); ! } ! } /* TODO: look for devirtualizing oppurtunities. */ for (e = node->indirect_calls; e; e = e->next_callee) ! { ! struct inline_edge_summary *es = inline_edge_summary (e); ! if (!es->predicate || evaluate_predicate (es->predicate, possible_truths)) ! estimate_edge_size_and_time (e, size, time); ! } } *************** estimate_callee_size_and_time (struct cg *** 1182,1188 **** int *ret_size, int *ret_time) { struct inline_summary *info = inline_summary (edge->callee); ! clause_t clause = evaulate_conditions_for_edge (edge, inline_p); size_time_entry *e; int size = 0, time = 0; int i; --- 1270,1276 ---- 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; *************** estimate_callee_size_and_time (struct cg *** 1209,1221 **** } for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++) ! if (evaulate_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); time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE; size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE; --- 1297,1309 ---- } 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; *************** estimate_callee_size_and_time (struct cg *** 1231,1251 **** } ! /* Translate all conditions from callee representation into caller representaiton and ! symbolically evaulate predicate P into new predicate. */ static struct predicate remap_predicate (struct inline_summary *info, struct inline_summary *callee_info, struct predicate *p, VEC (int, heap) *operand_map, ! clause_t possible_truths) { int i; struct predicate out = true_predicate (); /* True predicate is easy. */ ! if (p->clause[0] == 0) ! return *p; for (i = 0; p->clause[i]; i++) { clause_t clause = p->clause[i]; --- 1319,1346 ---- } ! /* Translate all conditions from callee representation into caller representation and ! symbolically evaluate predicate P into new predicate. ! ! INFO is inline_summary of function we are adding predicate into, CALLEE_INFO is summary ! of function predicate P is from. OPERAND_MAP is array giving callee formal IDs the ! caller formal IDs. POSSSIBLE_TRUTHS is clausule of all callee conditions that ! may be true in caller context. TOPLEV_PREDICATE is predicate under which callee ! is executed. */ static struct predicate remap_predicate (struct inline_summary *info, struct inline_summary *callee_info, struct predicate *p, VEC (int, heap) *operand_map, ! clause_t possible_truths, ! struct predicate *toplev_predicate) { int i; struct predicate out = true_predicate (); /* True predicate is easy. */ ! if (true_predicate_p (p)) ! return *toplev_predicate; for (i = 0; p->clause[i]; i++) { clause_t clause = p->clause[i]; *************** remap_predicate (struct inline_summary * *** 1289,1295 **** } out = and_predicates (&out, &clause_predicate); } ! return out; } --- 1384,1390 ---- } out = and_predicates (&out, &clause_predicate); } ! return and_predicates (&out, toplev_predicate); } *************** inline_update_callee_summaries (struct c *** 1325,1330 **** --- 1420,1483 ---- } + /* Remap predicates of callees of NODE. Rest of arguments match + remap_predicate. */ + + static void + remap_edge_predicates (struct cgraph_node *node, + struct inline_summary *info, + struct inline_summary *callee_info, + VEC (int, heap) *operand_map, + clause_t possible_truths, + struct predicate *toplev_predicate) + { + struct cgraph_edge *e; + for (e = node->callees; e; e = e->next_callee) + { + struct inline_edge_summary *es = inline_edge_summary (e); + struct predicate p; + if (es->predicate) + { + p = remap_predicate (info, callee_info, + es->predicate, operand_map, possible_truths, + toplev_predicate); + edge_set_predicate (e, &p); + /* TODO: We should remove the edge for code that will be optimized out, + but we need to keep verifiers and tree-inline happy. + Make it cold for now. */ + if (false_predicate_p (&p)) + { + e->count = 0; + e->frequency = 0; + } + } + if (!e->inline_failed) + remap_edge_predicates (e->callee, info, callee_info, operand_map, + possible_truths, toplev_predicate); + } + for (e = node->indirect_calls; e; e = e->next_callee) + { + struct inline_edge_summary *es = inline_edge_summary (e); + struct predicate p; + if (es->predicate) + { + p = remap_predicate (info, callee_info, + es->predicate, operand_map, possible_truths, + toplev_predicate); + edge_set_predicate (e, &p); + /* TODO: We should remove the edge for code that will be optimized out, + but we need to keep verifiers and tree-inline happy. + Make it cold for now. */ + if (false_predicate_p (&p)) + { + e->count = 0; + e->frequency = 0; + } + } + } + } + + /* We inlined EDGE. Update summary of the function we inlined into. */ void *************** inline_merge_summary (struct cgraph_edge *** 1338,1343 **** --- 1491,1503 ---- size_time_entry *e; VEC (int, heap) *operand_map = NULL; int i; + struct predicate toplev_predicate; + struct inline_edge_summary *es = inline_edge_summary (edge); + + if (es->predicate) + toplev_predicate = *es->predicate; + else + toplev_predicate = true_predicate (); if (ipa_node_params_vector && callee_info->conds /* FIXME: it seems that we forget to get argument count in some cases, *************** inline_merge_summary (struct cgraph_edge *** 1349,1355 **** int count = ipa_get_cs_argument_count (args); int i; ! clause = evaulate_conditions_for_edge (edge, true); VEC_safe_grow_cleared (int, heap, operand_map, count); for (i = 0; i < count; i++) { --- 1509,1515 ---- int count = ipa_get_cs_argument_count (args); int i; ! clause = evaluate_conditions_for_edge (edge, true); VEC_safe_grow_cleared (int, heap, operand_map, count); for (i = 0; i < count; i++) { *************** inline_merge_summary (struct cgraph_edge *** 1366,1383 **** for (i = 0; VEC_iterate (size_time_entry, callee_info->entry, i, e); i++) { struct predicate p = remap_predicate (info, callee_info, ! &e->predicate, operand_map, clause); gcov_type add_time = ((gcov_type)e->time * edge->frequency + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE; if (add_time > MAX_TIME) add_time = MAX_TIME; account_size_time (info, e->size, add_time, &p); } info->size = 0; 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 (to, &info->size, &info->time); inline_update_callee_summaries (edge->callee, inline_edge_summary (edge)->loop_depth); --- 1526,1547 ---- for (i = 0; VEC_iterate (size_time_entry, callee_info->entry, i, e); i++) { struct predicate p = remap_predicate (info, callee_info, ! &e->predicate, operand_map, clause, ! &toplev_predicate); gcov_type add_time = ((gcov_type)e->time * edge->frequency + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE; if (add_time > MAX_TIME) add_time = MAX_TIME; account_size_time (info, e->size, add_time, &p); } + remap_edge_predicates (edge->callee, info, callee_info, operand_map, + clause, &toplev_predicate); info->size = 0; 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 (to, &info->size, &info->time, ! ~(clause_t)(1 << predicate_false_condition)); inline_update_callee_summaries (edge->callee, inline_edge_summary (edge)->loop_depth); *************** inline_generate_summary (void) *** 1602,1616 **** --- 1766,1803 ---- } + /* Read predicate from IB. */ + + static struct predicate + read_predicate (struct lto_input_block *ib) + { + struct predicate out; + clause_t clause; + int k = 0; + + do + { + clause = out.clause[k++] = lto_input_uleb128 (ib); + gcc_assert (k < MAX_CLAUSES); + } + while (clause); + return out; + } + + /* Write inline summary for edge E to OB. */ static void read_inline_edge_summary (struct lto_input_block *ib, struct cgraph_edge *e) { struct inline_edge_summary *es = inline_edge_summary (e); + struct predicate p; + es->call_stmt_size = lto_input_uleb128 (ib); es->call_stmt_time = lto_input_uleb128 (ib); es->loop_depth = lto_input_uleb128 (ib); + p = read_predicate (ib); + edge_set_predicate (e, &p); } *************** inline_read_section (struct lto_file_dec *** 1675,1691 **** for (j = 0; j < count2; j++) { struct size_time_entry e; - clause_t clause; - int k = 0; e.size = lto_input_uleb128 (&ib); e.time = lto_input_uleb128 (&ib); ! do ! { ! clause = e.predicate.clause[k++] = lto_input_uleb128 (&ib); ! gcc_assert (k < MAX_CLAUSES); ! } ! while (clause); VEC_safe_push (size_time_entry, gc, info->entry, &e); } --- 1862,1871 ---- for (j = 0; j < count2; j++) { struct size_time_entry e; e.size = lto_input_uleb128 (&ib); e.time = lto_input_uleb128 (&ib); ! e.predicate = read_predicate (&ib); VEC_safe_push (size_time_entry, gc, info->entry, &e); } *************** inline_read_summary (void) *** 1736,1741 **** --- 1916,1939 ---- cgraph_add_function_insertion_hook (&add_new_function, NULL); } + + /* Write predicate P to OB. */ + + static void + write_predicate (struct output_block *ob, struct predicate *p) + { + int j; + if (p) + for (j = 0; p->clause[j]; j++) + { + gcc_assert (j < MAX_CLAUSES); + lto_output_uleb128_stream (ob->main_stream, + p->clause[j]); + } + lto_output_uleb128_stream (ob->main_stream, 0); + } + + /* Write inline summary for edge E to OB. */ static void *************** write_inline_edge_summary (struct output *** 1745,1750 **** --- 1943,1949 ---- lto_output_uleb128_stream (ob->main_stream, es->call_stmt_size); lto_output_uleb128_stream (ob->main_stream, es->call_stmt_time); lto_output_uleb128_stream (ob->main_stream, es->loop_depth); + write_predicate (ob, es->predicate); } *************** inline_write_summary (cgraph_node_set se *** 1808,1825 **** VEC_iterate (size_time_entry, info->entry, i, e); i++) { - int j; lto_output_uleb128_stream (ob->main_stream, e->size); lto_output_uleb128_stream (ob->main_stream, e->time); ! for (j = 0; e->predicate.clause[j]; j++) ! { ! gcc_assert (j < MAX_CLAUSES); ! lto_output_uleb128_stream (ob->main_stream, ! e->predicate.clause[j]); ! } ! lto_output_uleb128_stream (ob->main_stream, 0); } for (edge = node->callees; edge; edge = edge->next_callee) write_inline_edge_summary (ob, edge); --- 2007,2017 ---- VEC_iterate (size_time_entry, info->entry, i, e); i++) { lto_output_uleb128_stream (ob->main_stream, e->size); lto_output_uleb128_stream (ob->main_stream, e->time); ! write_predicate (ob, &e->predicate); } for (edge = node->callees; edge; edge = edge->next_callee) write_inline_edge_summary (ob, edge); *************** inline_free_summary (void) *** 1856,1859 **** --- 2048,2056 ---- node_duplication_hook_holder = NULL; VEC_free (inline_summary_t, gc, inline_summary_vec); inline_summary_vec = NULL; + VEC_free (inline_edge_summary_t, heap, inline_edge_summary_vec); + inline_edge_summary_vec = NULL; + if (edge_predicate_pool) + free_alloc_pool (edge_predicate_pool); + edge_predicate_pool = 0; }