tree-inline.c (remap_ssa_name): New function.
* tree-inline.c (remap_ssa_name): New function. (remap_decl): Update SSA datastructures for DECLs. (copy_body_r): Deal with SSA_NAMEs; add referenced global vars. (copy_bb): Set SSA_NAME def stmts. (update_ssa_acorss_eh_edges): New function. (copy_edge_for_bb): Call it; mark new vars for renaming. (copy_phis_for_bb): New function. (initialize_cfun): Break out from ... (copy_cfg_body): ... here; maintain AUX map for both directions; call SSA updating workers; do not produce copy of cfun to be copied. (setup_one_parameter): Do propagation across SSA form. (declare_return_variable): Work on SSA; use return_slot instead of address of return slot of argument to avoid folding back and forth. (expand_call_inline): Update SSA from on return values. (optimize_inline_calls): Do sanity checking, dead blocks removal, update SSA form. (tree_function_verioning): Update initialize_cfun. From-SVN: r120260
This commit is contained in:
parent
9d30f270db
commit
110cfe1cdc
2 changed files with 524 additions and 143 deletions
|
@ -1,3 +1,23 @@
|
|||
2006-12-29 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* tree-inline.c (remap_ssa_name): New function.
|
||||
(remap_decl): Update SSA datastructures for DECLs.
|
||||
(copy_body_r): Deal with SSA_NAMEs; add referenced global vars.
|
||||
(copy_bb): Set SSA_NAME def stmts.
|
||||
(update_ssa_acorss_eh_edges): New function.
|
||||
(copy_edge_for_bb): Call it; mark new vars for renaming.
|
||||
(copy_phis_for_bb): New function.
|
||||
(initialize_cfun): Break out from ...
|
||||
(copy_cfg_body): ... here; maintain AUX map for both directions;
|
||||
call SSA updating workers; do not produce copy of cfun to be copied.
|
||||
(setup_one_parameter): Do propagation across SSA form.
|
||||
(declare_return_variable): Work on SSA; use return_slot instead of
|
||||
address of return slot of argument to avoid folding back and forth.
|
||||
(expand_call_inline): Update SSA from on return values.
|
||||
(optimize_inline_calls): Do sanity checking, dead blocks removal,
|
||||
update SSA form.
|
||||
(tree_function_verioning): Update initialize_cfun.
|
||||
|
||||
2006-12-29 Marcin Dalecki <martin@dalecki.de>
|
||||
|
||||
* doc/invoke.texi: Replace no longer supported -fno-strength-reduce
|
||||
|
|
|
@ -50,6 +50,7 @@ Boston, MA 02110-1301, USA. */
|
|||
#include "pointer-set.h"
|
||||
#include "ipa-prop.h"
|
||||
#include "value-prof.h"
|
||||
#include "tree-pass.h"
|
||||
|
||||
/* I'm not real happy about this, but we need to handle gimple and
|
||||
non-gimple trees. */
|
||||
|
@ -141,6 +142,50 @@ insert_decl_map (copy_body_data *id, tree key, tree value)
|
|||
(splay_tree_value) value);
|
||||
}
|
||||
|
||||
/* Construct new SSA name for old NAME. ID is the inline context. */
|
||||
|
||||
static tree
|
||||
remap_ssa_name (tree name, copy_body_data *id)
|
||||
{
|
||||
tree new;
|
||||
splay_tree_node n;
|
||||
|
||||
gcc_assert (TREE_CODE (name) == SSA_NAME);
|
||||
|
||||
n = splay_tree_lookup (id->decl_map, (splay_tree_key) name);
|
||||
if (n)
|
||||
return (tree) n->value;
|
||||
|
||||
/* Do not set DEF_STMT yet as statement is not copied yet. We do that
|
||||
in copy_bb. */
|
||||
new = remap_decl (SSA_NAME_VAR (name), id);
|
||||
/* We might've substituted constant or another SSA_NAME for
|
||||
the variable.
|
||||
|
||||
Replace the SSA name representing RESULT_DECL by variable during
|
||||
inlining: this saves us from need to introduce PHI node in a case
|
||||
return value is just partly initialized. */
|
||||
if ((TREE_CODE (new) == VAR_DECL || TREE_CODE (new) == PARM_DECL)
|
||||
&& (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
|
||||
|| !id->transform_return_to_modify))
|
||||
{
|
||||
new = make_ssa_name (new, NULL);
|
||||
insert_decl_map (id, name, new);
|
||||
if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name)))
|
||||
{
|
||||
SSA_NAME_DEF_STMT (new) = build_empty_stmt ();
|
||||
if (gimple_default_def (id->src_cfun, SSA_NAME_VAR (name)) == name)
|
||||
set_default_def (SSA_NAME_VAR (new), new);
|
||||
}
|
||||
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new)
|
||||
= SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
|
||||
TREE_TYPE (new) = TREE_TYPE (SSA_NAME_VAR (new));
|
||||
}
|
||||
else
|
||||
insert_decl_map (id, name, new);
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Remap DECL during the copying of the BLOCK tree for the function. */
|
||||
|
||||
tree
|
||||
|
@ -188,6 +233,22 @@ remap_decl (tree decl, copy_body_data *id)
|
|||
walk_tree (&DECL_QUALIFIER (t), copy_body_r, id, NULL);
|
||||
}
|
||||
|
||||
if (cfun && gimple_in_ssa_p (cfun)
|
||||
&& (TREE_CODE (t) == VAR_DECL
|
||||
|| TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
|
||||
{
|
||||
tree def = gimple_default_def (id->src_cfun, decl);
|
||||
get_var_ann (t);
|
||||
if (TREE_CODE (decl) != PARM_DECL && def)
|
||||
{
|
||||
tree map = remap_ssa_name (def, id);
|
||||
/* Watch out RESULT_DECLs whose SSA names map directly
|
||||
to them. */
|
||||
if (TREE_CODE (map) == SSA_NAME)
|
||||
set_default_def (t, map);
|
||||
}
|
||||
add_referenced_var (t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -500,6 +561,12 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
|
|||
return (tree) (void *)1;
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (*tp) == SSA_NAME)
|
||||
{
|
||||
*tp = remap_ssa_name (*tp, id);
|
||||
*walk_subtrees = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Local variables and labels need to be replaced by equivalent
|
||||
variables. We don't want to copy static variables; there's only
|
||||
|
@ -621,6 +688,11 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
|
|||
/* Here is the "usual case". Copy this tree node, and then
|
||||
tweak some special cases. */
|
||||
copy_tree_r (tp, walk_subtrees, NULL);
|
||||
|
||||
/* Global variables we didn't seen yet needs to go into referenced
|
||||
vars. */
|
||||
if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL)
|
||||
add_referenced_var (*tp);
|
||||
|
||||
/* If EXPR has block defined, map it to newly constructed block.
|
||||
When inlining we want EXPRs without block appear in the block
|
||||
|
@ -718,74 +790,132 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
|
|||
gimplify_stmt (&stmt);
|
||||
|
||||
bsi_insert_after (©_bsi, stmt, BSI_NEW_STMT);
|
||||
call = get_call_expr_in (stmt);
|
||||
/* We're duplicating a CALL_EXPR. Find any corresponding
|
||||
callgraph edges and update or duplicate them. */
|
||||
if (call && (decl = get_callee_fndecl (call)))
|
||||
|
||||
/* Process new statement. gimplify_stmt possibly turned statement
|
||||
into multiple statements, we need to process all of them. */
|
||||
while (!bsi_end_p (copy_bsi))
|
||||
{
|
||||
struct cgraph_node *node;
|
||||
struct cgraph_edge *edge;
|
||||
|
||||
switch (id->transform_call_graph_edges)
|
||||
stmt = bsi_stmt (copy_bsi);
|
||||
call = get_call_expr_in (stmt);
|
||||
/* We're duplicating a CALL_EXPR. Find any corresponding
|
||||
callgraph edges and update or duplicate them. */
|
||||
if (call && (decl = get_callee_fndecl (call)))
|
||||
{
|
||||
case CB_CGE_DUPLICATE:
|
||||
edge = cgraph_edge (id->src_node, orig_stmt);
|
||||
if (edge)
|
||||
cgraph_clone_edge (edge, id->dst_node, stmt,
|
||||
REG_BR_PROB_BASE, 1, true);
|
||||
break;
|
||||
|
||||
case CB_CGE_MOVE_CLONES:
|
||||
for (node = id->dst_node->next_clone;
|
||||
node;
|
||||
node = node->next_clone)
|
||||
struct cgraph_node *node;
|
||||
struct cgraph_edge *edge;
|
||||
|
||||
switch (id->transform_call_graph_edges)
|
||||
{
|
||||
edge = cgraph_edge (node, orig_stmt);
|
||||
gcc_assert (edge);
|
||||
cgraph_set_call_stmt (edge, stmt);
|
||||
case CB_CGE_DUPLICATE:
|
||||
edge = cgraph_edge (id->src_node, orig_stmt);
|
||||
if (edge)
|
||||
cgraph_clone_edge (edge, id->dst_node, stmt,
|
||||
REG_BR_PROB_BASE, 1, true);
|
||||
break;
|
||||
|
||||
case CB_CGE_MOVE_CLONES:
|
||||
for (node = id->dst_node->next_clone;
|
||||
node;
|
||||
node = node->next_clone)
|
||||
{
|
||||
edge = cgraph_edge (node, orig_stmt);
|
||||
gcc_assert (edge);
|
||||
cgraph_set_call_stmt (edge, stmt);
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
||||
case CB_CGE_MOVE:
|
||||
edge = cgraph_edge (id->dst_node, orig_stmt);
|
||||
if (edge)
|
||||
cgraph_set_call_stmt (edge, stmt);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
||||
case CB_CGE_MOVE:
|
||||
edge = cgraph_edge (id->dst_node, orig_stmt);
|
||||
if (edge)
|
||||
cgraph_set_call_stmt (edge, stmt);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
/* If you think we can abort here, you are wrong.
|
||||
There is no region 0 in tree land. */
|
||||
gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt)
|
||||
!= 0);
|
||||
/* If you think we can abort here, you are wrong.
|
||||
There is no region 0 in tree land. */
|
||||
gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt)
|
||||
!= 0);
|
||||
|
||||
if (tree_could_throw_p (stmt))
|
||||
{
|
||||
int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
|
||||
/* Add an entry for the copied tree in the EH hashtable.
|
||||
When cloning or versioning, use the hashtable in
|
||||
cfun, and just copy the EH number. When inlining, use the
|
||||
hashtable in the caller, and adjust the region number. */
|
||||
if (region > 0)
|
||||
add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
|
||||
if (tree_could_throw_p (stmt))
|
||||
{
|
||||
int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
|
||||
/* Add an entry for the copied tree in the EH hashtable.
|
||||
When cloning or versioning, use the hashtable in
|
||||
cfun, and just copy the EH number. When inlining, use the
|
||||
hashtable in the caller, and adjust the region number. */
|
||||
if (region > 0)
|
||||
add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
|
||||
|
||||
/* If this tree doesn't have a region associated with it,
|
||||
and there is a "current region,"
|
||||
then associate this tree with the current region
|
||||
and add edges associated with this region. */
|
||||
if ((lookup_stmt_eh_region_fn (id->src_cfun,
|
||||
orig_stmt) <= 0
|
||||
&& id->eh_region > 0)
|
||||
&& tree_could_throw_p (stmt))
|
||||
add_stmt_to_eh_region (stmt, id->eh_region);
|
||||
/* If this tree doesn't have a region associated with it,
|
||||
and there is a "current region,"
|
||||
then associate this tree with the current region
|
||||
and add edges associated with this region. */
|
||||
if ((lookup_stmt_eh_region_fn (id->src_cfun,
|
||||
orig_stmt) <= 0
|
||||
&& id->eh_region > 0)
|
||||
&& tree_could_throw_p (stmt))
|
||||
add_stmt_to_eh_region (stmt, id->eh_region);
|
||||
}
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
{
|
||||
ssa_op_iter i;
|
||||
tree def;
|
||||
|
||||
find_new_referenced_vars (bsi_stmt_ptr (copy_bsi));
|
||||
FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_DEF)
|
||||
if (TREE_CODE (def) == SSA_NAME)
|
||||
SSA_NAME_DEF_STMT (def) = stmt;
|
||||
}
|
||||
bsi_next (©_bsi);
|
||||
}
|
||||
copy_bsi = bsi_last (copy_basic_block);
|
||||
}
|
||||
}
|
||||
return copy_basic_block;
|
||||
}
|
||||
|
||||
/* Inserting Single Entry Multiple Exit region in SSA form into code in SSA
|
||||
form is quite easy, since dominator relationship for old basic blocks does
|
||||
not change.
|
||||
|
||||
There is however exception where inlining might change dominator relation
|
||||
across EH edges from basic block within inlined functions destinating
|
||||
to landging pads in function we inline into.
|
||||
|
||||
The function mark PHI_RESULT of such PHI nodes for renaming; it is
|
||||
safe the EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI
|
||||
must be set. This means, that there will be no overlapping live ranges
|
||||
for the underlying symbol.
|
||||
|
||||
This might change in future if we allow redirecting of EH edges and
|
||||
we might want to change way build CFG pre-inlining to include
|
||||
all the possible edges then. */
|
||||
static void
|
||||
update_ssa_across_eh_edges (basic_block bb)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
if (!e->dest->aux
|
||||
|| ((basic_block)e->dest->aux)->index == ENTRY_BLOCK)
|
||||
{
|
||||
tree phi;
|
||||
|
||||
gcc_assert (e->flags & EDGE_EH);
|
||||
for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
|
||||
{
|
||||
gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
|
||||
(PHI_RESULT (phi)));
|
||||
mark_sym_for_renaming
|
||||
(SSA_NAME_VAR (PHI_RESULT (phi)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy edges from BB into its copy constructed earlier, scale profile
|
||||
accordingly. Edges will be taken care of later. Assume aux
|
||||
pointers to point to the copies of each BB. */
|
||||
|
@ -825,6 +955,8 @@ copy_edges_for_bb (basic_block bb, int count_scale)
|
|||
|
||||
copy_stmt = bsi_stmt (bsi);
|
||||
update_stmt (copy_stmt);
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
mark_symbols_for_renaming (copy_stmt);
|
||||
/* Do this before the possible split_block. */
|
||||
bsi_next (&bsi);
|
||||
|
||||
|
@ -847,11 +979,54 @@ copy_edges_for_bb (basic_block bb, int count_scale)
|
|||
right at this point; split_block doesn't care. */
|
||||
{
|
||||
edge e = split_block (new_bb, copy_stmt);
|
||||
|
||||
new_bb = e->dest;
|
||||
new_bb->aux = e->src->aux;
|
||||
bsi = bsi_start (new_bb);
|
||||
}
|
||||
|
||||
make_eh_edges (copy_stmt);
|
||||
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
update_ssa_across_eh_edges (bb_for_stmt (copy_stmt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the PHIs. All blocks and edges are copied, some blocks
|
||||
was possibly split and new outgoing EH edges inserted.
|
||||
BB points to the block of original function and AUX pointers links
|
||||
the original and newly copied blocks. */
|
||||
|
||||
static void
|
||||
copy_phis_for_bb (basic_block bb, copy_body_data *id)
|
||||
{
|
||||
basic_block new_bb = bb->aux;
|
||||
edge_iterator ei;
|
||||
tree phi;
|
||||
|
||||
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
||||
{
|
||||
tree res = PHI_RESULT (phi);
|
||||
tree new_res = res;
|
||||
tree new_phi;
|
||||
edge new_edge;
|
||||
|
||||
if (is_gimple_reg (res))
|
||||
{
|
||||
walk_tree (&new_res, copy_body_r, id, NULL);
|
||||
SSA_NAME_DEF_STMT (new_res)
|
||||
= new_phi = create_phi_node (new_res, new_bb);
|
||||
FOR_EACH_EDGE (new_edge, ei, new_bb->preds)
|
||||
{
|
||||
edge old_edge = find_edge (new_edge->src->aux, bb);
|
||||
tree arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge);
|
||||
tree new_arg = arg;
|
||||
|
||||
walk_tree (&new_arg, copy_body_r, id, NULL);
|
||||
gcc_assert (new_arg);
|
||||
add_phi_arg (new_phi, new_arg, new_edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -863,6 +1038,67 @@ remap_decl_1 (tree decl, void *data)
|
|||
return remap_decl (decl, (copy_body_data *) data);
|
||||
}
|
||||
|
||||
/* Build struct function and associated datastructures for the new clone
|
||||
NEW_FNDECL to be build. CALLEE_FNDECL is the original */
|
||||
|
||||
static void
|
||||
initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
|
||||
int frequency)
|
||||
{
|
||||
struct function *new_cfun
|
||||
= (struct function *) ggc_alloc_cleared (sizeof (struct function));
|
||||
struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
|
||||
int count_scale, frequency_scale;
|
||||
|
||||
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
|
||||
count_scale = (REG_BR_PROB_BASE * count
|
||||
/ ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count);
|
||||
else
|
||||
count_scale = 1;
|
||||
|
||||
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency)
|
||||
frequency_scale = (REG_BR_PROB_BASE * frequency
|
||||
/
|
||||
ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency);
|
||||
else
|
||||
frequency_scale = count_scale;
|
||||
|
||||
/* Register specific tree functions. */
|
||||
tree_register_cfg_hooks ();
|
||||
*new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
|
||||
VALUE_HISTOGRAMS (new_cfun) = NULL;
|
||||
new_cfun->unexpanded_var_list = NULL;
|
||||
new_cfun->cfg = NULL;
|
||||
new_cfun->decl = new_fndecl /*= copy_node (callee_fndecl)*/;
|
||||
new_cfun->ib_boundaries_block = NULL;
|
||||
DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
|
||||
push_cfun (new_cfun);
|
||||
init_empty_tree_cfg ();
|
||||
|
||||
ENTRY_BLOCK_PTR->count =
|
||||
(ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
|
||||
REG_BR_PROB_BASE);
|
||||
ENTRY_BLOCK_PTR->frequency =
|
||||
(ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
|
||||
frequency_scale / REG_BR_PROB_BASE);
|
||||
EXIT_BLOCK_PTR->count =
|
||||
(EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
|
||||
REG_BR_PROB_BASE);
|
||||
EXIT_BLOCK_PTR->frequency =
|
||||
(EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
|
||||
frequency_scale / REG_BR_PROB_BASE);
|
||||
if (src_cfun->eh)
|
||||
init_eh_for_function ();
|
||||
|
||||
if (src_cfun->gimple_df)
|
||||
{
|
||||
init_tree_ssa ();
|
||||
cfun->gimple_df->in_ssa_p = true;
|
||||
init_ssa_operands ();
|
||||
}
|
||||
pop_cfun ();
|
||||
}
|
||||
|
||||
/* Make a copy of the body of FN so that it can be inserted inline in
|
||||
another function. Walks FN via CFG, returns new fndecl. */
|
||||
|
||||
|
@ -873,15 +1109,11 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
|
|||
tree callee_fndecl = id->src_fn;
|
||||
/* Original cfun for the callee, doesn't change. */
|
||||
struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
|
||||
/* Copy, built by this function. */
|
||||
struct function *new_cfun;
|
||||
/* Place to copy from; when a copy of the function was saved off earlier,
|
||||
use that instead of the main copy. */
|
||||
struct function *cfun_to_copy =
|
||||
(struct function *) ggc_alloc_cleared (sizeof (struct function));
|
||||
struct function *cfun_to_copy;
|
||||
basic_block bb;
|
||||
tree new_fndecl = NULL;
|
||||
int count_scale, frequency_scale;
|
||||
int last;
|
||||
|
||||
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
|
||||
count_scale = (REG_BR_PROB_BASE * count
|
||||
|
@ -903,64 +1135,47 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
|
|||
gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
|
||||
(DECL_STRUCT_FUNCTION (callee_fndecl)));
|
||||
|
||||
*cfun_to_copy = *DECL_STRUCT_FUNCTION (callee_fndecl);
|
||||
cfun_to_copy = id->src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
|
||||
|
||||
id->src_cfun = cfun_to_copy;
|
||||
|
||||
/* If requested, create new basic_block_info and label_to_block_maps.
|
||||
Otherwise, insert our new blocks and labels into the existing cfg. */
|
||||
if (id->transform_new_cfg)
|
||||
{
|
||||
new_cfun =
|
||||
(struct function *) ggc_alloc_cleared (sizeof (struct function));
|
||||
*new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
|
||||
new_cfun->cfg = NULL;
|
||||
new_cfun->decl = new_fndecl = copy_node (callee_fndecl);
|
||||
new_cfun->ib_boundaries_block = NULL;
|
||||
DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
|
||||
push_cfun (new_cfun);
|
||||
init_empty_tree_cfg ();
|
||||
|
||||
ENTRY_BLOCK_PTR->count =
|
||||
(ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
|
||||
REG_BR_PROB_BASE);
|
||||
ENTRY_BLOCK_PTR->frequency =
|
||||
(ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
|
||||
frequency_scale / REG_BR_PROB_BASE);
|
||||
EXIT_BLOCK_PTR->count =
|
||||
(EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
|
||||
REG_BR_PROB_BASE);
|
||||
EXIT_BLOCK_PTR->frequency =
|
||||
(EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
|
||||
frequency_scale / REG_BR_PROB_BASE);
|
||||
|
||||
entry_block_map = ENTRY_BLOCK_PTR;
|
||||
exit_block_map = EXIT_BLOCK_PTR;
|
||||
}
|
||||
|
||||
ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = entry_block_map;
|
||||
EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = exit_block_map;
|
||||
entry_block_map->aux = ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
|
||||
exit_block_map->aux = EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
|
||||
|
||||
/* Duplicate any exception-handling regions. */
|
||||
if (cfun->eh)
|
||||
{
|
||||
if (id->transform_new_cfg)
|
||||
init_eh_for_function ();
|
||||
id->eh_region_offset
|
||||
= duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
|
||||
0, id->eh_region);
|
||||
}
|
||||
/* Use aux pointers to map the original blocks to copy. */
|
||||
FOR_EACH_BB_FN (bb, cfun_to_copy)
|
||||
bb->aux = copy_bb (id, bb, frequency_scale, count_scale);
|
||||
{
|
||||
basic_block new = copy_bb (id, bb, frequency_scale, count_scale);
|
||||
bb->aux = new;
|
||||
new->aux = bb;
|
||||
}
|
||||
|
||||
last = n_basic_blocks;
|
||||
/* Now that we've duplicated the blocks, duplicate their edges. */
|
||||
FOR_ALL_BB_FN (bb, cfun_to_copy)
|
||||
copy_edges_for_bb (bb, count_scale);
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
FOR_ALL_BB_FN (bb, cfun_to_copy)
|
||||
copy_phis_for_bb (bb, id);
|
||||
FOR_ALL_BB_FN (bb, cfun_to_copy)
|
||||
bb->aux = NULL;
|
||||
|
||||
if (id->transform_new_cfg)
|
||||
pop_cfun ();
|
||||
{
|
||||
((basic_block)bb->aux)->aux = NULL;
|
||||
bb->aux = NULL;
|
||||
}
|
||||
/* Zero out AUX fields of newly created block during EH edge
|
||||
insertion. */
|
||||
for (; last < n_basic_blocks; last++)
|
||||
BASIC_BLOCK (last)->aux = NULL;
|
||||
entry_block_map->aux = NULL;
|
||||
exit_block_map->aux = NULL;
|
||||
|
||||
return new_fndecl;
|
||||
}
|
||||
|
@ -1017,13 +1232,17 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
|
|||
tree init_stmt;
|
||||
tree var;
|
||||
tree var_sub;
|
||||
tree rhs = value ? fold_convert (TREE_TYPE (p), value) : NULL;
|
||||
tree def = (gimple_in_ssa_p (cfun)
|
||||
? gimple_default_def (id->src_cfun, p) : NULL);
|
||||
|
||||
/* If the parameter is never assigned to, we may not need to
|
||||
create a new variable here at all. Instead, we may be able
|
||||
to just use the argument value. */
|
||||
/* If the parameter is never assigned to, has no SSA_NAMEs created,
|
||||
we may not need to create a new variable here at all. Instead, we may
|
||||
be able to just use the argument value. */
|
||||
if (TREE_READONLY (p)
|
||||
&& !TREE_ADDRESSABLE (p)
|
||||
&& value && !TREE_SIDE_EFFECTS (value))
|
||||
&& value && !TREE_SIDE_EFFECTS (value)
|
||||
&& !def)
|
||||
{
|
||||
/* We may produce non-gimple trees by adding NOPs or introduce
|
||||
invalid sharing when operand is not really constant.
|
||||
|
@ -1047,6 +1266,11 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
|
|||
here since the type of this decl must be visible to the calling
|
||||
function. */
|
||||
var = copy_decl_to_var (p, id);
|
||||
if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
|
||||
{
|
||||
get_var_ann (var);
|
||||
add_referenced_var (var);
|
||||
}
|
||||
|
||||
/* See if the frontend wants to pass this by invisible reference. If
|
||||
so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
|
||||
|
@ -1085,21 +1309,54 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
|
|||
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
|
||||
TREE_READONLY (var) = 0;
|
||||
|
||||
/* If there is no setup required and we are in SSA, take the easy route
|
||||
replacing all SSA names representing the function parameter by the
|
||||
SSA name passed to function.
|
||||
|
||||
We need to construct map for the variable anyway as it might be used
|
||||
in different SSA names when parameter is set in function.
|
||||
|
||||
FIXME: This usually kills the last connection in between inlined
|
||||
function parameter and the actual value in debug info. Can we do
|
||||
better here? If we just inserted the statement, copy propagation
|
||||
would kill it anyway as it always did in older versions of GCC.
|
||||
|
||||
We might want to introduce a notion that single SSA_NAME might
|
||||
represent multiple variables for purposes of debugging. */
|
||||
if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p)
|
||||
&& (TREE_CODE (rhs) == SSA_NAME
|
||||
|| is_gimple_min_invariant (rhs)))
|
||||
{
|
||||
insert_decl_map (id, def, rhs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize this VAR_DECL from the equivalent argument. Convert
|
||||
the argument to the proper type in case it was promoted. */
|
||||
if (value)
|
||||
{
|
||||
tree rhs = fold_convert (TREE_TYPE (var), value);
|
||||
block_stmt_iterator bsi = bsi_last (bb);
|
||||
|
||||
if (rhs == error_mark_node)
|
||||
return;
|
||||
{
|
||||
insert_decl_map (id, p, var_sub);
|
||||
return;
|
||||
}
|
||||
|
||||
STRIP_USELESS_TYPE_CONVERSION (rhs);
|
||||
|
||||
/* We want to use GIMPLE_MODIFY_STMT, not INIT_EXPR here so that we
|
||||
keep our trees in gimple form. */
|
||||
init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), var, rhs);
|
||||
if (def && gimple_in_ssa_p (cfun) && is_gimple_reg (p))
|
||||
{
|
||||
def = remap_ssa_name (def, id);
|
||||
init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), def, rhs);
|
||||
SSA_NAME_DEF_STMT (def) = init_stmt;
|
||||
SSA_NAME_IS_DEFAULT_DEF (def) = 0;
|
||||
set_default_def (var, NULL);
|
||||
}
|
||||
else
|
||||
init_stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), var, rhs);
|
||||
|
||||
/* If we did not create a gimple value and we did not create a gimple
|
||||
cast of a gimple value, then we will need to gimplify INIT_STMTS
|
||||
|
@ -1110,12 +1367,29 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
|
|||
&& (!is_gimple_cast (rhs)
|
||||
|| !is_gimple_val (TREE_OPERAND (rhs, 0))))
|
||||
|| !is_gimple_reg (var))
|
||||
gimplify_stmt (&init_stmt);
|
||||
{
|
||||
tree_stmt_iterator i;
|
||||
|
||||
push_gimplify_context ();
|
||||
gimplify_stmt (&init_stmt);
|
||||
if (gimple_in_ssa_p (cfun)
|
||||
&& init_stmt && TREE_CODE (init_stmt) == STATEMENT_LIST)
|
||||
{
|
||||
/* The replacement can expose previously unreferenced
|
||||
variables. */
|
||||
for (i = tsi_start (init_stmt); !tsi_end_p (i); tsi_next (&i))
|
||||
find_new_referenced_vars (tsi_stmt_ptr (i));
|
||||
}
|
||||
pop_gimplify_context (NULL);
|
||||
}
|
||||
|
||||
/* If VAR represents a zero-sized variable, it's possible that the
|
||||
assignment statment may result in no gimple statements. */
|
||||
if (init_stmt)
|
||||
bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
for (;!bsi_end_p (bsi); bsi_next (&bsi))
|
||||
mark_symbols_for_renaming (bsi_stmt (bsi));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1170,17 +1444,17 @@ initialize_inlined_parameters (copy_body_data *id, tree args, tree static_chain,
|
|||
The USE_STMT is filled to contain a use of the declaration to
|
||||
indicate the return value of the function.
|
||||
|
||||
RETURN_SLOT_ADDR, if non-null, was a fake parameter that
|
||||
took the address of the result. MODIFY_DEST, if non-null, was the LHS of
|
||||
the GIMPLE_MODIFY_STMT to which this call is the RHS.
|
||||
RETURN_SLOT, if non-null is place where to store the result. It
|
||||
is set only for CALL_EXPR_RETURN_SLOT_OPT. MODIFY_DEST, if non-null,
|
||||
was the LHS of the GIMPLE_MODIFY_STMT to which this call is the RHS.
|
||||
|
||||
The return value is a (possibly null) value that is the result of the
|
||||
function as seen by the callee. *USE_P is a (possibly null) value that
|
||||
holds the result as seen by the caller. */
|
||||
|
||||
static tree
|
||||
declare_return_variable (copy_body_data *id, tree return_slot_addr,
|
||||
tree modify_dest, tree *use_p)
|
||||
declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
|
||||
tree *use_p)
|
||||
{
|
||||
tree callee = id->src_fn;
|
||||
tree caller = id->dst_fn;
|
||||
|
@ -1199,15 +1473,49 @@ declare_return_variable (copy_body_data *id, tree return_slot_addr,
|
|||
|
||||
/* If there was a return slot, then the return value is the
|
||||
dereferenced address of that object. */
|
||||
if (return_slot_addr)
|
||||
if (return_slot)
|
||||
{
|
||||
/* The front end shouldn't have used both return_slot_addr and
|
||||
/* The front end shouldn't have used both return_slot and
|
||||
a modify expression. */
|
||||
gcc_assert (!modify_dest);
|
||||
if (DECL_BY_REFERENCE (result))
|
||||
var = return_slot_addr;
|
||||
{
|
||||
tree return_slot_addr = build_fold_addr_expr (return_slot);
|
||||
STRIP_USELESS_TYPE_CONVERSION (return_slot_addr);
|
||||
|
||||
/* We are going to construct *&return_slot and we can't do that
|
||||
for variables believed to be not addressable.
|
||||
|
||||
FIXME: This check possibly can match, because values returned
|
||||
via return slot optimization are not believed to have address
|
||||
taken by alias analysis. */
|
||||
gcc_assert (TREE_CODE (return_slot) != SSA_NAME);
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
{
|
||||
HOST_WIDE_INT bitsize;
|
||||
HOST_WIDE_INT bitpos;
|
||||
tree offset;
|
||||
enum machine_mode mode;
|
||||
int unsignedp;
|
||||
int volatilep;
|
||||
tree base;
|
||||
base = get_inner_reference (return_slot, &bitsize, &bitpos,
|
||||
&offset,
|
||||
&mode, &unsignedp, &volatilep,
|
||||
false);
|
||||
if (TREE_CODE (base) == INDIRECT_REF)
|
||||
base = TREE_OPERAND (base, 0);
|
||||
if (TREE_CODE (base) == SSA_NAME)
|
||||
base = SSA_NAME_VAR (base);
|
||||
mark_sym_for_renaming (base);
|
||||
}
|
||||
var = return_slot_addr;
|
||||
}
|
||||
else
|
||||
var = build_fold_indirect_ref (return_slot_addr);
|
||||
{
|
||||
var = return_slot;
|
||||
gcc_assert (TREE_CODE (var) != SSA_NAME);
|
||||
}
|
||||
if ((TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
|
||||
|| TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
|
||||
&& !DECL_GIMPLE_REG_P (result)
|
||||
|
@ -1221,7 +1529,8 @@ declare_return_variable (copy_body_data *id, tree return_slot_addr,
|
|||
gcc_assert (!TREE_ADDRESSABLE (callee_type));
|
||||
|
||||
/* Attempt to avoid creating a new temporary variable. */
|
||||
if (modify_dest)
|
||||
if (modify_dest
|
||||
&& TREE_CODE (modify_dest) != SSA_NAME)
|
||||
{
|
||||
bool use_it = false;
|
||||
|
||||
|
@ -1270,6 +1579,11 @@ declare_return_variable (copy_body_data *id, tree return_slot_addr,
|
|||
gcc_assert (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) == INTEGER_CST);
|
||||
|
||||
var = copy_result_decl_to_var (result, id);
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
{
|
||||
get_var_ann (var);
|
||||
add_referenced_var (var);
|
||||
}
|
||||
|
||||
DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
|
||||
DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
|
||||
|
@ -1938,7 +2252,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
tree fn;
|
||||
splay_tree st;
|
||||
tree args;
|
||||
tree return_slot_addr;
|
||||
tree return_slot;
|
||||
tree modify_dest;
|
||||
location_t saved_location;
|
||||
struct cgraph_edge *cg_edge;
|
||||
|
@ -2095,6 +2409,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
/* Record the function we are about to inline. */
|
||||
id->src_fn = fn;
|
||||
id->src_node = cg_edge->callee;
|
||||
id->src_cfun = DECL_STRUCT_FUNCTION (fn);
|
||||
|
||||
initialize_inlined_parameters (id, args, TREE_OPERAND (t, 2), fn, bb);
|
||||
|
||||
|
@ -2108,7 +2423,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
gcc_assert (TREE_CODE (DECL_INITIAL (fn)) == BLOCK);
|
||||
|
||||
/* Find the lhs to which the result of this call is assigned. */
|
||||
return_slot_addr = NULL;
|
||||
return_slot = NULL;
|
||||
if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
|
||||
{
|
||||
modify_dest = GIMPLE_STMT_OPERAND (stmt, 0);
|
||||
|
@ -2123,8 +2438,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
TREE_NO_WARNING (modify_dest) = 1;
|
||||
if (CALL_EXPR_RETURN_SLOT_OPT (t))
|
||||
{
|
||||
return_slot_addr = build_fold_addr_expr (modify_dest);
|
||||
STRIP_USELESS_TYPE_CONVERSION (return_slot_addr);
|
||||
return_slot = modify_dest;
|
||||
modify_dest = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -2132,7 +2446,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
modify_dest = NULL;
|
||||
|
||||
/* Declare the return variable for the function. */
|
||||
declare_return_variable (id, return_slot_addr,
|
||||
declare_return_variable (id, return_slot,
|
||||
modify_dest, &use_retvar);
|
||||
|
||||
/* This is it. Duplicate the callee body. Assume callee is
|
||||
|
@ -2164,12 +2478,44 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
if (use_retvar && (TREE_CODE (bsi_stmt (stmt_bsi)) != CALL_EXPR))
|
||||
{
|
||||
*tp = use_retvar;
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
{
|
||||
update_stmt (stmt);
|
||||
mark_symbols_for_renaming (stmt);
|
||||
}
|
||||
maybe_clean_or_replace_eh_stmt (stmt, stmt);
|
||||
}
|
||||
else
|
||||
/* We're modifying a TSI owned by gimple_expand_calls_inline();
|
||||
tsi_delink() will leave the iterator in a sane state. */
|
||||
bsi_remove (&stmt_bsi, true);
|
||||
{
|
||||
/* Handle case of inlining function that miss return statement so
|
||||
return value becomes undefined. */
|
||||
if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
|
||||
&& TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME)
|
||||
{
|
||||
tree name = TREE_OPERAND (stmt, 0);
|
||||
tree var = SSA_NAME_VAR (TREE_OPERAND (stmt, 0));
|
||||
tree def = gimple_default_def (cfun, var);
|
||||
|
||||
/* If the variable is used undefined, make this name undefined via
|
||||
move. */
|
||||
if (def)
|
||||
{
|
||||
TREE_OPERAND (stmt, 1) = def;
|
||||
update_stmt (stmt);
|
||||
}
|
||||
/* Otherwise make this variable undefined. */
|
||||
else
|
||||
{
|
||||
bsi_remove (&stmt_bsi, true);
|
||||
set_default_def (var, name);
|
||||
SSA_NAME_DEF_STMT (name) = build_empty_stmt ();
|
||||
}
|
||||
}
|
||||
else
|
||||
bsi_remove (&stmt_bsi, true);
|
||||
}
|
||||
|
||||
if (purge_dead_abnormal_edges)
|
||||
tree_purge_dead_abnormal_call_edges (return_block);
|
||||
|
@ -2290,7 +2636,23 @@ optimize_inline_calls (tree fn)
|
|||
as inlining loops might increase the maximum. */
|
||||
if (ENTRY_BLOCK_PTR->count)
|
||||
counts_to_freqs ();
|
||||
fold_cond_expr_cond ();
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
{
|
||||
/* We make no attempts to keep dominance info up-to-date. */
|
||||
free_dominance_info (CDI_DOMINATORS);
|
||||
free_dominance_info (CDI_POST_DOMINATORS);
|
||||
delete_unreachable_blocks ();
|
||||
update_ssa (TODO_update_ssa);
|
||||
fold_cond_expr_cond ();
|
||||
if (need_ssa_update_p ())
|
||||
update_ssa (TODO_update_ssa);
|
||||
}
|
||||
else
|
||||
fold_cond_expr_cond ();
|
||||
/* It would be nice to check SSA/CFG/statement consistency here, but it is
|
||||
not possible yet - the IPA passes might make various functions to not
|
||||
throw and they don't care to proactively update local EH info. This is
|
||||
done later in fixup_cfg pass that also execute the verification. */
|
||||
}
|
||||
|
||||
/* FN is a function that has a complete body, and CLONE is a function whose
|
||||
|
@ -2782,7 +3144,7 @@ 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;
|
||||
copy_body_data id;
|
||||
tree p, new_fndecl;
|
||||
tree p;
|
||||
unsigned i;
|
||||
struct ipa_replace_map *replace_info;
|
||||
basic_block old_entry_block;
|
||||
|
@ -2828,6 +3190,12 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
|
|||
id.transform_lang_insert_block = false;
|
||||
|
||||
current_function_decl = new_decl;
|
||||
old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
|
||||
(DECL_STRUCT_FUNCTION (old_decl));
|
||||
initialize_cfun (new_decl, old_decl,
|
||||
old_entry_block->count,
|
||||
old_entry_block->frequency);
|
||||
push_cfun (DECL_STRUCT_FUNCTION (new_decl));
|
||||
|
||||
/* Copy the function's static chain. */
|
||||
p = DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl;
|
||||
|
@ -2871,22 +3239,8 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
|
|||
}
|
||||
|
||||
/* Copy the Function's body. */
|
||||
old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
|
||||
(DECL_STRUCT_FUNCTION (old_decl));
|
||||
new_fndecl = copy_body (&id,
|
||||
old_entry_block->count,
|
||||
old_entry_block->frequency, NULL, NULL);
|
||||
copy_body (&id, old_entry_block->count, old_entry_block->frequency, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR);
|
||||
|
||||
DECL_SAVED_TREE (new_decl) = DECL_SAVED_TREE (new_fndecl);
|
||||
|
||||
DECL_STRUCT_FUNCTION (new_decl)->cfg =
|
||||
DECL_STRUCT_FUNCTION (new_fndecl)->cfg;
|
||||
DECL_STRUCT_FUNCTION (new_decl)->eh = DECL_STRUCT_FUNCTION (new_fndecl)->eh;
|
||||
DECL_STRUCT_FUNCTION (new_decl)->ib_boundaries_block =
|
||||
DECL_STRUCT_FUNCTION (new_fndecl)->ib_boundaries_block;
|
||||
DECL_STRUCT_FUNCTION (new_decl)->last_label_uid =
|
||||
DECL_STRUCT_FUNCTION (new_fndecl)->last_label_uid;
|
||||
|
||||
if (DECL_RESULT (old_decl) != NULL_TREE)
|
||||
{
|
||||
tree *res_decl = &DECL_RESULT (old_decl);
|
||||
|
@ -2894,13 +3248,20 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
|
|||
lang_hooks.dup_lang_specific_decl (DECL_RESULT (new_decl));
|
||||
}
|
||||
|
||||
current_function_decl = NULL;
|
||||
/* Renumber the lexical scoping (non-code) blocks consecutively. */
|
||||
number_blocks (new_decl);
|
||||
|
||||
/* Clean up. */
|
||||
splay_tree_delete (id.decl_map);
|
||||
fold_cond_expr_cond ();
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
{
|
||||
update_ssa (TODO_update_ssa);
|
||||
}
|
||||
free_dominance_info (CDI_DOMINATORS);
|
||||
free_dominance_info (CDI_POST_DOMINATORS);
|
||||
pop_cfun ();
|
||||
current_function_decl = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue