mirror of git://gcc.gnu.org/git/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
This commit is contained in:
parent
dc1f5a1118
commit
2dee695bfc
|
|
@ -1,3 +1,23 @@
|
||||||
|
2007-01-06 Jan Hubicka <jh@suse.cz>
|
||||||
|
|
||||||
|
* 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 <steven@gcc.gnu.org>
|
2007-01-06 Steven Bosscher <steven@gcc.gnu.org>
|
||||||
|
|
||||||
* ifcvt.c (cond_move_convert_if_block): New function, code
|
* ifcvt.c (cond_move_convert_if_block): New function, code
|
||||||
|
|
|
||||||
|
|
@ -1014,7 +1014,7 @@ OBJS-common = \
|
||||||
|
|
||||||
OBJS-md = $(out_object_file)
|
OBJS-md = $(out_object_file)
|
||||||
OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o \
|
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-utils.o ipa-reference.o ipa-pure-const.o ipa-type-escape.o \
|
||||||
ipa-prop.o ipa-cp.o varpool.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) \
|
$(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) \
|
$(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
|
$(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) \
|
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) \
|
$(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) \
|
$(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
};
|
||||||
202
gcc/cgraphunit.c
202
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_expand_all_functions (void);
|
||||||
static void cgraph_mark_functions_to_output (void);
|
static void cgraph_mark_functions_to_output (void);
|
||||||
static void cgraph_expand_function (struct cgraph_node *);
|
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_output_pending_asms (void);
|
||||||
static void cgraph_increase_alignment (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;
|
static FILE *cgraph_dump_file;
|
||||||
|
|
||||||
|
|
@ -311,7 +303,6 @@ cgraph_process_new_functions (void)
|
||||||
/* Inlining characteristics are maintained by the
|
/* Inlining characteristics are maintained by the
|
||||||
cgraph_mark_inline. */
|
cgraph_mark_inline. */
|
||||||
node->global.insns = node->local.self_insns;
|
node->global.insns = node->local.self_insns;
|
||||||
initialize_inline_failed (node);
|
|
||||||
if (flag_really_no_inline && !node->local.disregard_inline_limits)
|
if (flag_really_no_inline && !node->local.disregard_inline_limits)
|
||||||
node->local.inlinable = 0;
|
node->local.inlinable = 0;
|
||||||
if ((cgraph_state == CGRAPH_STATE_IPA_SSA
|
if ((cgraph_state == CGRAPH_STATE_IPA_SSA
|
||||||
|
|
@ -495,189 +486,6 @@ cgraph_finalize_function (tree decl, bool nested)
|
||||||
do_warn_unused_parameter (decl);
|
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. */
|
/* Verify cgraph nodes of given cgraph node. */
|
||||||
void
|
void
|
||||||
verify_cgraph_node (struct cgraph_node *node)
|
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 nodes we're interested in are never shared, so walk
|
||||||
the tree ignoring duplicates. */
|
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
|
/* Reach the trees by walking over the CFG, and note the
|
||||||
enclosing basic-blocks in the call edges. */
|
enclosing basic-blocks in the call edges. */
|
||||||
FOR_EACH_BB_FN (this_block, this_cfun)
|
FOR_EACH_BB_FN (this_block, this_cfun)
|
||||||
|
|
@ -802,7 +610,6 @@ verify_cgraph_node (struct cgraph_node *node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pointer_set_destroy (visited_nodes);
|
pointer_set_destroy (visited_nodes);
|
||||||
visited_nodes = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* No CFG available?! */
|
/* No CFG available?! */
|
||||||
|
|
@ -867,9 +674,6 @@ cgraph_analyze_function (struct cgraph_node *node)
|
||||||
push_cfun (DECL_STRUCT_FUNCTION (decl));
|
push_cfun (DECL_STRUCT_FUNCTION (decl));
|
||||||
cgraph_lower_function (node);
|
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->local.estimated_self_stack_size = estimated_stack_frame_size ();
|
||||||
node->global.estimated_stack_size = node->local.estimated_self_stack_size;
|
node->global.estimated_stack_size = node->local.estimated_self_stack_size;
|
||||||
node->global.stack_frame_offset = 0;
|
node->global.stack_frame_offset = 0;
|
||||||
|
|
@ -879,7 +683,6 @@ cgraph_analyze_function (struct cgraph_node *node)
|
||||||
if (node->local.inlinable)
|
if (node->local.inlinable)
|
||||||
node->local.disregard_inline_limits
|
node->local.disregard_inline_limits
|
||||||
= lang_hooks.tree_inlining.disregard_inline_limits (decl);
|
= lang_hooks.tree_inlining.disregard_inline_limits (decl);
|
||||||
initialize_inline_failed (node);
|
|
||||||
if (flag_really_no_inline && !node->local.disregard_inline_limits)
|
if (flag_really_no_inline && !node->local.disregard_inline_limits)
|
||||||
node->local.inlinable = 0;
|
node->local.inlinable = 0;
|
||||||
/* Inlining characteristics are maintained by the cgraph_mark_inline. */
|
/* 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)
|
if (flag_unit_at_a_time)
|
||||||
announce_function (decl);
|
announce_function (decl);
|
||||||
|
|
||||||
cgraph_lower_function (node);
|
gcc_assert (node->lowered);
|
||||||
|
/*cgraph_lower_function (node);*/
|
||||||
|
|
||||||
/* Generate RTL for the body of DECL. */
|
/* Generate RTL for the body of DECL. */
|
||||||
lang_hooks.callgraph.expand_function (decl);
|
lang_hooks.callgraph.expand_function (decl);
|
||||||
|
|
|
||||||
|
|
@ -461,6 +461,7 @@ init_optimization_passes (void)
|
||||||
NEXT_PASS (pass_lower_complex_O0);
|
NEXT_PASS (pass_lower_complex_O0);
|
||||||
NEXT_PASS (pass_lower_vector);
|
NEXT_PASS (pass_lower_vector);
|
||||||
NEXT_PASS (pass_warn_function_return);
|
NEXT_PASS (pass_warn_function_return);
|
||||||
|
NEXT_PASS (pass_build_cgraph_edges);
|
||||||
*p = NULL;
|
*p = NULL;
|
||||||
|
|
||||||
p = &pass_early_local_passes.sub;
|
p = &pass_early_local_passes.sub;
|
||||||
|
|
|
||||||
|
|
@ -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_return_slot;
|
||||||
extern struct tree_opt_pass pass_reassoc;
|
extern struct tree_opt_pass pass_reassoc;
|
||||||
extern struct tree_opt_pass pass_rebuild_cgraph_edges;
|
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;
|
extern struct tree_opt_pass pass_reset_cc_flags;
|
||||||
|
|
||||||
/* IPA Passes */
|
/* IPA Passes */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue