cgraph.h (cgraph_node): Add 'lowered' state.

* cgraph.h (cgraph_node): Add 'lowered' state.
	(cgraph_lower_function): Declare.
	* cgraphunit.c (cgraph_finalize_function): Initialize lowered flag.
	(cgraph_lower_function): New function.
	(cgraph_create_edges): Deal with lowered function bodies.
	(verify_cgraph_node): Likewise.
	(cgraph_analyze_function): Do lowering job.
	(cgraph_build_static_cdtor): Likewise.
	* function.h (struct function): Add saved_eh and saved_cfg.
	* integrate.c (copy_decl_for_inlining): Kill LABEL_DECL_UID field.
	* tree-cfg.c (fold_cond_expr_cond): Export.
	* tree-flow.h (fold_cond_expr_cond): Declare.
	* tree-inline.c: Include basic-block, ggc, tree-flow, except.h and
	pointer-set.
	(struct_inline_data): Kill fnd, first_inlined_fn, ret_label,
	in_target_cleanup_p, tree_pruner, tsi; add callee, caller and
	callee_cfun, block, eh_region, eh_region_offset.
	(inlining_p): New predicate.
	(remap_decl): Update for new inline_data; declare newly created inline
	vars in low gimple way.
	(copy_body_r): Update for new datastructure, simplify some of handling
	when we are in gimple; remap LABEL_DECLs for EH; copy TREE_BLOCK;
	deal with RESX_EXPRs.
	(copy_bb): New.
	(copy_edges_for_bb): Likewise.
	(remap_decl_1): New.
	(copy_cfg_body): New.
	(copy_generic_body): Rewrite to work on low gimple.
	(copy_body): Turn into simple wrapper around copy_cfg_body.
	(setup_one_parameter): Insert new statements into given basic block.
	(initialize_initialized_parameters): Likewise, reorganize way things are
	gimplified.
	(declare_return_variable): Update for new inline data datastructure.
	(inline_forbidden_p): Work on low gimple.
	(estimate_num_insns): Likewise.
	(expand_call_inline): Work on CFG.
	(push_cfun, pop_cfun): New functions.
	(cfun_stack): New stack.
	(add_lexical_block): New function.
	(gimple_expand_calls_inline): Work on basic block.
	(optimize_inline_calls): Likewise.
	(clone_body, save_body, unsave_ewpr_now): Update for new
	datastructures.
	(declare_inline_vars): Work on block instead of bind_expr.
	(inlining_p): New predicate.
	* tree-inline.h (push_cfun, pop_cfun): Declare.
	* tree-optimize.c: Include except.h
	(all_lowering_passes): New variable.
	(execute_fixup_cfg, pass_fixup_cfg): New pass.
	(init_tree_optimization_passes): Move some to all_lowering_passes.
	(tree_lowering_passes): New function.
	(tree_rest_of_compilation): Register cfg hooks; save/unsave eh.

Co-Authored-By: Dale Johannesen <dalej@apple.com>
Co-Authored-By: Jan Hubicka <jh@suse.cz>
Co-Authored-By: Stuart Hastings <stuart@apple.com>

From-SVN: r99840
This commit is contained in:
Steven Bosscher 2005-05-17 16:56:32 +00:00 committed by Jan Hubicka
parent 8f2a14065c
commit e21aff8abe
13 changed files with 957 additions and 415 deletions

View File

@ -1,3 +1,61 @@
2005-05-17 Steven Bosscher <stevenb@suse.de>
Stuart Hastings <stuart@apple.com>
Jan Hubicka <jh@suse.cz>
Dale Johannesen <dalej@apple.com>
* cgraph.h (cgraph_node): Add 'lowered' state.
(cgraph_lower_function): Declare.
* cgraphunit.c (cgraph_finalize_function): Initialize lowered flag.
(cgraph_lower_function): New function.
(cgraph_create_edges): Deal with lowered function bodies.
(verify_cgraph_node): Likewise.
(cgraph_analyze_function): Do lowering job.
(cgraph_build_static_cdtor): Likewise.
* function.h (struct function): Add saved_eh and saved_cfg.
* integrate.c (copy_decl_for_inlining): Kill LABEL_DECL_UID field.
* tree-cfg.c (fold_cond_expr_cond): Export.
* tree-flow.h (fold_cond_expr_cond): Declare.
* tree-inline.c: Include basic-block, ggc, tree-flow, except.h and
pointer-set.
(struct_inline_data): Kill fnd, first_inlined_fn, ret_label,
in_target_cleanup_p, tree_pruner, tsi; add callee, caller and
callee_cfun, block, eh_region, eh_region_offset.
(inlining_p): New predicate.
(remap_decl): Update for new inline_data; declare newly created inline
vars in low gimple way.
(copy_body_r): Update for new datastructure, simplify some of handling
when we are in gimple; remap LABEL_DECLs for EH; copy TREE_BLOCK;
deal with RESX_EXPRs.
(copy_bb): New.
(copy_edges_for_bb): Likewise.
(remap_decl_1): New.
(copy_cfg_body): New.
(copy_generic_body): Rewrite to work on low gimple.
(copy_body): Turn into simple wrapper around copy_cfg_body.
(setup_one_parameter): Insert new statements into given basic block.
(initialize_initialized_parameters): Likewise, reorganize way things are
gimplified.
(declare_return_variable): Update for new inline data datastructure.
(inline_forbidden_p): Work on low gimple.
(estimate_num_insns): Likewise.
(expand_call_inline): Work on CFG.
(push_cfun, pop_cfun): New functions.
(cfun_stack): New stack.
(add_lexical_block): New function.
(gimple_expand_calls_inline): Work on basic block.
(optimize_inline_calls): Likewise.
(clone_body, save_body, unsave_ewpr_now): Update for new
datastructures.
(declare_inline_vars): Work on block instead of bind_expr.
(inlining_p): New predicate.
* tree-inline.h (push_cfun, pop_cfun): Declare.
* tree-optimize.c: Include except.h
(all_lowering_passes): New variable.
(execute_fixup_cfg, pass_fixup_cfg): New pass.
(init_tree_optimization_passes): Move some to all_lowering_passes.
(tree_lowering_passes): New function.
(tree_rest_of_compilation): Register cfg hooks; save/unsave eh.
2005-05-17 Nathan Sidwell <nathan@codesourcery.com>
* unwind-dw2-fde-darwin.c: Include tsystem.h.

View File

@ -117,6 +117,8 @@ struct cgraph_node GTY((chain_next ("%h.next"), chain_prev ("%h.previous")))
/* Set when function is reachable by call from other function
that is either reachable or needed. */
bool reachable;
/* Set once the function is lowered (ie it's CFG is built). */
bool lowered;
/* Set once the function has been instantiated and its callee
lists created. */
bool analyzed;
@ -215,6 +217,7 @@ bool decide_is_variable_needed (struct cgraph_varpool_node *, tree);
bool cgraph_assemble_pending_functions (void);
bool cgraph_varpool_assemble_pending_decls (void);
void cgraph_finalize_function (tree, bool);
void cgraph_lower_function (struct cgraph_node *);
void cgraph_finalize_compilation_unit (void);
void cgraph_create_edges (struct cgraph_node *, tree);
void cgraph_optimize (void);

View File

@ -427,6 +427,7 @@ cgraph_finalize_function (tree decl, bool nested)
notice_global_symbol (decl);
node->decl = decl;
node->local.finalized = true;
node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
if (node->nested)
lower_nested_functions (decl);
gcc_assert (!node->nested);
@ -459,6 +460,16 @@ cgraph_finalize_function (tree decl, bool nested)
do_warn_unused_parameter (decl);
}
void
cgraph_lower_function (struct cgraph_node *node)
{
if (node->lowered)
return;
tree_lowering_passes (node->decl);
node->lowered = true;
}
/* Walk tree and record all calls. Called via walk_tree. */
static tree
record_call_1 (tree *tp, int *walk_subtrees, void *data)
@ -538,6 +549,43 @@ cgraph_create_edges (struct cgraph_node *node, tree body)
/* The nodes we're interested in are never shared, so walk
the tree ignoring duplicates. */
visited_nodes = pointer_set_create ();
if (TREE_CODE (body) == FUNCTION_DECL)
{
struct function *this_cfun = DECL_STRUCT_FUNCTION (body);
basic_block this_block;
block_stmt_iterator bsi;
tree step;
/* Reach the trees by walking over the CFG, and note the
enclosing basic-blocks in the call edges. */
FOR_EACH_BB_FN (this_block, this_cfun)
for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
walk_tree (bsi_stmt_ptr (bsi), record_call_1, node, visited_nodes);
/* Walk over any private statics that may take addresses of functions. */
if (TREE_CODE (DECL_INITIAL (body)) == BLOCK)
{
for (step = BLOCK_VARS (DECL_INITIAL (body));
step;
step = TREE_CHAIN (step))
if (DECL_INITIAL (step))
walk_tree (&DECL_INITIAL (step), record_call_1, node, visited_nodes);
}
/* Also look here for private statics. */
if (DECL_STRUCT_FUNCTION (body))
for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list;
step;
step = TREE_CHAIN (step))
{
tree decl = TREE_VALUE (step);
if (DECL_INITIAL (decl) && TREE_STATIC (decl))
walk_tree (&DECL_INITIAL (decl), record_call_1, node, visited_nodes);
}
}
else
walk_tree (&body, record_call_1, node, visited_nodes);
walk_tree (&body, record_call_1, node, visited_nodes);
pointer_set_destroy (visited_nodes);
visited_nodes = NULL;
@ -596,6 +644,9 @@ verify_cgraph_node (struct cgraph_node *node)
{
struct cgraph_edge *e;
struct cgraph_node *main_clone;
struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl);
basic_block this_block;
block_stmt_iterator bsi;
timevar_push (TV_CGRAPH_VERIFY);
error_found = false;
@ -655,8 +706,23 @@ verify_cgraph_node (struct cgraph_node *node)
&& DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl)
&& (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
{
walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl),
verify_cgraph_node_1, node);
if (this_cfun->cfg)
{
/* The nodes we're interested in are never shared, so walk
the tree ignoring duplicates. */
visited_nodes = pointer_set_create ();
/* Reach the trees by walking over the CFG, and note the
enclosing basic-blocks in the call edges. */
FOR_EACH_BB_FN (this_block, this_cfun)
for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
walk_tree (bsi_stmt_ptr (bsi), verify_cgraph_node_1, node, visited_nodes);
pointer_set_destroy (visited_nodes);
visited_nodes = NULL;
}
else
/* No CFG available?! */
gcc_unreachable ();
for (e = node->callees; e; e = e->next_callee)
{
if (!e->aux)
@ -729,12 +795,14 @@ cgraph_analyze_function (struct cgraph_node *node)
struct cgraph_edge *e;
current_function_decl = decl;
push_cfun (DECL_STRUCT_FUNCTION (decl));
cgraph_lower_function (node);
/* First kill forward declaration so reverse inlining works properly. */
cgraph_create_edges (node, DECL_SAVED_TREE (decl));
cgraph_create_edges (node, decl);
node->local.inlinable = tree_inlinable_function_p (decl);
node->local.self_insns = estimate_num_insns (DECL_SAVED_TREE (decl));
node->local.self_insns = estimate_num_insns (decl);
if (node->local.inlinable)
node->local.disregard_inline_limits
= lang_hooks.tree_inlining.disregard_inline_limits (decl);
@ -754,6 +822,7 @@ cgraph_analyze_function (struct cgraph_node *node)
node->global.insns = node->local.self_insns;
node->analyzed = true;
pop_cfun ();
current_function_decl = NULL;
}
@ -1178,7 +1247,10 @@ cgraph_build_static_cdtor (char which, tree body, int priority)
/* ??? We will get called LATE in the compilation process. */
if (cgraph_global_info_ready)
tree_rest_of_compilation (decl);
{
tree_lowering_passes (decl);
tree_rest_of_compilation (decl);
}
else
cgraph_finalize_function (decl, 0);

View File

@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA. */
#include "toplev.h"
#include "tm_p.h"
#include "target.h"
#include "tree-pass.h"
/* Various flags to control the mangling process. */
@ -504,7 +505,9 @@ use_thunk (tree thunk_fndecl, bool emit_p)
/* Re-enable access control. */
pop_deferring_access_checks ();
expand_body (finish_function (0));
thunk_fndecl = finish_function (0);
tree_lowering_passes (thunk_fndecl);
expand_body (thunk_fndecl);
}
pop_from_top_level ();

View File

@ -162,19 +162,20 @@ struct expr_status GTY(())
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_tree;
tree saved_args;
tree saved_static_chain_decl;

View File

@ -121,6 +121,7 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn)
if (TREE_CODE (copy) == LABEL_DECL)
{
TREE_ADDRESSABLE (copy) = 0;
LABEL_DECL_UID (copy) = -1;
}
}

View File

@ -7,5 +7,5 @@
The warning about "no return statement in function
returning non-void" is PR 13000. */
static int foo (int a __attribute__((unused)) ) { }
int main (void) { return foo (0); } /* { dg-warning "control may reach end" } */
static int foo (int a __attribute__((unused)) ) { } /* { dg-warning "control reaches end of non-void" } */
int main (void) { return foo (0); }

View File

