From 56851c03c313144953a69e730fef5e7b933fee09 Mon Sep 17 00:00:00 2001 From: hubicka Date: Mon, 26 Apr 2010 13:33:24 +0000 Subject: [PATCH] * cgraph.c (cgraph_create_node): Set node frequency to normal. (cgraph_clone_node): Copy function frequency. * cgraph.h (node_frequency): New enum (struct cgraph_node): Add. * final.c (rest_of_clean_state): Update. * lto-cgraph.c (lto_output_node): Output node frequency. (input_overwrite_node): Input node frequency. * tre-ssa-loop-ivopts (computation_cost): Update. * lto-streamer-out.c (output_function): Do not output function frequency. * predict.c (maybe_hot_frequency_p): Update and handle functions executed once. (cgraph_maybe_hot_edge_p): Likewise; use cgraph frequency instead of attribute lookup. (probably_never_executed_bb_p, optimize_function_for_size_p): Update. (compute_function_frequency): Set noreturn functions to be executed once. (choose_function_section): Update. * lto-streamer-in.c (input_function): Do not input function frequency. * function.c (allocate_struct_function): Do not initialize function frequency. * function.h (function_frequency): Remove. (struct function): Remove function frequency. * ipa-profile.c (CGRAPH_NODE_FREQUENCY): Remove. (try_update): Update. * tree-inline.c (initialize_cfun): Do not update function frequency. * passes.c (pass_init_dump_file): Update. * i386.c (ix86_compute_frame_layout): Update. (ix86_pad_returns): Update. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158732 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 28 +++ gcc/cgraph.c | 467 ++++++++++--------------------------------------- gcc/cgraph.h | 18 ++ gcc/config/i386/i386.c | 7 +- gcc/lto-cgraph.c | 2 + gcc/passes.c | 7 +- 6 files changed, 154 insertions(+), 375 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 15e61556d70..7a86f3c1b68 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +2010-04-26 Jan Hubicka + + * cgraph.c (cgraph_create_node): Set node frequency to normal. + (cgraph_clone_node): Copy function frequency. + * cgraph.h (node_frequency): New enum + (struct cgraph_node): Add. + * final.c (rest_of_clean_state): Update. + * lto-cgraph.c (lto_output_node): Output node frequency. + (input_overwrite_node): Input node frequency. + * tre-ssa-loop-ivopts (computation_cost): Update. + * lto-streamer-out.c (output_function): Do not output function frequency. + * predict.c (maybe_hot_frequency_p): Update and handle functions executed once. + (cgraph_maybe_hot_edge_p): Likewise; use cgraph frequency instead of + attribute lookup. + (probably_never_executed_bb_p, optimize_function_for_size_p): Update. + (compute_function_frequency): Set noreturn functions to be executed once. + (choose_function_section): Update. + * lto-streamer-in.c (input_function): Do not input function frequency. + * function.c (allocate_struct_function): Do not initialize function frequency. + * function.h (function_frequency): Remove. + (struct function): Remove function frequency. + * ipa-profile.c (CGRAPH_NODE_FREQUENCY): Remove. + (try_update): Update. + * tree-inline.c (initialize_cfun): Do not update function frequency. + * passes.c (pass_init_dump_file): Update. + * i386.c (ix86_compute_frame_layout): Update. + (ix86_pad_returns): Update. + 2010-04-26 Jie Zhang PR tree-optimization/43833 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 9433301cf77..b58d4ee5516 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -34,16 +34,10 @@ The callgraph: based on DECL_UID. The call-graph nodes are created lazily using cgraph_node function when called for unknown declaration. - The callgraph at the moment does not represent all indirect calls or calls - from other compilation units. Flag NEEDED is set for each node that may be - accessed in such an invisible way and it shall be considered an entry point - to the callgraph. - - On the other hand, the callgraph currently does contain some edges for - indirect calls with unknown callees which can be accessed through - indirect_calls field of a node. It should be noted however that at the - moment only calls which are potential candidates for indirect inlining are - added there. + The callgraph at the moment does not represent indirect calls or calls + from other compilation unit. Flag NEEDED is set for each node that may + be accessed in such an invisible way and it shall be considered an + entry point to the callgraph. Interprocedural information: @@ -54,9 +48,6 @@ The callgraph: rtl_info used by RTL backend to propagate data from already compiled functions to their callers. - Moreover, each node has a uid which can be used to keep information in - on-the-side arrays. UIDs are reused and therefore reasonably dense. - Inlining plans: The function inlining information is decided in advance and maintained @@ -96,7 +87,6 @@ The callgraph: #include "except.h" #include "diagnostic.h" #include "rtl.h" -#include "ipa-utils.h" static void cgraph_node_remove_callers (struct cgraph_node *node); static inline void cgraph_edge_remove_caller (struct cgraph_edge *e); @@ -464,7 +454,6 @@ cgraph_create_node (void) node->previous = NULL; node->global.estimated_growth = INT_MIN; node->frequency = NODE_FREQUENCY_NORMAL; - ipa_empty_ref_list (&node->ref_list); cgraph_nodes = node; cgraph_n_nodes++; return node; @@ -734,19 +723,6 @@ edge_eq (const void *x, const void *y) return ((const struct cgraph_edge *) x)->call_stmt == y; } -/* Add call graph edge E to call site hash of its caller. */ - -static inline void -cgraph_add_edge_to_call_site_hash (struct cgraph_edge *e) -{ - void **slot; - slot = htab_find_slot_with_hash (e->caller->call_site_hash, - e->call_stmt, - htab_hash_pointer (e->call_stmt), - INSERT); - gcc_assert (!*slot); - *slot = e; -} /* Return the callgraph edge representing the GIMPLE_CALL statement CALL_STMT. */ @@ -767,28 +743,26 @@ cgraph_edge (struct cgraph_node *node, gimple call_stmt) solution. It is not good idea to add pointer into CALL_EXPR itself because we want to make possible having multiple cgraph nodes representing different clones of the same body before the body is actually cloned. */ - for (e = node->callees; e; e = e->next_callee) + for (e = node->callees; e; e= e->next_callee) { if (e->call_stmt == call_stmt) break; n++; } - if (!e) - for (e = node->indirect_calls; e; e = e->next_callee) - { - if (e->call_stmt == call_stmt) - break; - n++; - } - if (n > 100) { node->call_site_hash = htab_create_ggc (120, edge_hash, edge_eq, NULL); for (e2 = node->callees; e2; e2 = e2->next_callee) - cgraph_add_edge_to_call_site_hash (e2); - for (e2 = node->indirect_calls; e2; e2 = e2->next_callee) - cgraph_add_edge_to_call_site_hash (e2); + { + void **slot; + slot = htab_find_slot_with_hash (node->call_site_hash, + e2->call_stmt, + htab_hash_pointer (e2->call_stmt), + INSERT); + gcc_assert (!*slot); + *slot = e2; + } } return e; @@ -800,31 +774,26 @@ cgraph_edge (struct cgraph_node *node, gimple call_stmt) void cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt) { - tree decl; - if (e->caller->call_site_hash) { htab_remove_elt_with_hash (e->caller->call_site_hash, e->call_stmt, htab_hash_pointer (e->call_stmt)); } - e->call_stmt = new_stmt; - if (e->indirect_unknown_callee - && (decl = gimple_call_fndecl (new_stmt))) - { - /* Constant propagation (and possibly also inlining?) can turn an - indirect call into a direct one. */ - struct cgraph_node *new_callee = cgraph_node (decl); - - cgraph_make_edge_direct (e, new_callee); - } - push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl)); e->can_throw_external = stmt_can_throw_external (new_stmt); pop_cfun (); if (e->caller->call_site_hash) - cgraph_add_edge_to_call_site_hash (e); + { + void **slot; + slot = htab_find_slot_with_hash (e->caller->call_site_hash, + e->call_stmt, + htab_hash_pointer + (e->call_stmt), INSERT); + gcc_assert (!*slot); + *slot = e; + } } /* Like cgraph_set_call_stmt but walk the clone tree and update all @@ -926,9 +895,7 @@ initialize_inline_failed (struct cgraph_edge *e) { struct cgraph_node *callee = e->callee; - if (e->indirect_unknown_callee) - e->inline_failed = CIF_INDIRECT_UNKNOWN_CALL; - else if (!callee->analyzed) + if (!callee->analyzed) e->inline_failed = CIF_BODY_NOT_AVAILABLE; else if (callee->local.redefined_extern_inline) e->inline_failed = CIF_REDEFINED_EXTERN_INLINE; @@ -940,16 +907,15 @@ initialize_inline_failed (struct cgraph_edge *e) e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED; } -/* Allocate a cgraph_edge structure and fill it with data according to the - parameters of which only CALLEE can be NULL (when creating an indirect call - edge). */ +/* Create edge from CALLER to CALLEE in the cgraph. */ -static struct cgraph_edge * -cgraph_create_edge_1 (struct cgraph_node *caller, struct cgraph_node *callee, - gimple call_stmt, gcov_type count, int freq, int nest) +struct cgraph_edge * +cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, + gimple call_stmt, gcov_type count, int freq, int nest) { struct cgraph_edge *edge; + /* LTO does not actually have access to the call_stmt since these have not been loaded yet. */ if (call_stmt) @@ -975,85 +941,47 @@ cgraph_create_edge_1 (struct cgraph_node *caller, struct cgraph_node *callee, } edge->aux = NULL; + edge->caller = caller; edge->callee = callee; - edge->prev_caller = NULL; - edge->next_caller = NULL; - edge->prev_callee = NULL; - edge->next_callee = NULL; - - edge->count = count; - gcc_assert (count >= 0); - edge->frequency = freq; - gcc_assert (freq >= 0); - gcc_assert (freq <= CGRAPH_FREQ_MAX); - edge->loop_nest = nest; - edge->call_stmt = call_stmt; push_cfun (DECL_STRUCT_FUNCTION (caller->decl)); edge->can_throw_external = call_stmt ? stmt_can_throw_external (call_stmt) : false; pop_cfun (); - edge->call_stmt_cannot_inline_p = - (call_stmt ? gimple_call_cannot_inline_p (call_stmt) : false); - if (call_stmt && caller->call_site_hash) - cgraph_add_edge_to_call_site_hash (edge); - - edge->indirect_info = NULL; - edge->indirect_inlining_edge = 0; - - return edge; -} - -/* Create edge from CALLER to CALLEE in the cgraph. */ - -struct cgraph_edge * -cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, - gimple call_stmt, gcov_type count, int freq, int nest) -{ - struct cgraph_edge *edge = cgraph_create_edge_1 (caller, callee, call_stmt, - count, freq, nest); - - edge->indirect_unknown_callee = 0; - initialize_inline_failed (edge); - + edge->prev_caller = NULL; edge->next_caller = callee->callers; if (callee->callers) callee->callers->prev_caller = edge; + edge->prev_callee = NULL; edge->next_callee = caller->callees; if (caller->callees) caller->callees->prev_callee = edge; caller->callees = edge; callee->callers = edge; + edge->count = count; + gcc_assert (count >= 0); + edge->frequency = freq; + gcc_assert (freq >= 0); + gcc_assert (freq <= CGRAPH_FREQ_MAX); + edge->loop_nest = nest; + edge->indirect_call = 0; + edge->call_stmt_cannot_inline_p = + (call_stmt ? gimple_call_cannot_inline_p (call_stmt) : false); + if (call_stmt && caller->call_site_hash) + { + void **slot; + slot = htab_find_slot_with_hash (caller->call_site_hash, + edge->call_stmt, + htab_hash_pointer + (edge->call_stmt), + INSERT); + gcc_assert (!*slot); + *slot = edge; + } - return edge; -} - - -/* Create an indirect edge with a yet-undetermined callee where the call - statement destination is a formal parameter of the caller with index - PARAM_INDEX. */ - -struct cgraph_edge * -cgraph_create_indirect_edge (struct cgraph_node *caller, gimple call_stmt, - int ecf_flags, - gcov_type count, int freq, int nest) -{ - struct cgraph_edge *edge = cgraph_create_edge_1 (caller, NULL, call_stmt, - count, freq, nest); - - edge->indirect_unknown_callee = 1; initialize_inline_failed (edge); - edge->indirect_info = GGC_CNEW (struct cgraph_indirect_call_info); - edge->indirect_info->param_index = -1; - edge->indirect_info->ecf_flags = ecf_flags; - - edge->next_callee = caller->indirect_calls; - if (caller->indirect_calls) - caller->indirect_calls->prev_callee = edge; - caller->indirect_calls = edge; - return edge; } @@ -1062,7 +990,6 @@ cgraph_create_indirect_edge (struct cgraph_node *caller, gimple call_stmt, static inline void cgraph_edge_remove_callee (struct cgraph_edge *e) { - gcc_assert (!e->indirect_unknown_callee); if (e->prev_caller) e->prev_caller->next_caller = e->next_caller; if (e->next_caller) @@ -1081,12 +1008,7 @@ cgraph_edge_remove_caller (struct cgraph_edge *e) if (e->next_callee) e->next_callee->prev_callee = e->prev_callee; if (!e->prev_callee) - { - if (e->indirect_unknown_callee) - e->caller->indirect_calls = e->next_callee; - else - e->caller->callees = e->next_callee; - } + e->caller->callees = e->next_callee; if (e->caller->call_site_hash) htab_remove_elt_with_hash (e->caller->call_site_hash, e->call_stmt, @@ -1115,9 +1037,8 @@ cgraph_remove_edge (struct cgraph_edge *e) /* Call all edge removal hooks. */ cgraph_call_edge_removal_hooks (e); - if (!e->indirect_unknown_callee) - /* Remove from callers list of the callee. */ - cgraph_edge_remove_callee (e); + /* Remove from callers list of the callee. */ + cgraph_edge_remove_callee (e); /* Remove from callees list of the callers. */ cgraph_edge_remove_caller (e); @@ -1126,20 +1047,6 @@ cgraph_remove_edge (struct cgraph_edge *e) cgraph_free_edge (e); } -/* Set callee of call graph edge E and add it to the corresponding set of - callers. */ - -static void -cgraph_set_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) -{ - e->prev_caller = NULL; - if (n->callers) - n->callers->prev_caller = e; - e->next_caller = n->callers; - n->callers = e; - e->callee = n; -} - /* Redirect callee of E to N. The function does not update underlying call expression. */ @@ -1150,37 +1057,12 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) cgraph_edge_remove_callee (e); /* Insert to callers list of the new callee. */ - cgraph_set_edge_callee (e, n); -} - -/* Make an indirect EDGE with an unknown callee an ordinary edge leading to - CALLEE. */ - -void -cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee) -{ - edge->indirect_unknown_callee = 0; - - /* Get the edge out of the indirect edge list. */ - if (edge->prev_callee) - edge->prev_callee->next_callee = edge->next_callee; - if (edge->next_callee) - edge->next_callee->prev_callee = edge->prev_callee; - if (!edge->prev_callee) - edge->caller->indirect_calls = edge->next_callee; - - /* Put it into the normal callee list */ - edge->prev_callee = NULL; - edge->next_callee = edge->caller->callees; - if (edge->caller->callees) - edge->caller->callees->prev_callee = edge; - edge->caller->callees = edge; - - /* Insert to callers list of the new callee. */ - cgraph_set_edge_callee (edge, callee); - - /* We need to re-determine the inlining status of the edge. */ - initialize_inline_failed (edge); + e->prev_caller = NULL; + if (n->callers) + n->callers->prev_caller = e; + e->next_caller = n->callers; + n->callers = e; + e->callee = n; } @@ -1209,10 +1091,9 @@ cgraph_update_edges_for_call_stmt_node (struct cgraph_node *node, if (e) { - /* See if the edge is already there and has the correct callee. It - might be so because of indirect inlining has already updated - it. */ - if (new_call && e->callee && e->callee->decl == new_call) + /* See if the call is already there. It might be because of indirect + inlining already found it. */ + if (new_call && e->callee->decl == new_call) return; /* Otherwise remove edge and create new one; we can't simply redirect @@ -1290,19 +1171,9 @@ cgraph_node_remove_callees (struct cgraph_node *node) { f = e->next_callee; cgraph_call_edge_removal_hooks (e); - if (!e->indirect_unknown_callee) - cgraph_edge_remove_callee (e); + cgraph_edge_remove_callee (e); cgraph_free_edge (e); } - for (e = node->indirect_calls; e; e = f) - { - f = e->next_callee; - cgraph_call_edge_removal_hooks (e); - if (!e->indirect_unknown_callee) - cgraph_edge_remove_callee (e); - cgraph_free_edge (e); - } - node->indirect_calls = NULL; node->callees = NULL; if (node->call_site_hash) { @@ -1425,8 +1296,6 @@ cgraph_remove_node (struct cgraph_node *node) cgraph_call_node_removal_hooks (node); cgraph_node_remove_callers (node); cgraph_node_remove_callees (node); - ipa_remove_all_references (&node->ref_list); - ipa_remove_all_refering (&node->ref_list); VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply); @@ -1654,16 +1523,9 @@ cgraph_mark_reachable_node (struct cgraph_node *node) { if (!node->reachable && node->local.finalized) { - if (cgraph_global_info_ready) - { - /* Verify that function does not appear to be needed out of blue - during the optimization process. This can happen for extern - inlines when bodies was removed after inlining. */ - gcc_assert ((node->analyzed || DECL_EXTERNAL (node->decl))); - } - else - notice_global_symbol (node->decl); + notice_global_symbol (node->decl); node->reachable = 1; + gcc_assert (!cgraph_global_info_ready); node->next_needed = cgraph_nodes_queue; cgraph_nodes_queue = node; @@ -1686,8 +1548,8 @@ cgraph_mark_needed_node (struct cgraph_node *node) void cgraph_mark_address_taken_node (struct cgraph_node *node) { - cgraph_mark_reachable_node (node); node->address_taken = 1; + cgraph_mark_needed_node (node); } /* Return local info for the compiled function. */ @@ -1765,8 +1627,6 @@ void dump_cgraph_node (FILE *f, struct cgraph_node *node) { struct cgraph_edge *edge; - int indirect_calls_count = 0; - fprintf (f, "%s/%i(%i)", cgraph_node_name (node), node->uid, node->pid); dump_addr (f, " @", (void *)node); @@ -1830,8 +1690,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf (f, " always_inline"); else if (node->local.inlinable) fprintf (f, " inlinable"); - else if (node->local.versionable) - fprintf (f, " versionable"); if (node->local.redefined_extern_inline) fprintf (f, " redefined_extern_inline"); if (TREE_ASM_WRITTEN (node->decl)) @@ -1850,8 +1708,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) edge->frequency / (double)CGRAPH_FREQ_BASE); if (!edge->inline_failed) fprintf(f, "(inlined) "); - if (edge->indirect_inlining_edge) - fprintf(f, "(indirect_inlining) "); + if (edge->indirect_call) + fprintf(f, "(indirect) "); if (edge->can_throw_external) fprintf(f, "(can throw external) "); } @@ -1863,8 +1721,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) edge->callee->uid); if (!edge->inline_failed) fprintf(f, "(inlined) "); - if (edge->indirect_inlining_edge) - fprintf(f, "(indirect_inlining) "); + if (edge->indirect_call) + fprintf(f, "(indirect) "); if (edge->count) fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ", (HOST_WIDEST_INT)edge->count); @@ -1877,16 +1735,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf(f, "(can throw external) "); } fprintf (f, "\n"); - fprintf (f, " References: "); - ipa_dump_references (f, &node->ref_list); - fprintf (f, " Refering this function: "); - ipa_dump_refering (f, &node->ref_list); - - for (edge = node->indirect_calls; edge; edge = edge->next_callee) - indirect_calls_count++; - if (indirect_calls_count) - fprintf (f, " has %i outgoing edges for indirect calls.\n", - indirect_calls_count); if (node->same_body) { @@ -1905,8 +1753,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) (int)n->thunk.virtual_offset_p); fprintf (f, ")"); } - if (DECL_ASSEMBLER_NAME_SET_P (n->decl)) - fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl))); } fprintf (f, "\n"); } @@ -2009,32 +1855,11 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, freq = e->frequency * (gcov_type) freq_scale / CGRAPH_FREQ_BASE; if (freq > CGRAPH_FREQ_MAX) freq = CGRAPH_FREQ_MAX; - - if (e->indirect_unknown_callee) - { - tree decl; - - if (call_stmt && (decl = gimple_call_fndecl (call_stmt))) - { - struct cgraph_node *callee = cgraph_node (decl); - new_edge = cgraph_create_edge (n, callee, call_stmt, count, freq, - e->loop_nest + loop_nest); - } - else - { - new_edge = cgraph_create_indirect_edge (n, call_stmt, - e->indirect_info->ecf_flags, - count, freq, - e->loop_nest + loop_nest); - *new_edge->indirect_info = *e->indirect_info; - } - } - else - new_edge = cgraph_create_edge (n, e->callee, call_stmt, count, freq, - e->loop_nest + loop_nest); + new_edge = cgraph_create_edge (n, e->callee, call_stmt, count, freq, + e->loop_nest + loop_nest); new_edge->inline_failed = e->inline_failed; - new_edge->indirect_inlining_edge = e->indirect_inlining_edge; + new_edge->indirect_call = e->indirect_call; new_edge->lto_stmt_uid = stmt_uid; if (update_original) { @@ -2048,14 +1873,12 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, /* 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 - as decl of N. 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, +cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq, int loop_nest, bool update_original, VEC(cgraph_edge_p,heap) *redirect_callers) { @@ -2064,7 +1887,7 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, gcov_type count_scale; unsigned i; - new_node->decl = decl; + new_node->decl = n->decl; new_node->origin = n->origin; if (new_node->origin) { @@ -2074,8 +1897,6 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, new_node->analyzed = n->analyzed; new_node->local = n->local; new_node->local.externally_visible = false; - new_node->local.local = true; - new_node->local.vtable_method = false; new_node->global = n->global; new_node->rtl = n->rtl; new_node->count = count; @@ -2110,11 +1931,6 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid, count_scale, freq, loop_nest, update_original); - for (e = n->indirect_calls; e; e = e->next_callee) - cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid, - count_scale, freq, loop_nest, update_original); - ipa_clone_references (new_node, NULL, &n->ref_list); - new_node->next_sibling_clone = n->clones; if (n->clones) n->clones->prev_sibling_clone = new_node; @@ -2122,24 +1938,6 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, new_node->clone_of = n; cgraph_call_node_duplication_hooks (n, new_node); - if (n->decl != decl) - { - struct cgraph_node **slot; - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, new_node, INSERT); - gcc_assert (!*slot); - *slot = new_node; - if (assembler_name_hash) - { - void **aslot; - tree name = DECL_ASSEMBLER_NAME (decl); - - aslot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - INSERT); - gcc_assert (!*aslot); - *aslot = new_node; - } - } return new_node; } @@ -2181,13 +1979,9 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, tree old_decl = old_node->decl; struct cgraph_node *new_node = NULL; tree new_decl; - size_t i; - struct ipa_replace_map *map; + struct cgraph_node key, **slot; -#ifdef ENABLE_CHECKING - if (!flag_wpa) - gcc_assert (tree_versionable_function_p (old_decl)); -#endif + gcc_assert (tree_versionable_function_p (old_decl)); /* Make a new FUNCTION_DECL tree node */ if (!args_to_skip) @@ -2201,9 +1995,10 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); SET_DECL_RTL (new_decl, NULL); - new_node = cgraph_clone_node (old_node, new_decl, old_node->count, + new_node = cgraph_clone_node (old_node, old_node->count, CGRAPH_FREQ_BASE, 0, false, redirect_callers); + new_node->decl = new_decl; /* Update the properties. Make clone visible only within this translation unit. Make sure that is not weak also. @@ -2216,26 +2011,6 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, DECL_WEAK (new_node->decl) = 0; new_node->clone.tree_map = tree_map; new_node->clone.args_to_skip = args_to_skip; - for (i = 0; VEC_iterate (ipa_replace_map_p, tree_map, i, map); i++) - { - tree var = map->new_tree; - - STRIP_NOPS (var); - if (TREE_CODE (var) != ADDR_EXPR) - continue; - var = get_base_var (var); - if (!var) - continue; - - /* Record references of the future statement initializing the constant - argument. */ - if (TREE_CODE (var) == FUNCTION_DECL) - ipa_record_reference (new_node, NULL, cgraph_node (var), - NULL, IPA_REF_ADDR, NULL); - else if (TREE_CODE (var) == VAR_DECL) - ipa_record_reference (new_node, NULL, NULL, varpool_node (var), - IPA_REF_ADDR, NULL); - } if (!args_to_skip) new_node->clone.combined_args_to_skip = old_node->clone.combined_args_to_skip; else if (old_node->clone.combined_args_to_skip) @@ -2266,6 +2041,21 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, new_node->lowered = true; new_node->reachable = true; + key.decl = new_decl; + slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT); + gcc_assert (!*slot); + *slot = new_node; + if (assembler_name_hash) + { + void **aslot; + tree name = DECL_ASSEMBLER_NAME (new_decl); + + aslot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + INSERT); + gcc_assert (!*aslot); + *aslot = new_node; + } return new_node; } @@ -2408,7 +2198,7 @@ cgraph_add_new_function (tree fndecl, bool lowered) bool cgraph_node_can_be_local_p (struct cgraph_node *node) { - return (!node->needed && !node->address_taken + return (!node->needed && ((DECL_COMDAT (node->decl) && !node->same_comdat_group) || !node->local.externally_visible)); } @@ -2517,67 +2307,4 @@ cgraph_set_looping_const_or_pure_flag (struct cgraph_node *node, DECL_LOOPING_CONST_OR_PURE_P (alias->decl) = looping_const_or_pure; } -/* See if the frequency of NODE can be updated based on frequencies of its - callers. */ -bool -cgraph_propagate_frequency (struct cgraph_node *node) -{ - bool maybe_unlikely_executed = true, maybe_executed_once = true; - struct cgraph_edge *edge; - if (!node->local.local) - return false; - gcc_assert (node->analyzed); - if (node->frequency == NODE_FREQUENCY_HOT) - return false; - if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) - return false; - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Processing frequency %s\n", cgraph_node_name (node)); - for (edge = node->callers; - edge && (maybe_unlikely_executed || maybe_executed_once); - edge = edge->next_caller) - { - if (!edge->frequency) - continue; - switch (edge->caller->frequency) - { - case NODE_FREQUENCY_UNLIKELY_EXECUTED: - break; - case NODE_FREQUENCY_EXECUTED_ONCE: - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " Called by %s that is executed once\n", cgraph_node_name (node)); - maybe_unlikely_executed = false; - if (edge->loop_nest) - { - maybe_executed_once = false; - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " Called in loop\n"); - } - break; - case NODE_FREQUENCY_HOT: - case NODE_FREQUENCY_NORMAL: - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " Called by %s that is normal or hot\n", cgraph_node_name (node)); - maybe_unlikely_executed = false; - maybe_executed_once = false; - break; - } - } - if (maybe_unlikely_executed) - { - node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; - if (dump_file) - fprintf (dump_file, "Node %s promoted to unlikely executed.\n", cgraph_node_name (node)); - return true; - } - if (maybe_executed_once && node->frequency != NODE_FREQUENCY_EXECUTED_ONCE) - { - node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; - if (dump_file) - fprintf (dump_file, "Node %s promoted to executed once.\n", cgraph_node_name (node)); - return true; - } - return false; -} - #include "gt-cgraph.h" diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 6bc565a2d17..9b9bf4d42d7 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -175,6 +175,21 @@ struct GTY(()) cgraph_clone_info bitmap combined_args_to_skip; }; +enum node_frequency { + /* This function most likely won't be executed at all. + (set only when profile feedback is available or via function attribute). */ + NODE_FREQUENCY_UNLIKELY_EXECUTED, + /* For functions that are known to be executed once (i.e. constructors, destructors + and main function. */ + NODE_FREQUENCY_EXECUTED_ONCE, + /* The default value. */ + NODE_FREQUENCY_NORMAL, + /* Optimize this function hard + (set only when profile feedback is available or via function attribute). */ + NODE_FREQUENCY_HOT +}; + + /* The cgraph data structure. Each function decl has assigned cgraph_node listing callees and callers. */ @@ -267,6 +282,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { /* Set for alias and thunk nodes, same_body points to the node they are alias of and they are linked through the next/previous pointers. */ unsigned same_body_alias : 1; + /* How commonly executed the node is. Initialized during branch + probabilities pass. */ + ENUM_BITFIELD (node_frequency) frequency : 2; }; typedef struct cgraph_node *cgraph_node_ptr; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 3e887f81612..d13ab18313d 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -8010,6 +8010,7 @@ ix86_compute_frame_layout (struct ix86_frame *frame) && cfun->machine->use_fast_prologue_epilogue_nregs != frame->nregs) { int count = frame->nregs; + struct cgraph_node *node = cgraph_node (current_function_decl); cfun->machine->use_fast_prologue_epilogue_nregs = count; /* The fast prologue uses move instead of push to save registers. This @@ -8024,9 +8025,9 @@ ix86_compute_frame_layout (struct ix86_frame *frame) slow to use many of them. */ if (count) count = (count - 1) * FAST_PROLOGUE_INSN_COUNT; - if (cfun->function_frequency < FUNCTION_FREQUENCY_NORMAL + if (node->frequency < NODE_FREQUENCY_NORMAL || (flag_branch_probabilities - && cfun->function_frequency < FUNCTION_FREQUENCY_HOT)) + && node->frequency < NODE_FREQUENCY_HOT)) cfun->machine->use_fast_prologue_epilogue = false; else cfun->machine->use_fast_prologue_epilogue @@ -26706,7 +26707,7 @@ ix86_pad_returns (void) replace = true; /* Empty functions get branch mispredict even when the jump destination is not visible to us. */ - if (!prev && cfun->function_frequency > FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + if (!prev && !optimize_function_for_size_p (cfun)) replace = true; } if (replace) diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index cb87143e4ac..6f229681b2c 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -286,6 +286,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, bp_pack_value (bp, node->process, 1); bp_pack_value (bp, node->alias, 1); bp_pack_value (bp, node->finalized_by_frontend, 1); + bp_pack_value (bp, node->frequency, 2); lto_output_bitpack (ob->main_stream, bp); bitpack_delete (bp); @@ -544,6 +545,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, node->process = bp_unpack_value (bp, 1); node->alias = bp_unpack_value (bp, 1); node->finalized_by_frontend = bp_unpack_value (bp, 1); + node->frequency = (enum node_frequency)bp_unpack_value (bp, 2); } diff --git a/gcc/passes.c b/gcc/passes.c index a6e5af50841..e503dc64bcc 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -1361,14 +1361,17 @@ pass_init_dump_file (struct opt_pass *pass) if (dump_file && current_function_decl) { const char *dname, *aname; + struct cgraph_node *node = cgraph_node (current_function_decl); dname = lang_hooks.decl_printable_name (current_function_decl, 2); aname = (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl))); fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname, - cfun->function_frequency == FUNCTION_FREQUENCY_HOT + node->frequency == NODE_FREQUENCY_HOT ? " (hot)" - : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED + : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED ? " (unlikely executed)" + : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE + ? " (executed once)" : ""); } return initializing_dump; -- 2.11.0