This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Kill function body saving code
- From: Jan Hubicka <jh at suse dot cz>
- To: Eric Christopher <echristo at apple dot com>, gcc-patches at gcc dot gnu dot org
- Cc: Jan Hubicka <jh at suse dot cz>
- Date: Sun, 27 Nov 2005 16:06:20 +0100
- Subject: Re: [PATCH] Kill function body saving code
- References: <20051126005520.GP15183@kam.mff.cuni.cz> <045113BF-BB64-4D1B-9309-E4BA2DB5372B@apple.com>
> >
> >Bootstrapped/regtested i686-pc-gnu-linux, ppc-linux in progress, OK?
>
> Awesome, I was wondering if you were going to do this :)
>
> Next time you put a patch up, for ease of reading can you please diff
> without
> whitespace changes? There are a number of lines in the patch that have
> zero changes, but are in the diff :)
Well, looking into diff, I found only one such accidental whitespace
change, but here is fixed patch. I also fixed one occurence of line
longer than 80 characters.
* 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.
Index: cgraph.c
===================================================================
*** cgraph.c (revision 107562)
--- cgraph.c (working copy)
*************** cgraph_node (tree decl)
*** 213,218 ****
--- 213,231 ----
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. */
static bool
Index: cgraph.h
===================================================================
*** cgraph.h (revision 107562)
--- cgraph.h (working copy)
*************** struct cgraph_node GTY((chain_next ("%h.
*** 161,166 ****
--- 161,171 ----
bool externally_visible;
/* Set for aliases once they got through assemble_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")))
*************** extern GTY(()) struct cgraph_varpool_nod
*** 225,230 ****
--- 230,236 ----
/* In cgraph.c */
void dump_cgraph (FILE *);
void dump_cgraph_node (FILE *, struct cgraph_node *);
+ void cgraph_insert_node_to_hashtable (struct cgraph_node *node);
void dump_varpool (FILE *);
void dump_cgraph_varpool_node (FILE *, struct cgraph_varpool_node *);
void cgraph_remove_edge (struct cgraph_edge *);
*************** void cgraph_reset_static_var_maps (void)
*** 281,286 ****
--- 287,293 ----
void init_cgraph (void);
struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
varray_type, varray_type);
+ struct cgraph_node *save_inline_function_body (struct cgraph_node *);
/* In ipa.c */
bool cgraph_remove_unreachable_nodes (bool, FILE *);
Index: cgraphunit.c
===================================================================
*** cgraphunit.c (revision 107562)
--- cgraphunit.c (working copy)
*************** verify_cgraph_node (struct cgraph_node *
*** 748,754 ****
debug_generic_stmt (stmt);
error_found = true;
}
! if (e->callee->decl != cgraph_node (decl)->decl)
{
error ("edge points to wrong declaration:");
debug_tree (e->callee->decl);
--- 748,755 ----
debug_generic_stmt (stmt);
error_found = true;
}
! if (e->callee->decl != cgraph_node (decl)->decl
! && e->inline_failed)
{
error ("edge points to wrong declaration:");
debug_tree (e->callee->decl);
*************** bool
*** 1202,1210 ****
cgraph_preserve_function_body_p (tree decl)
{
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)
return (DECL_INLINE (decl) && !flag_really_no_inline);
/* Look if there is any clone around. */
--- 1203,1208 ----
*************** cgraph_function_versioning (struct cgrap
*** 1504,1510 ****
redirect_callers);
/* Copy the OLD_VERSION_NODE function tree to the new version. */
! tree_function_versioning (old_decl, new_decl, tree_map);
/* Update the call_expr on the edges to call the new version node. */
update_call_expr (new_version_node);
--- 1502,1508 ----
redirect_callers);
/* Copy the OLD_VERSION_NODE function tree to the new version. */
! tree_function_versioning (old_decl, new_decl, tree_map, false);
/* Update the call_expr on the edges to call the new version node. */
update_call_expr (new_version_node);
*************** cgraph_function_versioning (struct cgrap
*** 1521,1523 ****
--- 1519,1575 ----
new_version_node->lowered = true;
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;
+ }
+
Index: ipa-inline.c
===================================================================
*** ipa-inline.c (revision 107562)
--- ipa-inline.c (working copy)
*************** cgraph_mark_inline_edge (struct cgraph_e
*** 156,161 ****
--- 156,164 ----
int old_insns = 0, new_insns = 0;
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);
e->inline_failed = NULL;
*************** cgraph_check_inline_limits (struct cgrap
*** 281,301 ****
bool
cgraph_default_inline_p (struct cgraph_node *n, const char **reason)
{
! if (!DECL_INLINE (n->decl))
{
if (reason)
*reason = N_("function not inlinable");
return false;
}
! if (!DECL_SAVED_TREE (n->decl))
{
if (reason)
*reason = N_("function body not available");
return false;
}
! if (DECL_DECLARED_INLINE_P (n->decl))
{
if (n->global.insns >= MAX_INLINE_INSNS_SINGLE)
{
--- 284,308 ----
bool
cgraph_default_inline_p (struct cgraph_node *n, const char **reason)
{
! tree decl = n->decl;
!
! if (n->inline_decl)
! decl = n->inline_decl;
! if (!DECL_INLINE (decl))
{
if (reason)
*reason = N_("function not inlinable");
return false;
}
! if (!DECL_STRUCT_FUNCTION (decl)->cfg)
{
if (reason)
*reason = N_("function body not available");
return false;
}
! if (DECL_DECLARED_INLINE_P (decl))
{
if (n->global.insns >= MAX_INLINE_INSNS_SINGLE)
{
*************** cgraph_decide_inlining_incrementally (st
*** 1044,1050 ****
&& !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
/* ??? It is possible that renaming variable removed the function body
in duplicate_decls. See gcc.c-torture/compile/20011119-2.c */
! && DECL_SAVED_TREE (e->callee->decl))
{
if (dump_file && early)
{
--- 1051,1057 ----
&& !cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed)
/* ??? It is possible that renaming variable removed the function body
in duplicate_decls. See gcc.c-torture/compile/20011119-2.c */
! && (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
{
if (dump_file && early)
{
*************** cgraph_decide_inlining_incrementally (st
*** 1067,1073 ****
|| (cgraph_estimate_size_after_inlining (1, e->caller, node)
<= e->caller->global.insns))
&& cgraph_check_inline_limits (node, e->callee, &e->inline_failed)
! && DECL_SAVED_TREE (e->callee->decl))
{
if (cgraph_default_inline_p (e->callee, &failed_reason))
{
--- 1074,1080 ----
|| (cgraph_estimate_size_after_inlining (1, e->caller, node)
<= e->caller->global.insns))
&& cgraph_check_inline_limits (node, e->callee, &e->inline_failed)
! && (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
{
if (cgraph_default_inline_p (e->callee, &failed_reason))
{
Index: function.h
===================================================================
*** function.h (revision 107562)
--- function.h (working copy)
*************** struct expr_status GTY(())
*** 162,185 ****
struct function GTY(())
{
struct eh_status *eh;
- struct eh_status *saved_eh;
struct expr_status *expr;
struct emit_status *emit;
struct varasm_status *varasm;
/* The control flow graph for this function. */
struct control_flow_graph *cfg;
- struct control_flow_graph *saved_cfg;
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. */
--- 162,174 ----
Index: tree-inline.c
===================================================================
*** tree-inline.c (revision 107562)
--- tree-inline.c (working copy)
*************** typedef struct inline_data
*** 111,119 ****
tree callee;
/* FUNCTION_DECL for function being inlined into. */
tree caller;
! /* struct function for function being inlined. Usually this is the same
! as DECL_STRUCT_FUNCTION (callee), but can be different if saved_cfg
! and saved_eh are in use. */
struct function *callee_cfun;
/* The VAR_DECL for the return value. */
tree retvar;
--- 111,117 ----
tree callee;
/* FUNCTION_DECL for function being inlined into. */
tree caller;
! /* struct function for function being inlined. */
struct function *callee_cfun;
/* The VAR_DECL for the return value. */
tree retvar;
*************** typedef struct inline_data
*** 125,134 ****
distinguish between those two situations. This flag is true if
we are cloning, rather than inlining. */
bool cloning_p;
- /* Similarly for saving function body. */
- bool saving_p;
/* Versioning function is slightly different from inlining. */
bool versioning_p;
/* Callgraph node of function we are inlining into. */
struct cgraph_node *node;
/* Callgraph node of currently inlined function. */
--- 123,131 ----
distinguish between those two situations. This flag is true if
we are cloning, rather than inlining. */
bool cloning_p;
/* Versioning function is slightly different from inlining. */
bool versioning_p;
+ bool update_clones_p;
/* Callgraph node of function we are inlining into. */
struct cgraph_node *node;
/* Callgraph node of currently inlined function. */
*************** copy_bb (inline_data *id, basic_block bb
*** 749,794 ****
callgraph edges and update or duplicate them. */
if (call && (decl = get_callee_fndecl (call)))
{
! if (id->saving_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;
/* We're cloning or inlining this body; duplicate the
associate callgraph nodes. */
! if (!id->versioning_p)
! {
! edge = cgraph_edge (id->current_node, orig_stmt);
! if (edge)
! cgraph_clone_edge (edge, id->node, stmt,
! REG_BR_PROB_BASE, 1, true);
! }
}
! if (id->versioning_p)
{
/* Update the call_expr on the edges from the new version
to its callees. */
struct cgraph_edge *edge;
edge = cgraph_edge (id->node, orig_stmt);
if (edge)
! edge->call_stmt = stmt;
}
}
/* If you think we can abort here, you are wrong.
--- 746,778 ----
callgraph edges and update or duplicate them. */
if (call && (decl = get_callee_fndecl (call)))
{
! if (!id->versioning_p)
{
struct cgraph_edge *edge;
/* We're cloning or inlining this body; duplicate the
associate callgraph nodes. */
! edge = cgraph_edge (id->current_node, orig_stmt);
! if (edge)
! cgraph_clone_edge (edge, id->node, stmt,
! REG_BR_PROB_BASE, 1, true);
}
! else
{
/* Update the call_expr on the edges from the new version
to its callees. */
struct cgraph_edge *edge;
edge = cgraph_edge (id->node, orig_stmt);
if (edge)
! {
! 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.
*************** copy_cfg_body (inline_data * id, gcov_ty
*** 916,922 ****
(struct function *) ggc_alloc_cleared (sizeof (struct function));
basic_block bb;
tree new_fndecl = NULL;
! bool saving_or_cloning;
int count_scale, frequency_scale;
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count)
--- 900,906 ----
(struct function *) ggc_alloc_cleared (sizeof (struct function));
basic_block bb;
tree new_fndecl = NULL;
! bool versioning_or_cloning;
int count_scale, frequency_scale;
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count)
*************** copy_cfg_body (inline_data * id, gcov_ty
*** 941,964 ****
*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;
/* If saving or cloning a function body, create new basic_block_info
and label_to_block_maps. Otherwise, we're duplicating a function
body for inlining; insert our new blocks and labels into the
existing varrays. */
! saving_or_cloning = (id->saving_p || id->cloning_p || id->versioning_p);
! if (saving_or_cloning)
{
new_cfun =
(struct function *) ggc_alloc_cleared (sizeof (struct function));
--- 925,938 ----
*cfun_to_copy = *DECL_STRUCT_FUNCTION (callee_fndecl);
id->callee_cfun = cfun_to_copy;
/* If saving or cloning a function body, create new basic_block_info
and label_to_block_maps. Otherwise, we're duplicating a function
body for inlining; insert our new blocks and labels into the
existing varrays. */
! versioning_or_cloning = (id->cloning_p || id->versioning_p);
! if (versioning_or_cloning)
{
new_cfun =
(struct function *) ggc_alloc_cleared (sizeof (struct function));
*************** copy_cfg_body (inline_data * id, gcov_ty
*** 994,1000 ****
/* Duplicate any exception-handling regions. */
if (cfun->eh)
{
! if (saving_or_cloning)
init_eh_for_function ();
id->eh_region_offset = duplicate_eh_regions (cfun_to_copy,
remap_decl_1,
--- 968,974 ----
/* Duplicate any exception-handling regions. */
if (cfun->eh)
{
! if (versioning_or_cloning)
init_eh_for_function ();
id->eh_region_offset = duplicate_eh_regions (cfun_to_copy,
remap_decl_1,
*************** copy_cfg_body (inline_data * id, gcov_ty
*** 1010,1016 ****
FOR_ALL_BB_FN (bb, cfun_to_copy)
bb->aux = NULL;
! if (saving_or_cloning)
pop_cfun ();
return new_fndecl;
--- 984,990 ----
FOR_ALL_BB_FN (bb, cfun_to_copy)
bb->aux = NULL;
! if (versioning_or_cloning)
pop_cfun ();
return new_fndecl;
*************** initialize_inlined_parameters (inline_da
*** 1182,1189 ****
/* Figure out what the parameters are. */
parms = DECL_ARGUMENTS (fn);
- if (fn == current_function_decl)
- parms = cfun->saved_args;
/* Loop through the parameter declarations, replacing each with an
equivalent VAR_DECL, appropriately initialized. */
--- 1156,1161 ----
*************** initialize_inlined_parameters (inline_da
*** 1203,1210 ****
/* Initialize the static chain. */
p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
! if (fn == current_function_decl)
! p = DECL_STRUCT_FUNCTION (fn)->saved_static_chain_decl;
if (p)
{
/* No static chain? Seems like a bug in tree-nested.c. */
--- 1175,1181 ----
/* Initialize the static chain. */
p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
! gcc_assert (fn != current_function_decl);
if (p)
{
/* No static chain? Seems like a bug in tree-nested.c. */
*************** expand_call_inline (basic_block bb, tree
*** 2038,2043 ****
--- 2009,2015 ----
}
goto egress;
}
+ fn = cg_edge->callee->decl;
#ifdef ENABLE_CHECKING
if (cg_edge->callee->decl != id->node->decl)
*************** expand_call_inline (basic_block bb, tree
*** 2094,2102 ****
/* Record the function we are about to inline. */
id->callee = fn;
! if (DECL_STRUCT_FUNCTION (fn)->saved_blocks)
! 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));
/* Return statements in the function body will be replaced by jumps
--- 2066,2072 ----
/* Record the function we are about to inline. */
id->callee = fn;
! if (DECL_INITIAL (fn))
add_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id));
/* Return statements in the function body will be replaced by jumps
*************** expand_call_inline (basic_block bb, tree
*** 2154,2161 ****
/* Add local vars in this inlined callee to caller. */
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))
{
var = TREE_VALUE (t_step);
--- 2124,2129 ----
*************** clone_body (tree clone, tree fn, void *a
*** 2330,2415 ****
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. */
tree
--- 2298,2303 ----
*************** tree_versionable_function_p (tree fndecl
*** 2808,2814 ****
body, TREE_MAP represents the mapping between these
trees. */
void
! tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map)
{
struct cgraph_node *old_version_node;
struct cgraph_node *new_version_node;
--- 2696,2703 ----
body, TREE_MAP represents the mapping between these
trees. */
void
! 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 *new_version_node;
*************** tree_function_versioning (tree old_decl,
*** 2834,2841 ****
DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl);
/* Generate a new name for the new version. */
! DECL_NAME (new_decl) =
! create_tmp_var_name (NULL);
/* Create a new SYMBOL_REF rtx for the new name. */
if (DECL_RTL (old_decl) != NULL)
{
--- 2723,2731 ----
DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl);
/* Generate a new name for the new version. */
! if (!update_clones)
! DECL_NAME (new_decl) =
! create_tmp_var_name (NULL);
/* Create a new SYMBOL_REF rtx for the new name. */
if (DECL_RTL (old_decl) != NULL)
{
*************** tree_function_versioning (tree old_decl,
*** 2855,2860 ****
--- 2745,2751 ----
id.current_node = cgraph_node (old_decl);
id.versioning_p = true;
+ id.update_clones_p = update_clones;
id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
id.caller = new_decl;
id.callee = old_decl;
*************** replace_ref_tree (inline_data * id, tree
*** 2981,2987 ****
static inline bool
inlining_p (inline_data * id)
{
! return (!id->saving_p && !id->cloning_p && !id->versioning_p);
}
/* Duplicate a type, fields and all. */
--- 2872,2878 ----
static inline bool
inlining_p (inline_data * id)
{
! return (!id->cloning_p && !id->versioning_p);
}
/* Duplicate a type, fields and all. */
Index: tree-inline.h
===================================================================
*** tree-inline.h (revision 107562)
--- tree-inline.h (working copy)
*************** void push_cfun (struct function *new_cfu
*** 35,41 ****
void pop_cfun (void);
int estimate_num_insns (tree expr);
bool tree_versionable_function_p (tree);
! void tree_function_versioning (tree, tree, varray_type);
/* Copy a declaration when one function is substituted inline into
another. It is used also for versioning. */
--- 35,41 ----
void pop_cfun (void);
int estimate_num_insns (tree expr);
bool tree_versionable_function_p (tree);
! void tree_function_versioning (tree, tree, varray_type, bool);
/* Copy a declaration when one function is substituted inline into
another. It is used also for versioning. */
Index: tree-optimize.c
===================================================================
*** tree-optimize.c (revision 107562)
--- tree-optimize.c (working copy)
*************** void
*** 342,353 ****
tree_rest_of_compilation (tree fndecl)
{
location_t saved_loc;
! struct cgraph_node *saved_node = NULL, *node;
timevar_push (TV_EXPAND);
gcc_assert (!flag_unit_at_a_time || cgraph_global_info_ready);
/* Initialize the RTL code for the function. */
current_function_decl = fndecl;
saved_loc = input_location;
--- 342,361 ----
tree_rest_of_compilation (tree fndecl)
{
location_t saved_loc;
! struct cgraph_node *node;
timevar_push (TV_EXPAND);
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. This means not lowering some constructs
+ such as exception handling. */
+ if (cgraph_preserve_function_body_p (fndecl))
+ save_inline_function_body (node);
+
/* Initialize the RTL code for the function. */
current_function_decl = fndecl;
saved_loc = input_location;
*************** tree_rest_of_compilation (tree fndecl)
*** 361,386 ****
cfun->x_dont_save_pending_sizes_p = 1;
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)
{
struct cgraph_edge *e;
--- 369,374 ----
*************** tree_rest_of_compilation (tree fndecl)
*** 423,462 ****
/* Release the default bitmap obstack. */
bitmap_obstack_release (NULL);
! /* Restore original body if still needed. */
! 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;
/* If requested, warn about function definitions where the function will
--- 411,417 ----
/* Release the default bitmap obstack. */
bitmap_obstack_release (NULL);
! DECL_SAVED_TREE (fndecl) = NULL;
cfun = 0;
/* If requested, warn about function definitions where the function will