diff options
author | Jan Hubicka <jh@suse.cz> | 2005-05-19 12:38:42 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2005-05-19 10:38:42 +0000 |
commit | e42922b1ae4c3da94882d3a92ce978a0db123064 (patch) | |
tree | 1d011084a5002e1aadab35d8ef841e441fb68211 /gcc | |
parent | eef16504e21f8d504b6a648cf73955e977d5adf6 (diff) | |
download | gcc-e42922b1ae4c3da94882d3a92ce978a0db123064.tar.gz |
basic-block.h (REG_BR_PROB_BASE): Define.
* basic-block.h (REG_BR_PROB_BASE): Define.
* cgraph.c (cgraph_create_edge): Initialize loop_nest and count.
(dump_cgraph_node): Dump count.
(cgraph_clone_edge): Rescale counts.
(cgraph_clone_node): Likewise.
* cgraph.h: Include basic-block.h
(cgraph_node): Add count.
(cgraph_edge): Add count and loop_nest.
(cgraph_node, cgraph_edge, cgraph_clone_edge, cgraph_clone_node):
Update prototypes.
* cgraphunit.c: Kill now redundant inlining comment.
(cgraph_create_edges): Make static, maintain current basic block;
fix pasto.
(record_call_1): Fill in new fields.
* ipa-inline.c (cgraph_clone_inlined_nodes): Update call of
cgraph_clone_node.
(cgraph_decide_recursive_inlining): Likewise.
* rtl.h (REG_BR_PROB_BASE): Kill.
* tree-inline.c (copy_body_r): Update call of cgraph_clone_edge.
(expand_call_inline): Update call of cgraph_create_edge.
* tree-optimize.c (tree_rest_of_compilation): Likewise.
From-SVN: r99976
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/basic-block.h | 3 | ||||
-rw-r--r-- | gcc/cgraph.c | 34 | ||||
-rw-r--r-- | gcc/cgraph.h | 22 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 47 | ||||
-rw-r--r-- | gcc/ipa-inline.c | 4 | ||||
-rw-r--r-- | gcc/rtl.h | 3 | ||||
-rw-r--r-- | gcc/tree-inline.c | 6 | ||||
-rw-r--r-- | gcc/tree-optimize.c | 2 |
9 files changed, 89 insertions, 56 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ac2ac51a264..51df4dc1950 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2005-05-19 Jan Hubicka <jh@suse.cz> + + * basic-block.h (REG_BR_PROB_BASE): Define. + * cgraph.c (cgraph_create_edge): Initialize loop_nest and count. + (dump_cgraph_node): Dump count. + (cgraph_clone_edge): Rescale counts. + (cgraph_clone_node): Likewise. + * cgraph.h: Include basic-block.h + (cgraph_node): Add count. + (cgraph_edge): Add count and loop_nest. + (cgraph_node, cgraph_edge, cgraph_clone_edge, cgraph_clone_node): + Update prototypes. + * cgraphunit.c: Kill now redundant inlining comment. + (cgraph_create_edges): Make static, maintain current basic block; + fix pasto. + (record_call_1): Fill in new fields. + * ipa-inline.c (cgraph_clone_inlined_nodes): Update call of + cgraph_clone_node. + (cgraph_decide_recursive_inlining): Likewise. + * rtl.h (REG_BR_PROB_BASE): Kill. + * tree-inline.c (copy_body_r): Update call of cgraph_clone_edge. + (expand_call_inline): Update call of cgraph_create_edge. + * tree-optimize.c (tree_rest_of_compilation): Likewise. + 2005-05-19 Nick Clifton <nickc@redhat.com> * config/rs6000/eabispe.h (SUBSUBTARGET_OVERRIDE_OPTIONS): Use the diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 5565053337a..4deeb899755 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -555,6 +555,9 @@ struct edge_list edge *index_to_edge; }; +/* The base value for branch probability notes and edge probabilities. */ +#define REG_BR_PROB_BASE 10000 + /* This is the value which indicates no edge is present. */ #define EDGE_INDEX_NO_EDGE -1 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index adef0bd09ce..c2509ffc033 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -275,7 +275,7 @@ cgraph_edge (struct cgraph_node *node, tree call_expr) struct cgraph_edge * cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, - tree call_expr) + tree call_expr, gcov_type count, int nest) { struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); #ifdef ENABLE_CHECKING @@ -312,6 +312,8 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, caller->callees->prev_callee = edge; caller->callees = edge; callee->callers = edge; + edge->count = count; + edge->loop_nest = nest; return edge; } @@ -559,6 +561,9 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf (f, " (inline copy in %s/%i)", cgraph_node_name (node->global.inlined_to), node->global.inlined_to->uid); + if (node->count) + fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x", + (HOST_WIDEST_INT)node->count); if (node->local.self_insns) fprintf (f, " %i insns", node->local.self_insns); if (node->global.insns && node->global.insns != node->local.self_insns) @@ -587,6 +592,9 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) { fprintf (f, "%s/%i ", cgraph_node_name (edge->caller), edge->caller->uid); + if (edge->count) + fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ", + (HOST_WIDEST_INT)edge->count); if (!edge->inline_failed) fprintf(f, "(inlined) "); } @@ -829,20 +837,28 @@ cgraph_function_possibly_inlined_p (tree decl) /* Create clone of E in the node N represented by CALL_EXPR the callgraph. */ struct cgraph_edge * -cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, tree call_expr) +cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, + tree call_expr, int count_scale, int loop_nest) { - struct cgraph_edge *new = cgraph_create_edge (n, e->callee, call_expr); + struct cgraph_edge *new; + + new = cgraph_create_edge (n, e->callee, call_expr, + e->count * count_scale / REG_BR_PROB_BASE, + e->loop_nest + loop_nest); new->inline_failed = e->inline_failed; + e->count -= new->count; return new; } -/* Create node representing clone of N. */ +/* Create node representing clone of N executed COUNT times. Decrease + the execution counts from original node too. */ struct cgraph_node * -cgraph_clone_node (struct cgraph_node *n) +cgraph_clone_node (struct cgraph_node *n, gcov_type count, int loop_nest) { struct cgraph_node *new = cgraph_create_node (); struct cgraph_edge *e; + int count_scale; new->decl = n->decl; new->origin = n->origin; @@ -855,9 +871,15 @@ cgraph_clone_node (struct cgraph_node *n) new->local = n->local; new->global = n->global; new->rtl = n->rtl; + new->count = count; + if (n->count) + count_scale = new->count * REG_BR_PROB_BASE / n->count; + else + count_scale = 0; + n->count -= count; for (e = n->callees;e; e=e->next_callee) - cgraph_clone_edge (e, new, e->call_expr); + cgraph_clone_edge (e, new, e->call_expr, count_scale, loop_nest); new->next_clone = n->next_clone; new->prev_clone = n; diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 6f3864cfcad..294b690787b 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -22,6 +22,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #ifndef GCC_CGRAPH_H #define GCC_CGRAPH_H #include "tree.h" +#include "basic-block.h" /* Information about the function collected locally. Available after function is analyzed. */ @@ -109,6 +110,8 @@ struct cgraph_node GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) struct cgraph_global_info global; struct cgraph_rtl_info rtl; + /* Expected number of executions: calculated in profile.c. */ + gcov_type count; /* Unique id of the node. */ int uid; /* Set when function must be output - it is externally visible @@ -141,6 +144,10 @@ struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_call /* When NULL, inline this call. When non-NULL, points to the explanation why function was not inlined. */ const char *inline_failed; + /* Expected number of executions: calculated in profile.c. */ + gcov_type count; + /* Depth of loop nest, 1 means no loop nest. */ + int loop_nest; }; /* The cgraph_varpool data structure. @@ -190,25 +197,25 @@ void cgraph_remove_node (struct cgraph_node *); void cgraph_node_remove_callees (struct cgraph_node *node); struct cgraph_edge *cgraph_create_edge (struct cgraph_node *, struct cgraph_node *, - tree); -struct cgraph_node *cgraph_node (tree decl); + tree, gcov_type, int); +struct cgraph_node *cgraph_node (tree); struct cgraph_node *cgraph_node_for_asm (tree asmname); -struct cgraph_edge *cgraph_edge (struct cgraph_node *, tree call_expr); +struct cgraph_edge *cgraph_edge (struct cgraph_node *, tree); struct cgraph_local_info *cgraph_local_info (tree); struct cgraph_global_info *cgraph_global_info (tree); struct cgraph_rtl_info *cgraph_rtl_info (tree); const char * cgraph_node_name (struct cgraph_node *); -struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *, struct cgraph_node *, tree); -struct cgraph_node * cgraph_clone_node (struct cgraph_node *); +struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *, struct cgraph_node *, tree, int, int); +struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int); -struct cgraph_varpool_node *cgraph_varpool_node (tree decl); +struct cgraph_varpool_node *cgraph_varpool_node (tree); struct cgraph_varpool_node *cgraph_varpool_node_for_asm (tree asmname); void cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *); void cgraph_varpool_finalize_decl (tree); void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *); bool cgraph_function_possibly_inlined_p (tree); -void cgraph_unnest_node (struct cgraph_node *node); +void cgraph_unnest_node (struct cgraph_node *); void cgraph_varpool_enqueue_needed_node (struct cgraph_varpool_node *); void cgraph_varpool_reset_queue (void); bool decide_is_variable_needed (struct cgraph_varpool_node *, tree); @@ -219,7 +226,6 @@ bool cgraph_varpool_assemble_pending_decls (void); void cgraph_finalize_function (tree, bool); void cgraph_lower_function (struct cgraph_node *); void cgraph_finalize_compilation_unit (void); -void cgraph_create_edges (struct cgraph_node *, tree); void cgraph_optimize (void); void cgraph_mark_needed_node (struct cgraph_node *); void cgraph_mark_reachable_node (struct cgraph_node *); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 548a5fcb177..14eb46b22c0 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -136,33 +136,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA decision on whether function is needed is made more conservative so uninlininable static functions are needed too. During the call-graph construction the edge destinations are not marked as reachable and it - is completely relied upn assemble_variable to mark them. - - Inlining decision heuristics - ??? Move this to separate file after tree-ssa merge. - - We separate inlining decisions from the inliner itself and store it - inside callgraph as so called inline plan. Refer to cgraph.c - documentation about particular representation of inline plans in the - callgraph - - The implementation of particular heuristics is separated from - the rest of code to make it easier to replace it with more complicated - implementation in the future. The rest of inlining code acts as a - library aimed to modify the callgraph and verify that the parameters - on code size growth fits. - - To mark given call inline, use cgraph_mark_inline function, the - verification is performed by cgraph_default_inline_p and - cgraph_check_inline_limits. - - The heuristics implements simple knapsack style algorithm ordering - all functions by their "profitability" (estimated by code size growth) - and inlining them in priority order. - - cgraph_decide_inlining implements heuristics taking whole callgraph - into account, while cgraph_decide_inlining_incrementally considers - only one function at a time and is used in non-unit-at-a-time mode. */ + is completely relied upn assemble_variable to mark them. */ #include "config.h" @@ -198,6 +172,7 @@ static void cgraph_expand_function (struct cgraph_node *); static tree record_call_1 (tree *, int *, void *); static void cgraph_mark_local_functions (void); static void cgraph_analyze_function (struct cgraph_node *node); +static void cgraph_create_edges (struct cgraph_node *node, tree body); /* Records tree nodes seen in cgraph_create_edges. Simply using walk_tree_without_duplicates doesn't guarantee each node is visited @@ -460,6 +435,9 @@ cgraph_finalize_function (tree decl, bool nested) do_warn_unused_parameter (decl); } +/* Used only while constructing the callgraph. */ +static basic_block current_basic_block; + void cgraph_lower_function (struct cgraph_node *node) { @@ -469,7 +447,6 @@ cgraph_lower_function (struct cgraph_node *node) node->lowered = true; } - /* Walk tree and record all calls. Called via walk_tree. */ static tree record_call_1 (tree *tp, int *walk_subtrees, void *data) @@ -508,7 +485,9 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data) tree decl = get_callee_fndecl (*tp); if (decl && TREE_CODE (decl) == FUNCTION_DECL) { - cgraph_create_edge (data, cgraph_node (decl), *tp); + cgraph_create_edge (data, cgraph_node (decl), *tp, + current_basic_block->count, + current_basic_block->loop_depth); /* When we see a function call, we don't want to look at the function reference in the ADDR_EXPR that is hanging from @@ -543,24 +522,25 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data) /* Create cgraph edges for function calls inside BODY from NODE. */ -void +static void cgraph_create_edges (struct cgraph_node *node, tree body) { /* The nodes we're interested in are never shared, so walk the tree ignoring duplicates. */ visited_nodes = pointer_set_create (); + gcc_assert (current_basic_block == NULL); if (TREE_CODE (body) == FUNCTION_DECL) { struct function *this_cfun = DECL_STRUCT_FUNCTION (body); - basic_block this_block; block_stmt_iterator bsi; tree step; /* Reach the trees by walking over the CFG, and note the enclosing basic-blocks in the call edges. */ - FOR_EACH_BB_FN (this_block, this_cfun) - for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi)) + FOR_EACH_BB_FN (current_basic_block, this_cfun) + for (bsi = bsi_start (current_basic_block); !bsi_end_p (bsi); bsi_next (&bsi)) walk_tree (bsi_stmt_ptr (bsi), record_call_1, node, visited_nodes); + current_basic_block = NULL; /* Walk over any private statics that may take addresses of functions. */ if (TREE_CODE (DECL_INITIAL (body)) == BLOCK) @@ -586,7 +566,6 @@ cgraph_create_edges (struct cgraph_node *node, tree body) else walk_tree (&body, record_call_1, node, visited_nodes); - walk_tree (&body, record_call_1, node, visited_nodes); pointer_set_destroy (visited_nodes); visited_nodes = NULL; } diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index f1236eac5f4..79150d2ba9a 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -123,7 +123,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate) } else if (duplicate) { - n = cgraph_clone_node (e->callee); + n = cgraph_clone_node (e->callee, e->count, e->loop_nest); cgraph_redirect_edge_callee (e, n); } @@ -369,7 +369,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); + master_clone = cgraph_clone_node (node, 0, 1); master_clone->needed = true; for (e = master_clone->callees; e; e = e->next_callee) if (!e->inline_failed) diff --git a/gcc/rtl.h b/gcc/rtl.h index c162393a74e..2eb5d9c84b8 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -706,9 +706,6 @@ enum reg_note REG_NOTE_MAX }; -/* The base value for branch probability notes. */ -#define REG_BR_PROB_BASE 10000 - /* Define macros to extract and insert the reg-note kind in an EXPR_LIST. */ #define REG_NOTE_KIND(LINK) ((enum reg_note) GET_MODE (LINK)) #define PUT_REG_NOTE_KIND(LINK, KIND) \ diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index d9654f4d52c..118f493e299 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -656,7 +656,8 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) associate callgraph nodes. */ edge = cgraph_edge (id->current_node, old_node); if (edge) - cgraph_clone_edge (edge, id->node, *tp); + cgraph_clone_edge (edge, id->node, *tp, + REG_BR_PROB_BASE, 1); } } else if (TREE_CODE (*tp) == RESX_EXPR && id->eh_region_offset) @@ -1922,7 +1923,8 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data) constant propagating arguments. In all other cases we hit a bug (incorrect node sharing is most common reason for missing edges. */ gcc_assert (dest->needed || !flag_unit_at_a_time); - cgraph_create_edge (id->node, dest, t)->inline_failed + cgraph_create_edge (id->node, dest, t, + bb->count, bb->loop_depth)->inline_failed = N_("originally indirect function call not considered for inlining"); goto egress; } diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index 109c5bc1c0e..7c9beb812dc 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -741,7 +741,7 @@ tree_rest_of_compilation (tree fndecl) { struct cgraph_edge *e; - saved_node = cgraph_clone_node (node); + saved_node = cgraph_clone_node (node, node->count, 1); for (e = saved_node->callees; e; e = e->next_callee) if (!e->inline_failed) cgraph_clone_inlined_nodes (e, true); |