Commit e42922b1 by Jan Hubicka Committed by Jan Hubicka

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
parent eef16504
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
......
......@@ -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
......
......@@ -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;
......
......@@ -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 *);
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -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) \
......
......@@ -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;
}
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment