diff options
author | Jan Hubicka <jh@suse.cz> | 2012-11-11 19:14:35 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2012-11-11 18:14:35 +0000 |
commit | 52843a4726629c92066668cf79979676560efce6 (patch) | |
tree | 5c72b6d621b40aab51257d773d939ff6d2be4567 /gcc | |
parent | 6e7e4ca2e8a83335929695eca491c587ae1fcc56 (diff) | |
download | gcc-52843a4726629c92066668cf79979676560efce6.zip gcc-52843a4726629c92066668cf79979676560efce6.tar.gz gcc-52843a4726629c92066668cf79979676560efce6.tar.bz2 |
re PR fortran/48636 (Enable more inlining with -O2 and higher)
PR middle-end/48636
* ipa-inline.c (want_inline_small_function_p): Take aray index hint.
(edge_badness): Likewise.
* ipa-inline.h (inline_hints_vals): Add array_index and comments.
(inline_summary_: Add ARRAY_INDEX.
* ipa-inline-analysis.c (dump_inline_hints): Dump array_index hint.
(reset_inline_summary): Handle array_index hint.
(inline_node_duplication_hook): Likewise.
(dump_inline_summary): Likewise.
(array_index_predicate): New function.
(estimate_function_body_sizes): Use it.
(estimate_node_size_and_time): Use array_index hint.
(inline_merge_summary, inline_read_section): Likewise.
From-SVN: r193406
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/ipa-inline-analysis.c | 116 | ||||
-rw-r--r-- | gcc/ipa-inline.c | 3 | ||||
-rw-r--r-- | gcc/ipa-inline.h | 24 |
4 files changed, 141 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5a96bdd..535c0ef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2012-11-10 Jan Hubicka <jh@suse.cz> + + PR middle-end/48636 + * ipa-inline.c (want_inline_small_function_p): Take aray index hint. + (edge_badness): Likewise. + * ipa-inline.h (inline_hints_vals): Add array_index and comments. + (inline_summary_: Add ARRAY_INDEX. + * ipa-inline-analysis.c (dump_inline_hints): Dump array_index hint. + (reset_inline_summary): Handle array_index hint. + (inline_node_duplication_hook): Likewise. + (dump_inline_summary): Likewise. + (array_index_predicate): New function. + (estimate_function_body_sizes): Use it. + (estimate_node_size_and_time): Use array_index hint. + (inline_merge_summary, inline_read_section): Likewise. + 2012-11-10 Sandra Loosemore <sandra@codesourcery.com> * doc/extend.texi: Copy-edit to use "bit-field" consistently diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index 75dc308..f7b3af1 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -659,6 +659,11 @@ dump_inline_hints (FILE *f, inline_hints hints) hints &= ~INLINE_HINT_declared_inline; fprintf (f, " declared_inline"); } + if (hints & INLINE_HINT_array_index) + { + hints &= ~INLINE_HINT_array_index; + fprintf (f, " array_index"); + } gcc_assert (!hints); } @@ -1007,6 +1012,11 @@ reset_inline_summary (struct cgraph_node *node) pool_free (edge_predicate_pool, info->loop_stride); info->loop_stride = NULL; } + if (info->array_index) + { + pool_free (edge_predicate_pool, info->array_index); + info->array_index = NULL; + } VEC_free (condition, gc, info->conds); VEC_free (size_time_entry,gc, info->entry); for (e = node->callees; e; e = e->next_callee) @@ -1201,6 +1211,9 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst, remap_hint_predicate_after_duplication (&info->loop_stride, possible_truths, info); + remap_hint_predicate_after_duplication (&info->array_index, + possible_truths, + info); /* If inliner or someone after inliner will ever start producing non-trivial clones, we will get trouble with lack of information @@ -1224,6 +1237,12 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst, info->loop_stride = NULL; set_hint_predicate (&info->loop_stride, p); } + if (info->array_index) + { + predicate p = *info->array_index; + info->array_index = NULL; + set_hint_predicate (&info->array_index, p); + } } inline_update_overall_summary (dst); } @@ -1413,6 +1432,11 @@ dump_inline_summary (FILE * f, struct cgraph_node *node) fprintf (f, " loop stride:"); dump_predicate (f, s->conds, s->loop_stride); } + if (s->array_index) + { + fprintf (f, " array index:"); + dump_predicate (f, s->conds, s->array_index); + } fprintf (f, " calls:\n"); dump_inline_edge_summary (f, 4, node, s); fprintf (f, "\n"); @@ -2262,6 +2286,28 @@ predicate_for_phi_result (struct inline_summary *summary, gimple phi, SSA_NAME_VERSION (gimple_phi_result (phi)), *p); } +/* Return predicate specifying when array index in access OP becomes non-constant. */ + +static struct predicate +array_index_predicate (struct inline_summary *info, + VEC (predicate_t, heap) *nonconstant_names, tree op) +{ + struct predicate p = false_predicate (); + while (handled_component_p (op)) + { + if (TREE_CODE (op) == ARRAY_REF + || TREE_CODE (op) == ARRAY_RANGE_REF) + { + if (TREE_CODE (TREE_OPERAND (op, 1)) == SSA_NAME) + p = or_predicates (info->conds, &p, + &VEC_index (predicate_t, nonconstant_names, + SSA_NAME_VERSION (TREE_OPERAND (op, 1)))); + } + op = TREE_OPERAND (op, 0); + } + return p; +} + /* Compute function body size parameters for NODE. When EARLY is true, we compute only simple summaries without non-trivial predicates to drive the early inliner. */ @@ -2284,6 +2330,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) VEC (predicate_t, heap) *nonconstant_names = NULL; int nblocks, n; int *order; + predicate array_index = true_predicate (); info->conds = 0; info->entry = 0; @@ -2380,6 +2427,24 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) ((double)freq)/CGRAPH_FREQ_BASE, this_size, this_time); } + if (gimple_assign_load_p (stmt) && nonconstant_names) + { + struct predicate this_array_index; + this_array_index = array_index_predicate (info, nonconstant_names, + gimple_assign_rhs1 (stmt)); + if (!false_predicate_p (&this_array_index)) + array_index = and_predicates (info->conds, &array_index, &this_array_index); + } + if (gimple_store_p (stmt) && nonconstant_names) + { + struct predicate this_array_index; + this_array_index = array_index_predicate (info, nonconstant_names, + gimple_get_lhs (stmt)); + if (!false_predicate_p (&this_array_index)) + array_index = and_predicates (info->conds, &array_index, &this_array_index); + } + + if (is_gimple_call (stmt)) { struct cgraph_edge *edge = cgraph_edge (node, stmt); @@ -2476,21 +2541,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) } } } - FOR_ALL_BB_FN (bb, my_function) - { - edge e; - edge_iterator ei; - - if (bb->aux) - pool_free (edge_predicate_pool, bb->aux); - bb->aux = NULL; - FOR_EACH_EDGE (e, ei, bb->succs) - { - if (e->aux) - pool_free (edge_predicate_pool, e->aux); - e->aux = NULL; - } - } + set_hint_predicate (&inline_summary (node)->array_index, array_index); time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE; if (time > MAX_TIME) time = MAX_TIME; @@ -2513,6 +2564,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) unsigned int j, i; struct tree_niter_desc niter_desc; basic_block *body = get_loop_body (loop); + bb_predicate = *(struct predicate *)loop->header->aux; exits = get_loop_exit_edges (loop); FOR_EACH_VEC_ELT (edge, exits, j, ex) @@ -2522,6 +2574,10 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) predicate will_be_nonconstant = will_be_nonconstant_expr_predicate (parms_info, info, niter_desc.niter, nonconstant_names); + if (!true_predicate_p (&will_be_nonconstant)) + will_be_nonconstant = and_predicates (info->conds, + &bb_predicate, + &will_be_nonconstant); if (!true_predicate_p (&will_be_nonconstant) && !false_predicate_p (&will_be_nonconstant)) /* This is slightly inprecise. We may want to represent each loop with @@ -2533,6 +2589,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) for (i = 0; i < loop->num_nodes; i++) { gimple_stmt_iterator gsi; + bb_predicate = *(struct predicate *)body[i]->aux; for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); @@ -2550,6 +2607,10 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) will_be_nonconstant = will_be_nonconstant_expr_predicate (parms_info, info, iv.step, nonconstant_names); + if (!true_predicate_p (&will_be_nonconstant)) + will_be_nonconstant = and_predicates (info->conds, + &bb_predicate, + &will_be_nonconstant); if (!true_predicate_p (&will_be_nonconstant) && !false_predicate_p (&will_be_nonconstant)) /* This is slightly inprecise. We may want to represent each loop with @@ -2564,6 +2625,21 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) set_hint_predicate (&inline_summary (node)->loop_stride, loop_stride); scev_finalize (); } + FOR_ALL_BB_FN (bb, my_function) + { + edge e; + edge_iterator ei; + + if (bb->aux) + pool_free (edge_predicate_pool, bb->aux); + bb->aux = NULL; + FOR_EACH_EDGE (e, ei, bb->succs) + { + if (e->aux) + pool_free (edge_predicate_pool, e->aux); + e->aux = NULL; + } + } inline_summary (node)->self_time = time; inline_summary (node)->self_size = size; VEC_free (predicate_t, heap, nonconstant_names); @@ -2881,6 +2957,9 @@ estimate_node_size_and_time (struct cgraph_node *node, if (info->loop_stride && !evaluate_predicate (info->loop_stride, possible_truths)) hints |=INLINE_HINT_loop_stride; + if (info->array_index + && !evaluate_predicate (info->array_index, possible_truths)) + hints |=INLINE_HINT_array_index; if (info->scc_no) hints |= INLINE_HINT_in_scc; if (DECL_DECLARED_INLINE_P (node->symbol.decl)) @@ -3311,6 +3390,10 @@ inline_merge_summary (struct cgraph_edge *edge) &callee_info->loop_stride, operand_map, offset_map, clause, &toplev_predicate); + remap_hint_predicate (info, callee_info, + &callee_info->array_index, + operand_map, offset_map, + clause, &toplev_predicate); inline_update_callee_summaries (edge->callee, inline_edge_summary (edge)->loop_depth); @@ -3803,6 +3886,8 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data, set_hint_predicate (&info->loop_iterations, p); p = read_predicate (&ib); set_hint_predicate (&info->loop_stride, p); + p = read_predicate (&ib); + set_hint_predicate (&info->array_index, p); for (e = node->callees; e; e = e->next_callee) read_inline_edge_summary (&ib, e); for (e = node->indirect_calls; e; e = e->next_callee) @@ -3954,6 +4039,7 @@ inline_write_summary (void) } write_predicate (ob, info->loop_iterations); write_predicate (ob, info->loop_stride); + write_predicate (ob, info->array_index); for (edge = node->callees; edge; edge = edge->next_callee) write_inline_edge_summary (ob, edge); for (edge = node->indirect_calls; edge; edge = edge->next_callee) diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index fa3d456..9f792ff 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -541,6 +541,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) && !big_speedup && !(hints & (INLINE_HINT_indirect_call | INLINE_HINT_loop_iterations + | INLINE_HINT_array_index | INLINE_HINT_loop_stride))) { e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; @@ -595,6 +596,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) && !big_speedup && growth >= ((hints & (INLINE_HINT_indirect_call | INLINE_HINT_loop_iterations + | INLINE_HINT_array_index | INLINE_HINT_loop_stride)) ? MAX (MAX_INLINE_INSNS_AUTO, MAX_INLINE_INSNS_SINGLE) @@ -919,6 +921,7 @@ edge_badness (struct cgraph_edge *edge, bool dump) gcc_checking_assert (badness <=0 && badness >= INT_MIN / 16); if ((hints & (INLINE_HINT_indirect_call | INLINE_HINT_loop_iterations + | INLINE_HINT_array_index | INLINE_HINT_loop_stride)) || callee_info->growth <= 0) badness *= 8; diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h index 4791bf0..1e9658c 100644 --- a/gcc/ipa-inline.h +++ b/gcc/ipa-inline.h @@ -44,16 +44,32 @@ typedef struct GTY(()) condition 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. */ +/* 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 { + /* When inlining turns indirect call into a direct call, + it is good idea to do so. */ INLINE_HINT_indirect_call = 1, + /* Inlining may make loop iterations or loop stride known. It is good idea + to do so because it enables loop optimizatoins. */ INLINE_HINT_loop_iterations = 2, INLINE_HINT_loop_stride = 4, + /* Inlining withing same strongly connected component of callgraph is often + a loss due to increased stack frame usage and prologue setup costs. */ INLINE_HINT_same_scc = 8, + /* Inlining functions in strongly connected component is not such a great + win. */ INLINE_HINT_in_scc = 16, + /* If function is declared inline by user, it may be good idea to inline + it. */ INLINE_HINT_declared_inline = 32, - INLINE_HINT_cross_module = 64 + /* Programs are usually still organized for non-LTO compilation and thus + if functions are in different modules, inlining may not be so important. + */ + INLINE_HINT_cross_module = 64, + /* If array indexes of loads/stores become known there may be room for + futher optimization. */ + INLINE_HINT_array_index = 128 }; typedef int inline_hints; @@ -133,6 +149,8 @@ struct GTY(()) inline_summary /* Predicate on when some loop in the function becomes to have known stride. */ struct predicate * GTY((skip)) loop_stride; + /* Predicate on when some array indexes become constants. */ + struct predicate * GTY((skip)) array_index; /* Estimated growth for inlining all copies of the function before start of small functions inlining. This value will get out of date as the callers are duplicated, but |