From 125b6d78d39ec6f18cab9f54a07d474e496920c8 Mon Sep 17 00:00:00 2001 From: hubicka Date: Mon, 26 Apr 2010 13:33:24 +0000 Subject: * 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 | 2 ++ gcc/cgraph.h | 18 +++++++++++++++++ gcc/config/i386/i386.c | 7 ++++--- gcc/final.c | 7 +++++-- gcc/function.c | 2 -- gcc/function.h | 15 -------------- gcc/lto-cgraph.c | 2 ++ gcc/lto-streamer-in.c | 1 - gcc/lto-streamer-out.c | 1 - gcc/passes.c | 7 +++++-- gcc/predict.c | 50 ++++++++++++++++++++++++++++++++-------------- gcc/tree-inline.c | 1 - gcc/tree-ssa-loop-ivopts.c | 7 ++++--- 14 files changed, 103 insertions(+), 45 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 77d63554876..07f76298145 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 c5e0f3d940c..b58d4ee5516 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -453,6 +453,7 @@ cgraph_create_node (void) cgraph_nodes->previous = node; node->previous = NULL; node->global.estimated_growth = INT_MIN; + node->frequency = NODE_FREQUENCY_NORMAL; cgraph_nodes = node; cgraph_n_nodes++; return node; @@ -1899,6 +1900,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq, new_node->global = n->global; new_node->rtl = n->rtl; new_node->count = count; + new_node->frequency = n->frequency; new_node->clone = n->clone; new_node->clone.tree_map = 0; if (n->count) 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/final.c b/gcc/final.c index e2b7461bbbe..5011b6c5cac 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -4374,14 +4374,17 @@ rest_of_clean_state (void) else { const char *aname; + struct cgraph_node *node = cgraph_node (current_function_decl); aname = (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl))); fprintf (final_output, "\n;; Function (%s) %s\n\n", 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)" : ""); flag_dump_noaddr = flag_dump_unnumbered = 1; diff --git a/gcc/function.c b/gcc/function.c index f78bc98af28..949480ca9d0 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4115,8 +4115,6 @@ allocate_struct_function (tree fndecl, bool abstract_p) cfun = GGC_CNEW (struct function); - cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL; - init_eh_for_function (); if (init_machine_status) diff --git a/gcc/function.h b/gcc/function.h index fb2965a2c6b..e5e03384718 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -176,17 +176,6 @@ typedef struct ipa_opt_pass_d *ipa_opt_pass; DEF_VEC_P(ipa_opt_pass); DEF_VEC_ALLOC_P(ipa_opt_pass,heap); -enum function_frequency { - /* This function most likely won't be executed at all. - (set only when profile feedback is available or via function attribute). */ - FUNCTION_FREQUENCY_UNLIKELY_EXECUTED, - /* The default value. */ - FUNCTION_FREQUENCY_NORMAL, - /* Optimize this function hard - (set only when profile feedback is available or via function attribute). */ - FUNCTION_FREQUENCY_HOT -}; - struct GTY(()) varasm_status { /* If we're using a per-function constant pool, this is it. */ struct rtx_constant_pool *pool; @@ -538,10 +527,6 @@ struct GTY(()) function { function. */ unsigned int va_list_fpr_size : 8; - /* How commonly executed the function is. Initialized during branch - probabilities pass. */ - ENUM_BITFIELD (function_frequency) function_frequency : 2; - /* Nonzero if function being compiled can call setjmp. */ unsigned int calls_setjmp : 1; 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/lto-streamer-in.c b/gcc/lto-streamer-in.c index 6afad5b612c..4f9fca336fb 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1314,7 +1314,6 @@ input_function (tree fn_decl, struct data_in *data_in, fn->has_nonlocal_label = bp_unpack_value (bp, 1); fn->calls_alloca = bp_unpack_value (bp, 1); fn->calls_setjmp = bp_unpack_value (bp, 1); - fn->function_frequency = (enum function_frequency) bp_unpack_value (bp, 2); fn->va_list_fpr_size = bp_unpack_value (bp, 8); fn->va_list_gpr_size = bp_unpack_value (bp, 8); bitpack_delete (bp); diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index c9220254db9..e9ae494f3b7 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -1866,7 +1866,6 @@ output_function (struct cgraph_node *node) bp_pack_value (bp, fn->has_nonlocal_label, 1); bp_pack_value (bp, fn->calls_alloca, 1); bp_pack_value (bp, fn->calls_setjmp, 1); - bp_pack_value (bp, fn->function_frequency, 2); bp_pack_value (bp, fn->va_list_fpr_size, 8); bp_pack_value (bp, fn->va_list_gpr_size, 8); lto_output_bitpack (ob->main_stream, bp); 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; diff --git a/gcc/predict.c b/gcc/predict.c index eb5ddef2e38..29e0e2fcd99 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -113,15 +113,19 @@ static const struct predictor_info predictor_info[]= { static inline bool maybe_hot_frequency_p (int freq) { + struct cgraph_node *node = cgraph_node (current_function_decl); if (!profile_info || !flag_branch_probabilities) { - if (cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) return false; - if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT) + if (node->frequency == NODE_FREQUENCY_HOT) return true; } if (profile_status == PROFILE_ABSENT) return true; + if (node->frequency == NODE_FREQUENCY_EXECUTED_ONCE + && freq <= (ENTRY_BLOCK_PTR->frequency * 2 / 3)) + return false; if (freq < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION)) return false; return true; @@ -161,11 +165,16 @@ cgraph_maybe_hot_edge_p (struct cgraph_edge *edge) && (edge->count <= profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION))) return false; - if (lookup_attribute ("cold", DECL_ATTRIBUTES (edge->callee->decl)) - || lookup_attribute ("cold", DECL_ATTRIBUTES (edge->caller->decl))) + if (edge->caller->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED + || edge->callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) + return false; + if (optimize_size) return false; - if (lookup_attribute ("hot", DECL_ATTRIBUTES (edge->caller->decl))) + if (edge->caller->frequency == NODE_FREQUENCY_HOT) return true; + if (edge->caller->frequency == NODE_FREQUENCY_EXECUTED_ONCE + && edge->frequency < CGRAPH_FREQ_BASE * 3 / 2) + return false; if (flag_guess_branch_prob && edge->frequency <= (CGRAPH_FREQ_BASE / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))) @@ -191,7 +200,7 @@ probably_never_executed_bb_p (const_basic_block bb) if (profile_info && flag_branch_probabilities) return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0; if ((!profile_info || !flag_branch_probabilities) - && cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + && cgraph_node (current_function_decl)->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) return true; return false; } @@ -202,8 +211,9 @@ bool optimize_function_for_size_p (struct function *fun) { return (optimize_size - || (fun && (fun->function_frequency - == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED))); + || (fun && fun->decl + && (cgraph_node (fun->decl)->frequency + == NODE_FREQUENCY_UNLIKELY_EXECUTED))); } /* Return true when current function should always be optimized for speed. */ @@ -2148,27 +2158,36 @@ void compute_function_frequency (void) { basic_block bb; + struct cgraph_node *node = cgraph_node (current_function_decl); if (!profile_info || !flag_branch_probabilities) { + int flags = flags_from_decl_or_type (current_function_decl); if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl)) != NULL) - cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED; + node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; else if (lookup_attribute ("hot", DECL_ATTRIBUTES (current_function_decl)) != NULL) - cfun->function_frequency = FUNCTION_FREQUENCY_HOT; + node->frequency = NODE_FREQUENCY_HOT; + else if (flags & ECF_NORETURN) + node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; + else if (MAIN_NAME_P (DECL_NAME (current_function_decl))) + node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; + else if (DECL_STATIC_CONSTRUCTOR (current_function_decl) + || DECL_STATIC_DESTRUCTOR (current_function_decl)) + node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; return; } - cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED; + node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; FOR_EACH_BB (bb) { if (maybe_hot_bb_p (bb)) { - cfun->function_frequency = FUNCTION_FREQUENCY_HOT; + node->frequency = NODE_FREQUENCY_HOT; return; } if (!probably_never_executed_bb_p (bb)) - cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL; + node->frequency = NODE_FREQUENCY_NORMAL; } } @@ -2176,6 +2195,7 @@ compute_function_frequency (void) static void choose_function_section (void) { + struct cgraph_node *node = cgraph_node (current_function_decl); if (DECL_SECTION_NAME (current_function_decl) || !targetm.have_named_sections /* Theoretically we can split the gnu.linkonce text section too, @@ -2191,10 +2211,10 @@ choose_function_section (void) if (flag_reorder_blocks_and_partition) return; - if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT) + if (node->frequency == NODE_FREQUENCY_HOT) DECL_SECTION_NAME (current_function_decl) = build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME); - if (cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED) + if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) DECL_SECTION_NAME (current_function_decl) = build_string (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME), UNLIKELY_EXECUTED_TEXT_SECTION_NAME); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 59661a7d509..0c1293e6517 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -2014,7 +2014,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count) cfun->last_verified = src_cfun->last_verified; cfun->va_list_gpr_size = src_cfun->va_list_gpr_size; cfun->va_list_fpr_size = src_cfun->va_list_fpr_size; - cfun->function_frequency = src_cfun->function_frequency; cfun->has_nonlocal_label = src_cfun->has_nonlocal_label; cfun->stdarg = src_cfun->stdarg; cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p; diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index f6db2415a36..a7a9e253850 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -2738,9 +2738,10 @@ computation_cost (tree expr, bool speed) unsigned cost; /* Avoid using hard regs in ways which may be unsupported. */ int regno = LAST_VIRTUAL_REGISTER + 1; - enum function_frequency real_frequency = cfun->function_frequency; + struct cgraph_node *node = cgraph_node (current_function_decl); + enum node_frequency real_frequency = node->frequency; - cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL; + node->frequency = NODE_FREQUENCY_NORMAL; crtl->maybe_hot_insn_p = speed; walk_tree (&expr, prepare_decl_rtl, ®no, NULL); start_sequence (); @@ -2748,7 +2749,7 @@ computation_cost (tree expr, bool speed) seq = get_insns (); end_sequence (); default_rtl_profile (); - cfun->function_frequency = real_frequency; + node->frequency = real_frequency; cost = seq_cost (seq, speed); if (MEM_P (rslt)) -- cgit v1.2.1