@ -446,7 +446,7 @@ create_bb (void *h, void *e, basic_block after)
/* Fold COND_EXPR_COND of each COND_EXPR. */
static void
void
fold_cond_expr_cond (void)
{
basic_block bb;

View File

@ -542,6 +542,7 @@ extern tree gimplify_build2 (block_stmt_iterator *, enum tree_code,
extern tree gimplify_build3 (block_stmt_iterator *, enum tree_code,
tree, tree, tree, tree);
extern void init_empty_tree_cfg (void);
extern void fold_cond_expr_cond (void);
/* In tree-pretty-print.c. */
extern void dump_generic_bb (FILE *, basic_block, int, int);

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,10 @@ void optimize_inline_calls (tree);
bool tree_inlinable_function_p (tree);
tree copy_tree_r (tree *, int *, void *);
void clone_body (tree, tree, void *);
tree save_body (tree, tree *, tree *);
void save_body (tree, tree *, tree *);
int estimate_move_cost (tree type);
void push_cfun (struct function *new_cfun);
void pop_cfun (void);
int estimate_num_insns (tree expr);
/* 0 if we should not perform inlining.

View File

@ -48,6 +48,7 @@ Boston, MA 02111-1307, USA. */
#include "cgraph.h"
#include "graph.h"
#include "cfgloop.h"
#include "except.h"
/* Global variables used to communicate with passes. */
@ -55,7 +56,7 @@ int dump_flags;
bool in_gimple_form;
/* The root of the compilation pass tree, once constructed. */
static struct tree_opt_pass *all_passes, *all_ipa_passes;
static struct tree_opt_pass *all_passes, *all_ipa_passes, * all_lowering_passes;
/* Gate: execute, or not, all of the non-trivial optimizations. */
@ -158,6 +159,51 @@ static struct tree_opt_pass pass_free_datastructures =
0 /* letter */
};
/* Pass: fixup_cfg - IPA passes or compilation of earlier functions might've
changed some properties - such as marged functions nothrow. Remove now
redundant edges and basic blocks. */
static void
execute_fixup_cfg (void)
{
basic_block bb;
block_stmt_iterator bsi;
if (cfun->eh)
FOR_EACH_BB (bb)
{
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
tree call = get_call_expr_in (stmt);
if (call && call_expr_flags (call) & (ECF_CONST | ECF_PURE))
TREE_SIDE_EFFECTS (call) = 0;
if (!tree_could_throw_p (stmt) && lookup_stmt_eh_region (stmt))
remove_stmt_from_eh_region (stmt);
}
tree_purge_dead_eh_edges (bb);
}
cleanup_tree_cfg ();
}
static struct tree_opt_pass pass_fixup_cfg =
{
NULL, /* name */
NULL, /* gate */
execute_fixup_cfg, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
0 /* letter */
};
/* Do the actions required to initialize internal data structures used
in tree-ssa optimization passes. */
@ -320,14 +366,21 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_ipa_inline);
*p = NULL;
p = &all_passes;
/* All passes needed to lower the function into shape optimizers can operate
on. These passes are performed before interprocedural passes, unlike rest
of local passes (all_passes). */
p = &all_lowering_passes;
NEXT_PASS (pass_remove_useless_stmts);
NEXT_PASS (pass_mudflap_1);
NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_lower_eh);
NEXT_PASS (pass_build_cfg);
NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_lower_eh);
NEXT_PASS (pass_build_cfg);
NEXT_PASS (pass_pre_expand);
NEXT_PASS (pass_warn_function_return);
*p = NULL;
p = &all_passes;
NEXT_PASS (pass_fixup_cfg);
NEXT_PASS (pass_tree_profile);
NEXT_PASS (pass_init_datastructures);
NEXT_PASS (pass_all_optimizations);
@ -432,6 +485,7 @@ init_tree_optimization_passes (void)
#undef NEXT_PASS
register_dump_files (all_lowering_passes, false, 0);
register_dump_files (all_passes, false, PROP_gimple_any
| PROP_gimple_lcf
| PROP_gimple_leh
@ -606,6 +660,23 @@ execute_pass_list (struct tree_opt_pass *pass)
while (pass);
}
void
tree_lowering_passes (tree fn)
{
tree saved_current_function_decl = current_function_decl;
current_function_decl = fn;
push_cfun (DECL_STRUCT_FUNCTION (fn));
tree_register_cfg_hooks ();
bitmap_obstack_initialize (NULL);
execute_pass_list (all_lowering_passes);
free_dominance_info (CDI_POST_DOMINATORS);
compact_blocks ();
current_function_decl = saved_current_function_decl;
bitmap_obstack_release (NULL);
pop_cfun ();
}
/* Execute all IPA passes. */
void
ipa_passes (void)
@ -675,8 +746,7 @@ tree_rest_of_compilation (tree fndecl)
cgraph_clone_inlined_nodes (e, true);
}
cfun->saved_static_chain_decl = cfun->static_chain_decl;
cfun->saved_tree = save_body (fndecl, &cfun->saved_args,
&cfun->saved_static_chain_decl);
save_body (fndecl, &cfun->saved_args, &cfun->saved_static_chain_decl);
}
if (flag_inline_trees)
@ -712,6 +782,7 @@ tree_rest_of_compilation (tree fndecl)
bitmap_obstack_initialize (NULL);
bitmap_obstack_initialize (&reg_obstack); /* FIXME, only at RTL generation*/
tree_register_cfg_hooks ();
/* Perform all tree transforms and optimizations. */
execute_pass_list (all_passes);
@ -721,12 +792,16 @@ tree_rest_of_compilation (tree fndecl)
bitmap_obstack_release (NULL);
/* Restore original body if still needed. */
if (cfun->saved_tree)
if (cfun->saved_cfg)
{
DECL_SAVED_TREE (fndecl) = cfun->saved_tree;
DECL_ARGUMENTS (fndecl) = cfun->saved_args;
cfun->cfg = cfun->saved_cfg;
cfun->eh = cfun->saved_eh;
cfun->saved_cfg = NULL;
cfun->saved_eh = NULL;
cfun->saved_args = 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. */
@ -734,6 +809,7 @@ tree_rest_of_compilation (tree fndecl)
{
struct cgraph_edge *e;
node = cgraph_node (current_function_decl);
cgraph_node_remove_callees (node);
node->callees = saved_node->callees;
saved_node->callees = NULL;

View File

@ -155,6 +155,7 @@ struct dump_file_info
(TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts)
extern void ipa_passes (void);
extern void tree_lowering_passes (tree decl);
extern struct tree_opt_pass pass_mudflap_1;
extern struct tree_opt_pass pass_mudflap_2;