From: Jan Hubicka Date: Sat, 6 Jan 2007 17:58:40 +0000 (+0100) Subject: tree-pass.h (pass_build_cgraph_edges): Declare. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2dee695bfc9d9384aa18e9e8a7fbc822a18e43c6;p=gcc.git tree-pass.h (pass_build_cgraph_edges): Declare. * tree-pass.h (pass_build_cgraph_edges): Declare. * cgraphunit.c (record_refernece): Move to cgraphbuild.c (visited_nodes): Remove. (cgraph_create_edges): Move to cgraphbuild.c; rename to build_cgrpah_edges; make visited_nodes local. (cgraph_process_new_functions): DO not call initialize_inline_failed. (record_references_in_initializer): Move to cgraphbuild.c (initialize_inline_failed, rebuild_cgraph_edges, pass_rebuild_cgraph_edges): Move to cgraphbuild.c. (verify_cgraph_node): Make visited_nodes local. (cgraph_analyze_function): Do not call cgraph_create_edges and initialize_inline_failed. (cgraph_expand_function): Do not call cgraph_lower_function; assert that function is already lowered. * Makefile.in (cgraphbuild.o): New. * passes.c (init_optimization_passes): Add pass_build_cgraph_edges at the end of lowering passes. From-SVN: r120527 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2623d7fecf9..74eb580e49e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2007-01-06 Jan Hubicka + + * tree-pass.h (pass_build_cgraph_edges): Declare. + * cgraphunit.c (record_refernece): Move to cgraphbuild.c + (visited_nodes): Remove. + (cgraph_create_edges): Move to cgraphbuild.c; rename to + build_cgrpah_edges; make visited_nodes local. + (cgraph_process_new_functions): DO not call initialize_inline_failed. + (record_references_in_initializer): Move to cgraphbuild.c + (initialize_inline_failed, rebuild_cgraph_edges, + pass_rebuild_cgraph_edges): Move to cgraphbuild.c. + (verify_cgraph_node): Make visited_nodes local. + (cgraph_analyze_function): Do not call cgraph_create_edges and + initialize_inline_failed. + (cgraph_expand_function): Do not call cgraph_lower_function; + assert that function is already lowered. + * Makefile.in (cgraphbuild.o): New. + * passes.c (init_optimization_passes): Add pass_build_cgraph_edges + at the end of lowering passes. + 2007-01-06 Steven Bosscher * ifcvt.c (cond_move_convert_if_block): New function, code diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 182b738c82f..1ec937a9d57 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1014,7 +1014,7 @@ OBJS-common = \ OBJS-md = $(out_object_file) OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o \ - cgraph.o cgraphunit.o tree-nomudflap.o ipa.o ipa-inline.o \ + cgraph.o cgraphunit.o cgraphbuild.o tree-nomudflap.o ipa.o ipa-inline.o \ ipa-utils.o ipa-reference.o ipa-pure-const.o ipa-type-escape.o \ ipa-prop.o ipa-cp.o varpool.o @@ -2269,6 +2269,9 @@ cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \ $(TREE_FLOW_H) tree-pass.h $(C_COMMON_H) debug.h $(DIAGNOSTIC_H) \ $(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) ipa-prop.h +cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(TREE_GIMPLE_H) \ + $(TREE_FLOW_H) tree-pass.h varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(FLAGS_H) $(GGC_H) \ $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \ diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c new file mode 100644 index 00000000000..a2df564aa65 --- /dev/null +++ b/gcc/cgraphbuild.c @@ -0,0 +1,236 @@ +/* Callgraph construction. + Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Contributed by Jan Hubicka + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tree-flow.h" +#include "langhooks.h" +#include "pointer-set.h" +#include "cgraph.h" +#include "intl.h" +#include "tree-gimple.h" +#include "tree-pass.h" + +/* Walk tree and record all calls and references to functions/variables. + Called via walk_tree: TP is pointer to tree to be examined. */ + +static tree +record_reference (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + + switch (TREE_CODE (t)) + { + case VAR_DECL: + if (TREE_STATIC (t) || DECL_EXTERNAL (t)) + { + varpool_mark_needed_node (varpool_node (t)); + if (lang_hooks.callgraph.analyze_expr) + return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, + data); + } + break; + + case FDESC_EXPR: + case ADDR_EXPR: + if (flag_unit_at_a_time) + { + /* Record dereferences to the functions. This makes the + functions reachable unconditionally. */ + tree decl = TREE_OPERAND (*tp, 0); + if (TREE_CODE (decl) == FUNCTION_DECL) + cgraph_mark_needed_node (cgraph_node (decl)); + } + break; + + default: + /* Save some cycles by not walking types and declaration as we + won't find anything useful there anyway. */ + if (IS_TYPE_OR_DECL_P (*tp)) + { + *walk_subtrees = 0; + break; + } + + if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE) + return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, data); + break; + } + + return NULL_TREE; +} + +/* Give initial reasons why inlining would fail on all calls from + NODE. Those get either nullified or usually overwritten by more precise + reason later. */ + +static void +initialize_inline_failed (struct cgraph_node *node) +{ + struct cgraph_edge *e; + + for (e = node->callers; e; e = e->next_caller) + { + gcc_assert (!e->callee->global.inlined_to); + gcc_assert (e->inline_failed); + if (node->local.redefined_extern_inline) + e->inline_failed = N_("redefined extern inline functions are not " + "considered for inlining"); + else if (!node->local.inlinable) + e->inline_failed = N_("function not inlinable"); + else + e->inline_failed = N_("function not considered for inlining"); + } +} + +/* Create cgraph edges for function calls. + Also look for functions and variables having addresses taken. */ + +static unsigned int +build_cgraph_edges (void) +{ + basic_block bb; + struct cgraph_node *node = cgraph_node (current_function_decl); + struct pointer_set_t *visited_nodes = pointer_set_create (); + block_stmt_iterator bsi; + tree step; + + /* Create the callgraph edges and record the nodes referenced by the function. + body. */ + 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); + tree decl; + + if (call && (decl = get_callee_fndecl (call))) + { + cgraph_create_edge (node, cgraph_node (decl), stmt, + bb->count, + bb->loop_depth); + walk_tree (&TREE_OPERAND (call, 1), + record_reference, node, visited_nodes); + if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT) + walk_tree (&GIMPLE_STMT_OPERAND (stmt, 0), + record_reference, node, visited_nodes); + } + else + walk_tree (bsi_stmt_ptr (bsi), record_reference, node, visited_nodes); + } + + /* Look for initializers of constant variables and private statics. */ + for (step = cfun->unexpanded_var_list; + step; + step = TREE_CHAIN (step)) + { + tree decl = TREE_VALUE (step); + if (TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + && flag_unit_at_a_time) + varpool_finalize_decl (decl); + else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl)) + walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes); + } + + pointer_set_destroy (visited_nodes); + initialize_inline_failed (node); + return 0; +} + +struct tree_opt_pass pass_build_cgraph_edges = +{ + NULL, /* name */ + NULL, /* gate */ + build_cgraph_edges, /* 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 */ +}; + +/* Record references to functions and other variables present in the + initial value of DECL, a variable. */ + +void +record_references_in_initializer (tree decl) +{ + struct pointer_set_t *visited_nodes = pointer_set_create (); + walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes); + pointer_set_destroy (visited_nodes); +} + +/* Rebuild cgraph edges for current function node. This needs to be run after + passes that don't update the cgraph. */ + +static unsigned int +rebuild_cgraph_edges (void) +{ + basic_block bb; + struct cgraph_node *node = cgraph_node (current_function_decl); + block_stmt_iterator bsi; + + cgraph_node_remove_callees (node); + + node->count = ENTRY_BLOCK_PTR->count; + + 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); + tree decl; + + if (call && (decl = get_callee_fndecl (call))) + cgraph_create_edge (node, cgraph_node (decl), stmt, + bb->count, + bb->loop_depth); + } + initialize_inline_failed (node); + gcc_assert (!node->global.inlined_to); + return 0; +} + +struct tree_opt_pass pass_rebuild_cgraph_edges = +{ + NULL, /* name */ + NULL, /* gate */ + rebuild_cgraph_edges, /* 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 */ +}; diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index b1c5c8b461f..e6f9db4a22c 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -164,16 +164,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA static void cgraph_expand_all_functions (void); static void cgraph_mark_functions_to_output (void); static void cgraph_expand_function (struct cgraph_node *); -static tree record_reference (tree *, int *, void *); static void cgraph_output_pending_asms (void); static void cgraph_increase_alignment (void); -static void initialize_inline_failed (struct cgraph_node *); - -/* Records tree nodes seen in record_reference. Simply using - walk_tree_without_duplicates doesn't guarantee each node is visited - once because it gets a new htab upon each recursive call from - record_reference itself. */ -static struct pointer_set_t *visited_nodes; static FILE *cgraph_dump_file; @@ -311,7 +303,6 @@ cgraph_process_new_functions (void) /* Inlining characteristics are maintained by the cgraph_mark_inline. */ node->global.insns = node->local.self_insns; - initialize_inline_failed (node); if (flag_really_no_inline && !node->local.disregard_inline_limits) node->local.inlinable = 0; if ((cgraph_state == CGRAPH_STATE_IPA_SSA @@ -495,189 +486,6 @@ cgraph_finalize_function (tree decl, bool nested) do_warn_unused_parameter (decl); } -/* Walk tree and record all calls. Called via walk_tree. */ -static tree -record_reference (tree *tp, int *walk_subtrees, void *data) -{ - tree t = *tp; - - switch (TREE_CODE (t)) - { - case VAR_DECL: - /* ??? Really, we should mark this decl as *potentially* referenced - by this function and re-examine whether the decl is actually used - after rtl has been generated. */ - if (TREE_STATIC (t) || DECL_EXTERNAL (t)) - { - varpool_mark_needed_node (varpool_node (t)); - if (lang_hooks.callgraph.analyze_expr) - return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, - data); - } - break; - - case FDESC_EXPR: - case ADDR_EXPR: - if (flag_unit_at_a_time) - { - /* Record dereferences to the functions. This makes the - functions reachable unconditionally. */ - tree decl = TREE_OPERAND (*tp, 0); - if (TREE_CODE (decl) == FUNCTION_DECL) - cgraph_mark_needed_node (cgraph_node (decl)); - } - break; - - default: - /* Save some cycles by not walking types and declaration as we - won't find anything useful there anyway. */ - if (IS_TYPE_OR_DECL_P (*tp)) - { - *walk_subtrees = 0; - break; - } - - if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE) - return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, data); - break; - } - - return NULL; -} - -/* Create cgraph edges for function calls inside BODY from NODE. */ - -static void -cgraph_create_edges (struct cgraph_node *node, tree body) -{ - basic_block bb; - - struct function *this_cfun = DECL_STRUCT_FUNCTION (body); - block_stmt_iterator bsi; - tree step; - 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 (bb, this_cfun) - for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) - { - tree stmt = bsi_stmt (bsi); - tree call = get_call_expr_in (stmt); - tree decl; - - if (call && (decl = get_callee_fndecl (call))) - { - cgraph_create_edge (node, cgraph_node (decl), stmt, - bb->count, - bb->loop_depth); - walk_tree (&TREE_OPERAND (call, 1), - record_reference, node, visited_nodes); - if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT) - walk_tree (&GIMPLE_STMT_OPERAND (stmt, 0), - record_reference, node, visited_nodes); - } - else - walk_tree (bsi_stmt_ptr (bsi), record_reference, node, visited_nodes); - } - - /* Look for initializers of constant variables and private statics. */ - for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list; - step; - step = TREE_CHAIN (step)) - { - tree decl = TREE_VALUE (step); - if (TREE_CODE (decl) == VAR_DECL - && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) - && flag_unit_at_a_time) - varpool_finalize_decl (decl); - else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl)) - walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes); - } - - pointer_set_destroy (visited_nodes); - visited_nodes = NULL; -} - -void -record_references_in_initializer (tree decl) -{ - visited_nodes = pointer_set_create (); - walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes); - pointer_set_destroy (visited_nodes); - visited_nodes = NULL; -} - - -/* Give initial reasons why inlining would fail. Those gets - either NULLified or usually overwritten by more precise reason - later. */ -static void -initialize_inline_failed (struct cgraph_node *node) -{ - struct cgraph_edge *e; - - for (e = node->callers; e; e = e->next_caller) - { - gcc_assert (!e->callee->global.inlined_to); - gcc_assert (e->inline_failed); - if (node->local.redefined_extern_inline) - e->inline_failed = N_("redefined extern inline functions are not " - "considered for inlining"); - else if (!node->local.inlinable) - e->inline_failed = N_("function not inlinable"); - else - e->inline_failed = N_("function not considered for inlining"); - } -} - -/* Rebuild call edges from current function after a passes not aware - of cgraph updating. */ -static unsigned int -rebuild_cgraph_edges (void) -{ - basic_block bb; - struct cgraph_node *node = cgraph_node (current_function_decl); - block_stmt_iterator bsi; - - cgraph_node_remove_callees (node); - - node->count = ENTRY_BLOCK_PTR->count; - - 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); - tree decl; - - if (call && (decl = get_callee_fndecl (call))) - cgraph_create_edge (node, cgraph_node (decl), stmt, - bb->count, - bb->loop_depth); - } - initialize_inline_failed (node); - gcc_assert (!node->global.inlined_to); - return 0; -} - -struct tree_opt_pass pass_rebuild_cgraph_edges = -{ - NULL, /* name */ - NULL, /* gate */ - rebuild_cgraph_edges, /* 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 */ -}; - /* Verify cgraph nodes of given cgraph node. */ void verify_cgraph_node (struct cgraph_node *node) @@ -763,7 +571,7 @@ verify_cgraph_node (struct cgraph_node *node) { /* The nodes we're interested in are never shared, so walk the tree ignoring duplicates. */ - visited_nodes = pointer_set_create (); + struct pointer_set_t *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) @@ -802,7 +610,6 @@ verify_cgraph_node (struct cgraph_node *node) } } pointer_set_destroy (visited_nodes); - visited_nodes = NULL; } else /* No CFG available?! */ @@ -867,9 +674,6 @@ cgraph_analyze_function (struct cgraph_node *node) push_cfun (DECL_STRUCT_FUNCTION (decl)); cgraph_lower_function (node); - /* First kill forward declaration so reverse inlining works properly. */ - cgraph_create_edges (node, decl); - node->local.estimated_self_stack_size = estimated_stack_frame_size (); node->global.estimated_stack_size = node->local.estimated_self_stack_size; node->global.stack_frame_offset = 0; @@ -879,7 +683,6 @@ cgraph_analyze_function (struct cgraph_node *node) if (node->local.inlinable) node->local.disregard_inline_limits = lang_hooks.tree_inlining.disregard_inline_limits (decl); - initialize_inline_failed (node); if (flag_really_no_inline && !node->local.disregard_inline_limits) node->local.inlinable = 0; /* Inlining characteristics are maintained by the cgraph_mark_inline. */ @@ -1167,7 +970,8 @@ cgraph_expand_function (struct cgraph_node *node) if (flag_unit_at_a_time) announce_function (decl); - cgraph_lower_function (node); + gcc_assert (node->lowered); + /*cgraph_lower_function (node);*/ /* Generate RTL for the body of DECL. */ lang_hooks.callgraph.expand_function (decl); diff --git a/gcc/passes.c b/gcc/passes.c index d40f84e2688..91c9f1eff2a 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -461,6 +461,7 @@ init_optimization_passes (void) NEXT_PASS (pass_lower_complex_O0); NEXT_PASS (pass_lower_vector); NEXT_PASS (pass_warn_function_return); + NEXT_PASS (pass_build_cgraph_edges); *p = NULL; p = &pass_early_local_passes.sub; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 01a0c7dfcff..0cec9d4f993 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -303,6 +303,7 @@ extern struct tree_opt_pass pass_uncprop; extern struct tree_opt_pass pass_return_slot; extern struct tree_opt_pass pass_reassoc; extern struct tree_opt_pass pass_rebuild_cgraph_edges; +extern struct tree_opt_pass pass_build_cgraph_edges; extern struct tree_opt_pass pass_reset_cc_flags; /* IPA Passes */