X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fipa-inline.c;h=e9ba04b371c380226d2c1ab84371ffc94b791d9b;hp=38a9c56b282f528345f1e7c53958e30efad2eedb;hb=639d107391b49d38cbc87a869b2aabca014095e9;hpb=c864294a4604fbd40f31f7932a78754af8c25e25 diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 38a9c56b282..e9ba04b371c 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -128,7 +128,6 @@ along with GCC; see the file COPYING3. If not see #include "flags.h" #include "cgraph.h" #include "diagnostic.h" -#include "gimple-pretty-print.h" #include "timevar.h" #include "params.h" #include "fibheap.h" @@ -269,8 +268,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, else { struct cgraph_node *n; - n = cgraph_clone_node (e->callee, e->callee->decl, - e->count, e->frequency, e->loop_nest, + n = cgraph_clone_node (e->callee, e->count, e->frequency, e->loop_nest, update_original, NULL); cgraph_redirect_edge_callee (e, n); } @@ -287,7 +285,6 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, + inline_summary (e->callee)->estimated_self_stack_size; if (e->callee->global.inlined_to->global.estimated_stack_size < peak) e->callee->global.inlined_to->global.estimated_stack_size = peak; - cgraph_propagate_frequency (e->callee); /* Recursively clone all bodies. */ for (e = e->callee->callees; e; e = e->next_callee) @@ -309,11 +306,20 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original, struct cgraph_node *to = NULL, *what; struct cgraph_edge *curr = e; int freq; + bool duplicate = false; + int orig_size = e->callee->global.size; gcc_assert (e->inline_failed); e->inline_failed = CIF_OK; - DECL_POSSIBLY_INLINED (e->callee->decl) = true; + if (!e->callee->global.inlined) + DECL_POSSIBLY_INLINED (e->callee->decl) = true; + e->callee->global.inlined = true; + + if (e->callee->callers->next_caller + || !cgraph_can_remove_if_no_direct_calls_p (e->callee) + || e->callee->same_comdat_group) + duplicate = true; cgraph_clone_inlined_nodes (e, true, update_original); what = e->callee; @@ -331,6 +337,8 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original, gcc_assert (what->global.inlined_to == to); if (new_size > old_size) overall_size += new_size - old_size; + if (!duplicate) + overall_size -= orig_size; ncalls_inlined++; if (flag_indirect_inlining) @@ -536,57 +544,23 @@ cgraph_recursive_inlining_p (struct cgraph_node *to, of the function or function body size. */ static int -cgraph_edge_badness (struct cgraph_edge *edge, bool dump) +cgraph_edge_badness (struct cgraph_edge *edge) { gcov_type badness; int growth = - (cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee) - - edge->caller->global.size); + cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee); - if (edge->callee->local.disregard_inline_limits) - return INT_MIN; - - if (dump) - { - fprintf (dump_file, " Badness calculcation for %s -> %s\n", - cgraph_node_name (edge->caller), - cgraph_node_name (edge->callee)); - fprintf (dump_file, " growth %i, time %i-%i, size %i-%i\n", - growth, - edge->callee->global.time, - inline_summary (edge->callee)->time_inlining_benefit, - edge->callee->global.size, - inline_summary (edge->callee)->size_inlining_benefit); - } + growth -= edge->caller->global.size; /* Always prefer inlining saving code size. */ if (growth <= 0) - { - badness = INT_MIN - growth; - if (dump) - fprintf (dump_file, " %i: Growth %i < 0\n", (int) badness, - growth); - } + badness = INT_MIN - growth; /* When profiling is available, base priorities -(#calls / growth). So we optimize for overall number of "executed" inlined calls. */ else if (max_count) - { - badness = - ((int) - ((double) edge->count * INT_MIN / max_count / (max_benefit + 1)) * - (inline_summary (edge->callee)->time_inlining_benefit + 1)) / growth; - if (dump) - { - fprintf (dump_file, - " %i (relative %f): profile info. Relative count %f" - " * Relative benefit %f\n", - (int) badness, (double) badness / INT_MIN, - (double) edge->count / max_count, - (double) (inline_summary (edge->callee)-> - time_inlining_benefit + 1) / (max_benefit + 1)); - } - } + badness = ((int)((double)edge->count * INT_MIN / max_count / (max_benefit + 1)) + * (inline_summary (edge->callee)->time_inlining_benefit + 1)) / growth; /* When function local profile is available, base priorities on growth / frequency, so we optimize for overall frequency of inlined @@ -600,13 +574,9 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump) else if (flag_guess_branch_prob) { int div = edge->frequency * 100 / CGRAPH_FREQ_BASE + 1; - int benefitperc; - int growth_for_all; badness = growth * 10000; - benefitperc = - MIN (100 * inline_summary (edge->callee)->time_inlining_benefit / - (edge->callee->global.time + 1) +1, 100); - div *= benefitperc; + div *= MIN (100 * inline_summary (edge->callee)->time_inlining_benefit + / (edge->callee->global.time + 1) + 1, 100); /* Decrease badness if call is nested. */ @@ -617,17 +587,9 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump) div = 1; if (badness > 0) badness /= div; - growth_for_all = cgraph_estimate_growth (edge->callee); - badness += growth_for_all; + badness += cgraph_estimate_growth (edge->callee); if (badness > INT_MAX) - badness = INT_MAX; - if (dump) - { - fprintf (dump_file, - " %i: guessed profile. frequency %i, overall growth %i," - " benefit %i%%, divisor %i\n", - (int) badness, edge->frequency, growth_for_all, benefitperc, div); - } + badness = INT_MAX; } /* When function local profile is not available or it does not give useful information (ie frequency is zero), base the cost on @@ -642,17 +604,10 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump) if (badness > 0) badness >>= nest; else - { + { badness <<= nest; - } - if (dump) - fprintf (dump_file, " %i: no profile. nest %i\n", (int) badness, - nest); + } } - - /* Ensure that we did not overflow in all the fixed point math above. */ - gcc_assert (badness >= INT_MIN); - gcc_assert (badness <= INT_MAX - 1); /* Make recursive inlining happen always after other inlining is done. */ if (cgraph_recursive_inlining_p (edge->caller, edge->callee, NULL)) return badness + 1; @@ -669,7 +624,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node, struct cgraph_edge *edge; cgraph_inline_failed_t failed_reason; - if (!node->local.inlinable + if (!node->local.inlinable || node->local.disregard_inline_limits || node->global.inlined_to) return; if (bitmap_bit_p (updated_nodes, node->uid)) @@ -696,7 +651,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node, for (edge = node->callers; edge; edge = edge->next_caller) if (edge->inline_failed) { - int badness = cgraph_edge_badness (edge, false); + int badness = cgraph_edge_badness (edge); if (edge->aux) { fibnode_t n = (fibnode_t) edge->aux; @@ -705,12 +660,8 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node, continue; /* fibheap_replace_key only increase the keys. */ - if (badness < n->key) - { - fibheap_replace_key (heap, n, badness); - gcc_assert (n->key == badness); - continue; - } + if (fibheap_replace_key (heap, n, badness)) + continue; fibheap_delete_node (heap, (fibnode_t) edge->aux); } edge->aux = fibheap_insert (heap, badness, edge); @@ -810,8 +761,7 @@ cgraph_decide_recursive_inlining (struct cgraph_node *node, cgraph_node_name (node)); /* We need original clone to copy around. */ - master_clone = cgraph_clone_node (node, node->decl, - node->count, CGRAPH_FREQ_BASE, 1, + master_clone = cgraph_clone_node (node, node->count, CGRAPH_FREQ_BASE, 1, false, NULL); master_clone->needed = true; for (e = master_clone->callees; e; e = e->next_callee) @@ -939,7 +889,7 @@ add_new_edges_to_heap (fibheap_t heap, VEC (cgraph_edge_p, heap) *new_edges) struct cgraph_edge *edge = VEC_pop (cgraph_edge_p, new_edges); gcc_assert (!edge->aux); - edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge); + edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge), edge); } } @@ -988,7 +938,7 @@ cgraph_decide_inlining_of_small_functions (void) if (edge->inline_failed) { gcc_assert (!edge->aux); - edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge); + edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge), edge); } } @@ -996,26 +946,15 @@ cgraph_decide_inlining_of_small_functions (void) min_size = overall_size; while (overall_size <= max_size - && !fibheap_empty (heap)) + && (edge = (struct cgraph_edge *) fibheap_extract_min (heap))) { int old_size = overall_size; - struct cgraph_node *where, *callee; - int badness = fibheap_min_key (heap); - int growth; + struct cgraph_node *where; + int growth = + cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee); cgraph_inline_failed_t not_good = CIF_OK; - edge = (struct cgraph_edge *) fibheap_extract_min (heap); - gcc_assert (edge->aux); - edge->aux = NULL; - if (!edge->inline_failed) - continue; -#ifdef ENABLE_CHECKING - gcc_assert (cgraph_edge_badness (edge, false) == badness); -#endif - callee = edge->callee; - - growth = (cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee) - - edge->caller->global.size); + growth -= edge->caller->global.size; if (dump_file) { @@ -1028,17 +967,18 @@ cgraph_decide_inlining_of_small_functions (void) " Estimated growth after inlined into all callees is %+i insns.\n" " Estimated badness is %i, frequency %.2f.\n", cgraph_node_name (edge->caller), - flag_wpa ? "unknown" - : gimple_filename ((const_gimple) edge->call_stmt), - flag_wpa ? -1 : gimple_lineno ((const_gimple) edge->call_stmt), + gimple_filename ((const_gimple) edge->call_stmt), + gimple_lineno ((const_gimple) edge->call_stmt), cgraph_estimate_growth (edge->callee), - badness, + cgraph_edge_badness (edge), edge->frequency / (double)CGRAPH_FREQ_BASE); if (edge->count) fprintf (dump_file," Called "HOST_WIDEST_INT_PRINT_DEC"x\n", edge->count); - if (dump_flags & TDF_DETAILS) - cgraph_edge_badness (edge, true); } + gcc_assert (edge->aux); + edge->aux = NULL; + if (!edge->inline_failed) + continue; /* When not having profile info ready we don't weight by any way the position of call in procedure itself. This means if call of @@ -1074,14 +1014,12 @@ cgraph_decide_inlining_of_small_functions (void) } } - if (edge->callee->local.disregard_inline_limits) - ; - else if (!cgraph_maybe_hot_edge_p (edge)) + if (!cgraph_maybe_hot_edge_p (edge)) not_good = CIF_UNLIKELY_CALL; - else if (!flag_inline_functions + if (!flag_inline_functions && !DECL_DECLARED_INLINE_P (edge->callee->decl)) not_good = CIF_NOT_DECLARED_INLINED; - else if (optimize_function_for_size_p (DECL_STRUCT_FUNCTION(edge->caller->decl))) + if (optimize_function_for_size_p (DECL_STRUCT_FUNCTION(edge->caller->decl))) not_good = CIF_OPTIMIZING_FOR_SIZE; if (not_good && growth > 0 && cgraph_estimate_growth (edge->callee) > 0) { @@ -1158,11 +1096,6 @@ cgraph_decide_inlining_of_small_functions (void) called by function we inlined (since number of it inlinable callers might change). */ update_caller_keys (heap, where, updated_nodes); - - /* We removed one call of the function we just inlined. If offline - copy is still needed, be sure to update the keys. */ - if (callee != where && !callee->global.inlined_to) - update_caller_keys (heap, callee, updated_nodes); bitmap_clear (updated_nodes); if (dump_file) @@ -1184,40 +1117,10 @@ cgraph_decide_inlining_of_small_functions (void) fprintf (dump_file, "New minimal size reached: %i\n", min_size); } } - while (!fibheap_empty (heap)) + while ((edge = (struct cgraph_edge *) fibheap_extract_min (heap)) != NULL) { - int badness = fibheap_min_key (heap); - - edge = (struct cgraph_edge *) fibheap_extract_min (heap); gcc_assert (edge->aux); edge->aux = NULL; - if (!edge->inline_failed) - continue; -#ifdef ENABLE_CHECKING - gcc_assert (cgraph_edge_badness (edge, false) == badness); -#endif - if (dump_file) - { - fprintf (dump_file, - "\nSkipping %s with %i size\n", - cgraph_node_name (edge->callee), - edge->callee->global.size); - fprintf (dump_file, - " called by %s in %s:%i\n" - " Estimated growth after inlined into all callees is %+i insns.\n" - " Estimated badness is %i, frequency %.2f.\n", - cgraph_node_name (edge->caller), - flag_wpa ? "unknown" - : gimple_filename ((const_gimple) edge->call_stmt), - flag_wpa ? -1 : gimple_lineno ((const_gimple) edge->call_stmt), - cgraph_estimate_growth (edge->callee), - badness, - edge->frequency / (double)CGRAPH_FREQ_BASE); - if (edge->count) - fprintf (dump_file," Called "HOST_WIDEST_INT_PRINT_DEC"x\n", edge->count); - if (dump_flags & TDF_DETAILS) - cgraph_edge_badness (edge, true); - } if (!edge->callee->local.disregard_inline_limits && edge->inline_failed && !cgraph_recursive_inlining_p (edge->caller, edge->callee, &edge->inline_failed)) @@ -1327,8 +1230,6 @@ cgraph_decide_inlining (void) cgraph_remove_function_insertion_hook (function_insertion_hook_holder); if (in_lto_p && flag_indirect_inlining) ipa_update_after_lto_read (); - if (flag_indirect_inlining) - ipa_create_all_structures_for_iinln (); max_count = 0; max_benefit = 0; @@ -1426,14 +1327,13 @@ cgraph_decide_inlining (void) if (cgraph_check_inline_limits (node->callers->caller, node, &reason, false)) { - struct cgraph_node *caller = node->callers->caller; cgraph_mark_inline (node->callers); if (dump_file) fprintf (dump_file, " Inlined into %s which now has %i size" " for a net change of %+i size.\n", - cgraph_node_name (caller), - caller->global.size, + cgraph_node_name (node->callers->caller), + node->callers->caller->global.size, overall_size - old_size); } else @@ -1449,7 +1349,7 @@ cgraph_decide_inlining (void) /* Free ipa-prop structures if they are no longer needed. */ if (flag_indirect_inlining) - ipa_free_all_structures_after_iinln (); + free_all_ipa_structures_after_iinln (); if (dump_file) fprintf (dump_file, @@ -1678,17 +1578,6 @@ cgraph_early_inlining (void) } else { - if (lookup_attribute ("flatten", - DECL_ATTRIBUTES (node->decl)) != NULL) - { - if (dump_file) - fprintf (dump_file, - "Flattening %s\n", cgraph_node_name (node)); - cgraph_flatten (node); - timevar_push (TV_INTEGRATION); - todo |= optimize_inline_calls (current_function_decl); - timevar_pop (TV_INTEGRATION); - } /* We iterate incremental inlining to get trivial cases of indirect inlining. */ while (iterations < PARAM_VALUE (PARAM_EARLY_INLINER_MAX_ITERATIONS) @@ -1841,6 +1730,14 @@ estimate_function_body_sizes (struct cgraph_node *node) int freq; tree funtype = TREE_TYPE (node->decl); + if (node->local.disregard_inline_limits) + { + inline_summary (node)->self_time = 0; + inline_summary (node)->self_size = 0; + inline_summary (node)->time_inlining_benefit = 0; + inline_summary (node)->size_inlining_benefit = 0; + } + if (dump_file) fprintf (dump_file, "Analyzing function body size: %s\n", cgraph_node_name (node)); @@ -1972,10 +1869,21 @@ struct gimple_opt_pass pass_inline_parameters = static void inline_indirect_intraprocedural_analysis (struct cgraph_node *node) { - ipa_initialize_node_params (node); - ipa_detect_param_modifications (node); + struct cgraph_edge *cs; + + if (!flag_ipa_cp) + { + ipa_initialize_node_params (node); + ipa_detect_param_modifications (node); + } ipa_analyze_params_uses (node); - ipa_compute_jump_functions (node); + + if (!flag_ipa_cp) + for (cs = node->callees; cs; cs = cs->next_callee) + { + ipa_count_arguments (cs); + ipa_compute_jump_functions (cs); + } if (dump_file) { @@ -2083,8 +1991,7 @@ inline_read_summary (void) active, we don't need to write them twice. */ static void -inline_write_summary (cgraph_node_set set, - varpool_node_set vset ATTRIBUTE_UNUSED) +inline_write_summary (cgraph_node_set set) { if (flag_indirect_inlining && !flag_ipa_cp) ipa_prop_write_jump_functions (set); @@ -2120,14 +2027,13 @@ struct ipa_opt_pass_d pass_ipa_inline = 0, /* properties_destroyed */ TODO_remove_functions, /* todo_flags_finish */ TODO_dump_cgraph | TODO_dump_func - | TODO_remove_functions | TODO_ggc_collect /* todo_flags_finish */ + | TODO_remove_functions /* todo_flags_finish */ }, inline_generate_summary, /* generate_summary */ inline_write_summary, /* write_summary */ inline_read_summary, /* read_summary */ - NULL, /* write_optimization_summary */ - NULL, /* read_optimization_summary */ - NULL, /* stmt_fixup */ + NULL, /* function_read_summary */ + lto_ipa_fixup_call_notes, /* stmt_fixup */ 0, /* TODOs */ inline_transform, /* function_transform */ NULL, /* variable_transform */