Commit ea99e0be by Jan Hubicka Committed by Jan Hubicka

cgraph.c (cgraph_insert_node_to_hashtable): New function.

	* cgraph.c (cgraph_insert_node_to_hashtable): New function.
	* cgraph.h (cgraph_node): Add inline_decl.
	(cgraph_insert_node_to_hashtable): Declare.
	(save_inline_function_body): Declare.
	* cgraphunit.c (verify_cgraph_node): Inline edges might point to inline
	clones.
	(cgraph_preserve_function_body_p): Do not presrve when dump is enabled.
	(cgraph_function_versioning): Update call of tree_function_versioning.
	(save_inline_function_body): New function.
	* function.h (struct function): Kill saved_eh, saved_cfg, saved_args,
	saved_static_chain_decl, saved_blocks and saved-unexpanded_var_list.
	* ipa-inline.c (cgraph_mark_inline_edge): Look for inline clones.
	(cgraph_default_inline_p): Likewise.
	(cgraph_decide_inlining_incrementally): Likewise.
	* tree-inline.c (inline_data): Kill saving_p add update_clones_p.
	(copy_bb): Kill saving; do updating of clones.
	(copy_cfg_body): Kill saving.
	(initialize_inlined-parameters): Likewise.
	(expand_call_inline): Likewise.
	(save_body): Kill.
	(tree_function_versioning): New parameter "update_clones".
	(inlining_p): Kill saving.
	* tree-inline.h (tree_function_versioning): Update prototype.
	* tree-optimize.c (tree_rest_of_compilation): Use clonning instead of
	saving.

From-SVN: r109580
parent abcb0cdc
2006-01-11 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_insert_node_to_hashtable): New function.
* cgraph.h (cgraph_node): Add inline_decl.
(cgraph_insert_node_to_hashtable): Declare.
(save_inline_function_body): Declare.
* cgraphunit.c (verify_cgraph_node): Inline edges might point to inline
clones.
(cgraph_preserve_function_body_p): Do not presrve when dump is enabled.
(cgraph_function_versioning): Update call of tree_function_versioning.
(save_inline_function_body): New function.
* function.h (struct function): Kill saved_eh, saved_cfg, saved_args,
saved_static_chain_decl, saved_blocks and saved-unexpanded_var_list.
* ipa-inline.c (cgraph_mark_inline_edge): Look for inline clones.
(cgraph_default_inline_p): Likewise.
(cgraph_decide_inlining_incrementally): Likewise.
* tree-inline.c (inline_data): Kill saving_p add update_clones_p.
(copy_bb): Kill saving; do updating of clones.
(copy_cfg_body): Kill saving.
(initialize_inlined-parameters): Likewise.
(expand_call_inline): Likewise.
(save_body): Kill.
(tree_function_versioning): New parameter "update_clones".
(inlining_p): Kill saving.
* tree-inline.h (tree_function_versioning): Update prototype.
* tree-optimize.c (tree_rest_of_compilation): Use clonning instead of
saving.
2006-01-11 Ian Lance Taylor <ian@airs.com> 2006-01-11 Ian Lance Taylor <ian@airs.com>
* combine.c (struct undo): Remove is_int. Enumify types of undos. * combine.c (struct undo): Remove is_int. Enumify types of undos.
......
...@@ -214,6 +214,19 @@ cgraph_node (tree decl) ...@@ -214,6 +214,19 @@ cgraph_node (tree decl)
return node; return node;
} }
/* Insert already constructed node into hashtable. */
void
cgraph_insert_node_to_hashtable (struct cgraph_node *node)
{
struct cgraph_node **slot;
slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, node, INSERT);
gcc_assert (!*slot);
*slot = node;
}
/* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */ /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */
static bool static bool
......
...@@ -161,6 +161,11 @@ struct cgraph_node GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) ...@@ -161,6 +161,11 @@ struct cgraph_node GTY((chain_next ("%h.next"), chain_prev ("%h.previous")))
bool externally_visible; bool externally_visible;
/* Set for aliases once they got through assemble_alias. */ /* Set for aliases once they got through assemble_alias. */
bool alias; bool alias;
/* In non-unit-at-a-time mode the function body of inline candidates is saved
into clone before compiling so the function in original form can be
inlined later. This pointer points to the clone. */
tree inline_decl;
}; };
struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller")))
...@@ -225,6 +230,7 @@ extern GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes_queue; ...@@ -225,6 +230,7 @@ extern GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes_queue;
/* In cgraph.c */ /* In cgraph.c */
void dump_cgraph (FILE *); void dump_cgraph (FILE *);
void dump_cgraph_node (FILE *, struct cgraph_node *); void dump_cgraph_node (FILE *, struct cgraph_node *);
void cgraph_insert_node_to_hashtable (struct cgraph_node *node);
void dump_varpool (FILE *); void dump_varpool (FILE *);
void dump_cgraph_varpool_node (FILE *, struct cgraph_varpool_node *); void dump_cgraph_varpool_node (FILE *, struct cgraph_varpool_node *);
void cgraph_remove_edge (struct cgraph_edge *); void cgraph_remove_edge (struct cgraph_edge *);
...@@ -281,6 +287,7 @@ void cgraph_reset_static_var_maps (void); ...@@ -281,6 +287,7 @@ void cgraph_reset_static_var_maps (void);
void init_cgraph (void); void init_cgraph (void);
struct cgraph_node *cgraph_function_versioning (struct cgraph_node *, struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
varray_type, varray_type); varray_type, varray_type);
struct cgraph_node *save_inline_function_body (struct cgraph_node *);
/* In ipa.c */ /* In ipa.c */
bool cgraph_remove_unreachable_nodes (bool, FILE *); bool cgraph_remove_unreachable_nodes (bool, FILE *);
......
...@@ -748,7 +748,8 @@ verify_cgraph_node (struct cgraph_node *node) ...@@ -748,7 +748,8 @@ verify_cgraph_node (struct cgraph_node *node)
debug_generic_stmt (stmt); debug_generic_stmt (stmt);
error_found = true; error_found = true;
} }
if (e->callee->decl != cgraph_node (decl)->decl) if (e->callee->decl != cgraph_node (decl)->decl
&& e->inline_failed)
{ {
error ("edge points to wrong declaration:"); error ("edge points to wrong declaration:");
debug_tree (e->callee->decl); debug_tree (e->callee->decl);
...@@ -1202,9 +1203,6 @@ bool ...@@ -1202,9 +1203,6 @@ bool
cgraph_preserve_function_body_p (tree decl) cgraph_preserve_function_body_p (tree decl)
{ {
struct cgraph_node *node; struct cgraph_node *node;
/* Keep the body; we're going to dump it. */
if (dump_enabled_p (TDI_tree_all))
return true;
if (!cgraph_global_info_ready) if (!cgraph_global_info_ready)
return (DECL_INLINE (decl) && !flag_really_no_inline); return (DECL_INLINE (decl) && !flag_really_no_inline);
/* Look if there is any clone around. */ /* Look if there is any clone around. */
...@@ -1504,7 +1502,7 @@ cgraph_function_versioning (struct cgraph_node *old_version_node, ...@@ -1504,7 +1502,7 @@ cgraph_function_versioning (struct cgraph_node *old_version_node,
redirect_callers); redirect_callers);
/* Copy the OLD_VERSION_NODE function tree to the new version. */ /* Copy the OLD_VERSION_NODE function tree to the new version. */
tree_function_versioning (old_decl, new_decl, tree_map); tree_function_versioning (old_decl, new_decl, tree_map, false);
/* Update the call_expr on the edges to call the new version node. */ /* Update the call_expr on the edges to call the new version node. */
update_call_expr (new_version_node); update_call_expr (new_version_node);
...@@ -1521,3 +1519,57 @@ cgraph_function_versioning (struct cgraph_node *old_version_node, ...@@ -1521,3 +1519,57 @@ cgraph_function_versioning (struct cgraph_node *old_version_node,
new_version_node->lowered = true; new_version_node->lowered = true;
return new_version_node; return new_version_node;
} }
/* Produce separate function body for inline clones so the offline copy can be
modified without affecting them. */
struct cgraph_node *
save_inline_function_body (struct cgraph_node *node)
{
struct cgraph_node *first_clone;
gcc_assert (node == cgraph_node (node->decl));
cgraph_lower_function (node);
/* In non-unit-at-a-time we construct full fledged clone we never output to
assembly file. This clone is pointed out by inline_decl of orginal function
and inlining infrastructure knows how to deal with this. */
if (!flag_unit_at_a_time)
{
struct cgraph_edge *e;
first_clone = cgraph_clone_node (node, node->count, 0, false);
first_clone->needed = 0;
first_clone->reachable = 1;
/* Recursively clone all bodies. */
for (e = first_clone->callees; e; e = e->next_callee)
if (!e->inline_failed)
cgraph_clone_inlined_nodes (e, true, false);
}
else
first_clone = node->next_clone;
first_clone->decl = copy_node (node->decl);
node->next_clone = NULL;
if (!flag_unit_at_a_time)
node->inline_decl = first_clone->decl;
first_clone->prev_clone = NULL;
cgraph_insert_node_to_hashtable (first_clone);
gcc_assert (first_clone == cgraph_node (first_clone->decl));
/* Copy the OLD_VERSION_NODE function tree to the new version. */
tree_function_versioning (node->decl, first_clone->decl, NULL, true);
DECL_EXTERNAL (first_clone->decl) = 0;
DECL_ONE_ONLY (first_clone->decl) = 0;
TREE_PUBLIC (first_clone->decl) = 0;
DECL_COMDAT (first_clone->decl) = 0;
for (node = first_clone->next_clone; node; node = node->next_clone)
node->decl = first_clone->decl;
#ifdef ENABLE_CHECKING
verify_cgraph_node (first_clone);
#endif
return first_clone;
}
...@@ -162,25 +162,14 @@ struct expr_status GTY(()) ...@@ -162,25 +162,14 @@ struct expr_status GTY(())
struct function GTY(()) struct function GTY(())
{ {
struct eh_status *eh; struct eh_status *eh;
struct eh_status *saved_eh;
struct expr_status *expr; struct expr_status *expr;
struct emit_status *emit; struct emit_status *emit;
struct varasm_status *varasm; struct varasm_status *varasm;
/* The control flow graph for this function. */ /* The control flow graph for this function. */
struct control_flow_graph *cfg; struct control_flow_graph *cfg;
struct control_flow_graph *saved_cfg;
bool after_inlining; bool after_inlining;
/* For tree-optimize.c. */
/* Saved tree and arguments during tree optimization. Used later for
inlining */
tree saved_args;
tree saved_static_chain_decl;
tree saved_blocks;
tree saved_unexpanded_var_list;
/* For function.c. */ /* For function.c. */
/* Points to the FUNCTION_DECL of this function. */ /* Points to the FUNCTION_DECL of this function. */
......
...@@ -158,6 +158,9 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original) ...@@ -158,6 +158,9 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original)
int old_insns = 0, new_insns = 0; int old_insns = 0, new_insns = 0;
struct cgraph_node *to = NULL, *what; struct cgraph_node *to = NULL, *what;
if (e->callee->inline_decl)
cgraph_redirect_edge_callee (e, cgraph_node (e->callee->inline_decl));
gcc_assert (e->inline_failed); gcc_assert (e->inline_failed);
e->inline_failed = NULL; e->inline_failed = NULL;
...@@ -283,21 +286,25 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what, ...@@ -283,21 +286,25 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
bool bool
cgraph_default_inline_p (struct cgraph_node *n, const char **reason) cgraph_default_inline_p (struct cgraph_node *n, const char **reason)
{ {
if (!DECL_INLINE (n->decl)) tree decl = n->decl;
if (n->inline_decl)
decl = n->inline_decl;
if (!DECL_INLINE (decl))
{ {
if (reason) if (reason)
*reason = N_("function not inlinable"); *reason = N_("function not inlinable");
return false; return false;
} }
if (!DECL_SAVED_TREE (n->decl)) if (!DECL_STRUCT_FUNCTION (decl)->cfg)
{ {
if (reason) if (reason)
*reason = N_("function body not available"); *reason = N_("function body not available");
return false; return false;
} }
if (DECL_DECLARED_INLINE_P (n->decl)) if (DECL_DECLARED_INLINE_P (decl))
{ {
if (n->global.insns >= MAX_INLINE_INSNS_SINGLE) if (n->global.insns >= MAX_INLINE_INSNS_SINGLE)
{ {
...@@ -1046,7 +1053,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early) ...@@ -1046,7 +1053,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early)
&& !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed) && !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
/* ??? It is possible that renaming variable removed the function body /* ??? It is possible that renaming variable removed the function body
in duplicate_decls. See gcc.c-torture/compile/20011119-2.c */ in duplicate_decls. See gcc.c-torture/compile/20011119-2.c */
&& DECL_SAVED_TREE (e->callee->decl)) && (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
{ {
if (dump_file && early) if (dump_file && early)
{ {
...@@ -1069,7 +1076,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early) ...@@ -1069,7 +1076,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early)
|| (cgraph_estimate_size_after_inlining (1, e->caller, node) || (cgraph_estimate_size_after_inlining (1, e->caller, node)
<= e->caller->global.insns)) <= e->caller->global.insns))
&& cgraph_check_inline_limits (node, e->callee, &e->inline_failed) && cgraph_check_inline_limits (node, e->callee, &e->inline_failed)
&& DECL_SAVED_TREE (e->callee->decl)) && (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
{ {
if (cgraph_default_inline_p (e->callee, &failed_reason)) if (cgraph_default_inline_p (e->callee, &failed_reason))
{ {
......
...@@ -111,9 +111,7 @@ typedef struct inline_data ...@@ -111,9 +111,7 @@ typedef struct inline_data
tree callee; tree callee;
/* FUNCTION_DECL for function being inlined into. */ /* FUNCTION_DECL for function being inlined into. */
tree caller; tree caller;
/* struct function for function being inlined. Usually this is the same /* struct function for function being inlined. */
as DECL_STRUCT_FUNCTION (callee), but can be different if saved_cfg
and saved_eh are in use. */
struct function *callee_cfun; struct function *callee_cfun;
/* The VAR_DECL for the return value. */ /* The VAR_DECL for the return value. */
tree retvar; tree retvar;
...@@ -125,10 +123,11 @@ typedef struct inline_data ...@@ -125,10 +123,11 @@ typedef struct inline_data
distinguish between those two situations. This flag is true if distinguish between those two situations. This flag is true if
we are cloning, rather than inlining. */ we are cloning, rather than inlining. */
bool cloning_p; bool cloning_p;
/* Similarly for saving function body. */
bool saving_p;
/* Versioning function is slightly different from inlining. */ /* Versioning function is slightly different from inlining. */
bool versioning_p; bool versioning_p;
/* If set, the call_stmt of edges in clones of caller functions will
be updated. */
bool update_clones_p;
/* Callgraph node of function we are inlining into. */ /* Callgraph node of function we are inlining into. */
struct cgraph_node *node; struct cgraph_node *node;
/* Callgraph node of currently inlined function. */ /* Callgraph node of currently inlined function. */
...@@ -750,46 +749,33 @@ copy_bb (inline_data *id, basic_block bb, int frequency_scale, int count_scale) ...@@ -750,46 +749,33 @@ copy_bb (inline_data *id, basic_block bb, int frequency_scale, int count_scale)
callgraph edges and update or duplicate them. */ callgraph edges and update or duplicate them. */
if (call && (decl = get_callee_fndecl (call))) if (call && (decl = get_callee_fndecl (call)))
{ {
if (id->saving_p) if (!id->versioning_p)
{
struct cgraph_node *node;
struct cgraph_edge *edge;
/* We're saving a copy of the body, so we'll update the
callgraph nodes in place. Note that we avoid
altering the original callgraph node; we begin with
the first clone. */
for (node = id->node->next_clone;
node;
node = node->next_clone)
{
edge = cgraph_edge (node, orig_stmt);
gcc_assert (edge);
edge->call_stmt = stmt;
}
}
else
{ {
struct cgraph_edge *edge; struct cgraph_edge *edge;
/* We're cloning or inlining this body; duplicate the /* We're cloning or inlining this body; duplicate the
associate callgraph nodes. */ associate callgraph nodes. */
if (!id->versioning_p) edge = cgraph_edge (id->current_node, orig_stmt);
{ if (edge)
edge = cgraph_edge (id->current_node, orig_stmt); cgraph_clone_edge (edge, id->node, stmt,
if (edge) REG_BR_PROB_BASE, 1, true);
cgraph_clone_edge (edge, id->node, stmt,
REG_BR_PROB_BASE, 1, true);
}
} }
if (id->versioning_p) else
{ {
/* Update the call_expr on the edges from the new version /* Update the call_expr on the edges from the new version
to its callees. */ to its callees. */
struct cgraph_edge *edge; struct cgraph_edge *edge;
edge = cgraph_edge (id->node, orig_stmt); edge = cgraph_edge (id->node, orig_stmt);
if (edge) if (edge)
edge->call_stmt = stmt; {
edge->call_stmt = stmt;
if (id->update_clones_p)
{
struct cgraph_node *n;
for (n = id->node->next_clone; n; n = n->next_clone)
cgraph_edge (n, orig_stmt)->call_stmt = stmt;
}
}
} }
} }
/* If you think we can abort here, you are wrong. /* If you think we can abort here, you are wrong.
...@@ -917,7 +903,7 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency, ...@@ -917,7 +903,7 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency,
(struct function *) ggc_alloc_cleared (sizeof (struct function)); (struct function *) ggc_alloc_cleared (sizeof (struct function));
basic_block bb; basic_block bb;
tree new_fndecl = NULL; tree new_fndecl = NULL;
bool saving_or_cloning; bool versioning_or_cloning;
int count_scale, frequency_scale; int count_scale, frequency_scale;
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count) if (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count)
...@@ -942,24 +928,14 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency, ...@@ -942,24 +928,14 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency,
*cfun_to_copy = *DECL_STRUCT_FUNCTION (callee_fndecl); *cfun_to_copy = *DECL_STRUCT_FUNCTION (callee_fndecl);
/* If there is a saved_cfg+saved_args lurking in the
struct function, a copy of the callee body was saved there, and
the 'struct cgraph edge' nodes have been fudged to point into the
saved body. Accordingly, we want to copy that saved body so the
callgraph edges will be recognized and cloned properly. */
if (cfun_to_copy->saved_cfg)
{
cfun_to_copy->cfg = cfun_to_copy->saved_cfg;
cfun_to_copy->eh = cfun_to_copy->saved_eh;
}
id->callee_cfun = cfun_to_copy; id->callee_cfun = cfun_to_copy;
/* If saving or cloning a function body, create new basic_block_info /* If saving or cloning a function body, create new basic_block_info
and label_to_block_maps. Otherwise, we're duplicating a function and label_to_block_maps. Otherwise, we're duplicating a function
body for inlining; insert our new blocks and labels into the body for inlining; insert our new blocks and labels into the
existing varrays. */ existing varrays. */
saving_or_cloning = (id->saving_p || id->cloning_p || id->versioning_p); versioning_or_cloning = (id->cloning_p || id->versioning_p);
if (saving_or_cloning) if (versioning_or_cloning)
{ {
new_cfun = new_cfun =
(struct function *) ggc_alloc_cleared (sizeof (struct function)); (struct function *) ggc_alloc_cleared (sizeof (struct function));
...@@ -995,7 +971,7 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency, ...@@ -995,7 +971,7 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency,
/* Duplicate any exception-handling regions. */ /* Duplicate any exception-handling regions. */
if (cfun->eh) if (cfun->eh)
{ {
if (saving_or_cloning) if (versioning_or_cloning)
init_eh_for_function (); init_eh_for_function ();
id->eh_region_offset = duplicate_eh_regions (cfun_to_copy, id->eh_region_offset = duplicate_eh_regions (cfun_to_copy,
remap_decl_1, remap_decl_1,
...@@ -1011,7 +987,7 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency, ...@@ -1011,7 +987,7 @@ copy_cfg_body (inline_data * id, gcov_type count, int frequency,
FOR_ALL_BB_FN (bb, cfun_to_copy) FOR_ALL_BB_FN (bb, cfun_to_copy)
bb->aux = NULL; bb->aux = NULL;
if (saving_or_cloning) if (versioning_or_cloning)
pop_cfun (); pop_cfun ();
return new_fndecl; return new_fndecl;
...@@ -1183,8 +1159,6 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain, ...@@ -1183,8 +1159,6 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain,
/* Figure out what the parameters are. */ /* Figure out what the parameters are. */
parms = DECL_ARGUMENTS (fn); parms = DECL_ARGUMENTS (fn);
if (fn == current_function_decl)
parms = cfun->saved_args;
/* Loop through the parameter declarations, replacing each with an /* Loop through the parameter declarations, replacing each with an
equivalent VAR_DECL, appropriately initialized. */ equivalent VAR_DECL, appropriately initialized. */
...@@ -1204,8 +1178,7 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain, ...@@ -1204,8 +1178,7 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain,
/* Initialize the static chain. */ /* Initialize the static chain. */
p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl; p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
if (fn == current_function_decl) gcc_assert (fn != current_function_decl);
p = DECL_STRUCT_FUNCTION (fn)->saved_static_chain_decl;
if (p) if (p)
{ {
/* No static chain? Seems like a bug in tree-nested.c. */ /* No static chain? Seems like a bug in tree-nested.c. */
...@@ -2039,6 +2012,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data) ...@@ -2039,6 +2012,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
} }
goto egress; goto egress;
} }
fn = cg_edge->callee->decl;
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
if (cg_edge->callee->decl != id->node->decl) if (cg_edge->callee->decl != id->node->decl)
...@@ -2095,9 +2069,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data) ...@@ -2095,9 +2069,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
/* Record the function we are about to inline. */ /* Record the function we are about to inline. */
id->callee = fn; id->callee = fn;
if (DECL_STRUCT_FUNCTION (fn)->saved_blocks) if (DECL_INITIAL (fn))
add_lexical_block (id->block, remap_blocks (DECL_STRUCT_FUNCTION (fn)->saved_blocks, id));
else if (DECL_INITIAL (fn))
add_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id)); add_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id));
/* Return statements in the function body will be replaced by jumps /* Return statements in the function body will be replaced by jumps
...@@ -2155,8 +2127,6 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data) ...@@ -2155,8 +2127,6 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
/* Add local vars in this inlined callee to caller. */ /* Add local vars in this inlined callee to caller. */
t_step = id->callee_cfun->unexpanded_var_list; t_step = id->callee_cfun->unexpanded_var_list;
if (id->callee_cfun->saved_unexpanded_var_list)
t_step = id->callee_cfun->saved_unexpanded_var_list;
for (; t_step; t_step = TREE_CHAIN (t_step)) for (; t_step; t_step = TREE_CHAIN (t_step))
{ {
var = TREE_VALUE (t_step); var = TREE_VALUE (t_step);
...@@ -2331,86 +2301,6 @@ clone_body (tree clone, tree fn, void *arg_map) ...@@ -2331,86 +2301,6 @@ clone_body (tree clone, tree fn, void *arg_map)
append_to_statement_list_force (copy_generic_body (&id), &DECL_SAVED_TREE (clone)); append_to_statement_list_force (copy_generic_body (&id), &DECL_SAVED_TREE (clone));
} }
/* Save duplicate body in FN. MAP is used to pass around splay tree
used to update arguments in restore_body. */
/* Make and return duplicate of body in FN. Put copies of DECL_ARGUMENTS
in *arg_copy and of the static chain, if any, in *sc_copy. */
void
save_body (tree fn, tree *arg_copy, tree *sc_copy)
{
inline_data id;
tree newdecl, *parg;
basic_block fn_entry_block;
tree t_step;
memset (&id, 0, sizeof (id));
id.callee = fn;
id.callee_cfun = DECL_STRUCT_FUNCTION (fn);
id.caller = fn;
id.node = cgraph_node (fn);
id.saving_p = true;
id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
*arg_copy = DECL_ARGUMENTS (fn);
for (parg = arg_copy; *parg; parg = &TREE_CHAIN (*parg))
{
tree new = copy_node (*parg);
lang_hooks.dup_lang_specific_decl (new);
DECL_ABSTRACT_ORIGIN (new) = DECL_ORIGIN (*parg);
insert_decl_map (&id, *parg, new);
TREE_CHAIN (new) = TREE_CHAIN (*parg);
*parg = new;
}
*sc_copy = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
if (*sc_copy)
{
tree new = copy_node (*sc_copy);
lang_hooks.dup_lang_specific_decl (new);
DECL_ABSTRACT_ORIGIN (new) = DECL_ORIGIN (*sc_copy);
insert_decl_map (&id, *sc_copy, new);
TREE_CHAIN (new) = TREE_CHAIN (*sc_copy);
*sc_copy = new;
}
/* We're not inside any EH region. */
id.eh_region = -1;
insert_decl_map (&id, DECL_RESULT (fn), DECL_RESULT (fn));
DECL_STRUCT_FUNCTION (fn)->saved_blocks
= remap_blocks (DECL_INITIAL (fn), &id);
for (t_step = id.callee_cfun->unexpanded_var_list;
t_step;
t_step = TREE_CHAIN (t_step))
{
tree var = TREE_VALUE (t_step);
if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
cfun->saved_unexpanded_var_list
= tree_cons (NULL_TREE, var, cfun->saved_unexpanded_var_list);
else
cfun->saved_unexpanded_var_list
= tree_cons (NULL_TREE, remap_decl (var, &id),
cfun->saved_unexpanded_var_list);
}
/* Actually copy the body, including a new (struct function *) and CFG.
EH info is also duplicated so its labels point into the copied
CFG, not the original. */
fn_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (fn));
newdecl = copy_body (&id, fn_entry_block->count, fn_entry_block->frequency,
NULL, NULL);
DECL_STRUCT_FUNCTION (fn)->saved_cfg = DECL_STRUCT_FUNCTION (newdecl)->cfg;
DECL_STRUCT_FUNCTION (fn)->saved_eh = DECL_STRUCT_FUNCTION (newdecl)->eh;
/* Clean up. */
splay_tree_delete (id.decl_map);
}
/* Passed to walk_tree. Copies the node pointed to, if appropriate. */ /* Passed to walk_tree. Copies the node pointed to, if appropriate. */
tree tree
...@@ -2807,9 +2697,11 @@ tree_versionable_function_p (tree fndecl) ...@@ -2807,9 +2697,11 @@ tree_versionable_function_p (tree fndecl)
respectively. In case we want to replace a DECL respectively. In case we want to replace a DECL
tree with another tree while duplicating the function's tree with another tree while duplicating the function's
body, TREE_MAP represents the mapping between these body, TREE_MAP represents the mapping between these
trees. */ trees. If UPDATE_CLONES is set, the call_stmt fields
of edges of clones of the function will be updated. */
void void
tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map) tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
bool update_clones)
{ {
struct cgraph_node *old_version_node; struct cgraph_node *old_version_node;
struct cgraph_node *new_version_node; struct cgraph_node *new_version_node;
...@@ -2835,8 +2727,9 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map) ...@@ -2835,8 +2727,9 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map)
DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl); DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl);
/* Generate a new name for the new version. */ /* Generate a new name for the new version. */
DECL_NAME (new_decl) = if (!update_clones)
create_tmp_var_name (NULL); DECL_NAME (new_decl) =
create_tmp_var_name (NULL);
/* Create a new SYMBOL_REF rtx for the new name. */ /* Create a new SYMBOL_REF rtx for the new name. */
if (DECL_RTL (old_decl) != NULL) if (DECL_RTL (old_decl) != NULL)
{ {
...@@ -2856,6 +2749,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map) ...@@ -2856,6 +2749,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map)
id.current_node = cgraph_node (old_decl); id.current_node = cgraph_node (old_decl);
id.versioning_p = true; id.versioning_p = true;
id.update_clones_p = update_clones;
id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
id.caller = new_decl; id.caller = new_decl;
id.callee = old_decl; id.callee = old_decl;
...@@ -2982,7 +2876,7 @@ replace_ref_tree (inline_data * id, tree * tp) ...@@ -2982,7 +2876,7 @@ replace_ref_tree (inline_data * id, tree * tp)
static inline bool static inline bool
inlining_p (inline_data * id) inlining_p (inline_data * id)
{ {
return (!id->saving_p && !id->cloning_p && !id->versioning_p); return (!id->cloning_p && !id->versioning_p);
} }
/* Duplicate a type, fields and all. */ /* Duplicate a type, fields and all. */
......
...@@ -35,7 +35,7 @@ void push_cfun (struct function *new_cfun); ...@@ -35,7 +35,7 @@ void push_cfun (struct function *new_cfun);
void pop_cfun (void); void pop_cfun (void);
int estimate_num_insns (tree expr); int estimate_num_insns (tree expr);
bool tree_versionable_function_p (tree); bool tree_versionable_function_p (tree);
void tree_function_versioning (tree, tree, varray_type); void tree_function_versioning (tree, tree, varray_type, bool);
/* Copy a declaration when one function is substituted inline into /* Copy a declaration when one function is substituted inline into
another. It is used also for versioning. */ another. It is used also for versioning. */
......
...@@ -348,12 +348,19 @@ void ...@@ -348,12 +348,19 @@ void
tree_rest_of_compilation (tree fndecl) tree_rest_of_compilation (tree fndecl)
{ {
location_t saved_loc; location_t saved_loc;
struct cgraph_node *saved_node = NULL, *node; struct cgraph_node *node;
timevar_push (TV_EXPAND); timevar_push (TV_EXPAND);
gcc_assert (!flag_unit_at_a_time || cgraph_global_info_ready); gcc_assert (!flag_unit_at_a_time || cgraph_global_info_ready);
node = cgraph_node (fndecl);
/* We might need the body of this function so that we can expand
it inline somewhere else. */
if (cgraph_preserve_function_body_p (fndecl))
save_inline_function_body (node);
/* Initialize the RTL code for the function. */ /* Initialize the RTL code for the function. */
current_function_decl = fndecl; current_function_decl = fndecl;
saved_loc = input_location; saved_loc = input_location;
...@@ -367,26 +374,6 @@ tree_rest_of_compilation (tree fndecl) ...@@ -367,26 +374,6 @@ tree_rest_of_compilation (tree fndecl)
cfun->x_dont_save_pending_sizes_p = 1; cfun->x_dont_save_pending_sizes_p = 1;
cfun->after_inlining = true; cfun->after_inlining = true;
node = cgraph_node (fndecl);
/* We might need the body of this function so that we can expand
it inline somewhere else. This means not lowering some constructs
such as exception handling. */
if (cgraph_preserve_function_body_p (fndecl))
{
if (!flag_unit_at_a_time)
{
struct cgraph_edge *e;
saved_node = cgraph_clone_node (node, node->count, 1, false);
for (e = saved_node->callees; e; e = e->next_callee)
if (!e->inline_failed)
cgraph_clone_inlined_nodes (e, true, false);
}
cfun->saved_static_chain_decl = cfun->static_chain_decl;
save_body (fndecl, &cfun->saved_args, &cfun->saved_static_chain_decl);
}
if (flag_inline_trees) if (flag_inline_trees)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
...@@ -429,40 +416,7 @@ tree_rest_of_compilation (tree fndecl) ...@@ -429,40 +416,7 @@ tree_rest_of_compilation (tree fndecl)
/* Release the default bitmap obstack. */ /* Release the default bitmap obstack. */
bitmap_obstack_release (NULL); bitmap_obstack_release (NULL);
/* Restore original body if still needed. */ DECL_SAVED_TREE (fndecl) = NULL;
if (cfun->saved_cfg)
{
DECL_ARGUMENTS (fndecl) = cfun->saved_args;
cfun->cfg = cfun->saved_cfg;
cfun->eh = cfun->saved_eh;
DECL_INITIAL (fndecl) = cfun->saved_blocks;
cfun->unexpanded_var_list = cfun->saved_unexpanded_var_list;
cfun->saved_cfg = NULL;
cfun->saved_eh = NULL;
cfun->saved_args = NULL_TREE;
cfun->saved_blocks = NULL_TREE;
cfun->saved_unexpanded_var_list = NULL_TREE;
cfun->static_chain_decl = cfun->saved_static_chain_decl;
cfun->saved_static_chain_decl = NULL;
/* When not in unit-at-a-time mode, we must preserve out of line copy
representing node before inlining. Restore original outgoing edges
using clone we created earlier. */
if (!flag_unit_at_a_time)
{
struct cgraph_edge *e;
node = cgraph_node (current_function_decl);
cgraph_node_remove_callees (node);
node->callees = saved_node->callees;
saved_node->callees = NULL;
update_inlined_to_pointers (node, node);
for (e = node->callees; e; e = e->next_callee)
e->caller = node;
cgraph_remove_node (saved_node);
}
}
else
DECL_SAVED_TREE (fndecl) = NULL;
cfun = 0; cfun = 0;
/* If requested, warn about function definitions where the function will /* If requested, warn about function definitions where the function will
......
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