Commit f45e0ad1 by Jan Hubicka Committed by Jan Hubicka

cgraph.c (cgraph_exapnd_queue): Rename to...


	* cgraph.c (cgraph_exapnd_queue): Rename to...
	(cgraph_new_nodes): ... this one.
	(cgraph_state): New global variable.
	(cgraph_add_new_function): Work in more cases.
	* cgraph.h (cgraph_expand_queue): Rename to ...
	(cgraph_new_nodes): ... this one.
	(cgraph_state): New enum and static variable.
	(cgraph_add_new_function): Update prototype.
	(cgraph_process_new_functions): New.
	* omp-low.c (expand_omp_parallel): Update.
	* cgraphunit.c (initialize_inline_failed): Declare early.
	(cgraph_process_new_functions): New function.
	(cgraph_assemble_pending_functions): Use it.
	(cgraph_expand_all_functions): Use it.
	(cgraph_optimize): Use it; set cgraph_state.
	* passes.c (execute_one_pass, execute_ipa_pass_list): Process new
	functions

From-SVN: r120282
parent e288c21a
2006-12-29 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_exapnd_queue): Rename to...
(cgraph_new_nodes): ... this one.
(cgraph_state): New global variable.
(cgraph_add_new_function): Work in more cases.
* cgraph.h (cgraph_expand_queue): Rename to ...
(cgraph_new_nodes): ... this one.
(cgraph_state): New enum and static variable.
(cgraph_add_new_function): Update prototype.
(cgraph_process_new_functions): New.
* omp-low.c (expand_omp_parallel): Update.
* cgraphunit.c (initialize_inline_failed): Declare early.
(cgraph_process_new_functions): New function.
(cgraph_assemble_pending_functions): Use it.
(cgraph_expand_all_functions): Use it.
(cgraph_optimize): Use it; set cgraph_state.
* passes.c (execute_one_pass, execute_ipa_pass_list): Process new
functions
2006-12-29 Kazu Hirata <kazu@codesourcery.com>
* tree-cfg.c (last_stmt_ptr): Remove.
......
......@@ -97,10 +97,10 @@ struct cgraph_node *cgraph_nodes;
/* Queue of cgraph nodes scheduled to be lowered. */
struct cgraph_node *cgraph_nodes_queue;
/* Queue of cgraph nodes scheduled to be expanded. This is a
/* Queue of cgraph nodes scheduled to be added into cgraph. This is a
secondary queue used during optimization to accommodate passes that
may generate new functions that need to be optimized and expanded. */
struct cgraph_node *cgraph_expand_queue;
struct cgraph_node *cgraph_new_nodes;
/* Number of nodes in existence. */
int cgraph_n_nodes;
......@@ -111,6 +111,9 @@ int cgraph_max_uid;
/* Set when whole unit has been analyzed so we can access global info. */
bool cgraph_global_info_ready = false;
/* What state callgraph is in right now. */
enum cgraph_state cgraph_state = CGRAPH_STATE_CONSTRUCTION;
/* Set when the cgraph is fully build and the basic flags are computed. */
bool cgraph_function_flags_ready = false;
......@@ -911,23 +914,60 @@ cgraph_function_body_availability (struct cgraph_node *node)
return avail;
}
/* Add the function FNDECL to the call graph. FNDECL is assumed to be
in low GIMPLE form and ready to be processed by cgraph_finalize_function.
/* Add the function FNDECL to the call graph.
Unlike cgraph_finalize_function, this function is intended to be used
by middle end and allows insertion of new function at arbitrary point
of compilation. The function can be either in high, low or SSA form
GIMPLE.
When operating in unit-at-a-time, a new callgraph node is added to
CGRAPH_EXPAND_QUEUE, which is processed after all the original
functions in the call graph .
The function is assumed to be reachable and have address taken (so no
API breaking optimizations are performed on it).
When not in unit-at-a-time, the new callgraph node is added to
CGRAPH_NODES_QUEUE for cgraph_assemble_pending_functions to
process. */
Main work done by this function is to enqueue the function for later
processing to avoid need the passes to be re-entrant. */
void
cgraph_add_new_function (tree fndecl)
cgraph_add_new_function (tree fndecl, bool lowered)
{
struct cgraph_node *n = cgraph_node (fndecl);
n->next_needed = cgraph_expand_queue;
cgraph_expand_queue = n;
struct cgraph_node *node;
switch (cgraph_state)
{
case CGRAPH_STATE_CONSTRUCTION:
/* Just enqueue function to be processed at nearest occurence. */
node = cgraph_node (fndecl);
node->next_needed = cgraph_new_nodes;
if (lowered)
node->lowered = true;
cgraph_new_nodes = node;
break;
case CGRAPH_STATE_IPA:
case CGRAPH_STATE_EXPANSION:
/* Bring the function into finalized state and enqueue for later
analyzing and compilation. */
node = cgraph_node (fndecl);
node->local.local = false;
node->local.finalized = true;
node->reachable = node->needed = true;
if (lowered)
node->lowered = true;
node->next_needed = cgraph_new_nodes;
cgraph_new_nodes = node;
break;
case CGRAPH_STATE_FINISHED:
/* At the very end of compilation we have to do all the work up
to expansion. */
push_cfun (DECL_STRUCT_FUNCTION (fndecl));
current_function_decl = fndecl;
tree_register_cfg_hooks ();
if (!lowered)
tree_lowering_passes (fndecl);
tree_rest_of_compilation (fndecl);
pop_cfun ();
current_function_decl = NULL;
break;
}
}
#include "gt-cgraph.h"
......@@ -254,9 +254,21 @@ extern GTY(()) struct cgraph_node *cgraph_nodes;
extern GTY(()) int cgraph_n_nodes;
extern GTY(()) int cgraph_max_uid;
extern bool cgraph_global_info_ready;
enum cgraph_state
{
/* Callgraph is being constructed. It is safe to add new functions. */
CGRAPH_STATE_CONSTRUCTION,
/* Callgraph is built and IPA passes are being run. */
CGRAPH_STATE_IPA,
/* Functions are now ordered and being passed to RTL expanders. */
CGRAPH_STATE_EXPANSION,
/* All cgraph expansion is done. */
CGRAPH_STATE_FINISHED
};
extern enum cgraph_state cgraph_state;
extern bool cgraph_function_flags_ready;
extern GTY(()) struct cgraph_node *cgraph_nodes_queue;
extern GTY(()) struct cgraph_node *cgraph_expand_queue;
extern GTY(()) struct cgraph_node *cgraph_new_nodes;
extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
extern GTY(()) int cgraph_order;
......@@ -295,7 +307,7 @@ void cgraph_unnest_node (struct cgraph_node *);
enum availability cgraph_function_body_availability (struct cgraph_node *);
bool cgraph_is_master_clone (struct cgraph_node *);
struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
void cgraph_add_new_function (tree);
void cgraph_add_new_function (tree, bool);
/* In cgraphunit.c */
void cgraph_finalize_function (tree, bool);
......@@ -316,6 +328,7 @@ struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
void cgraph_analyze_function (struct cgraph_node *);
struct cgraph_node *save_inline_function_body (struct cgraph_node *);
void record_references_in_initializer (tree);
bool cgraph_process_new_functions (void);
/* In ipa.c */
bool cgraph_remove_unreachable_nodes (bool, FILE *);
......
......@@ -167,6 +167,7 @@ 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
......@@ -262,6 +263,77 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
return false;
}
/* Process CGRAPH_NEW_FUNCTIONS and perform actions neccesary to add these
functions into callgraph in a way so they look like ordinary reachable
functions inserted into callgraph already at construction time. */
bool
cgraph_process_new_functions (void)
{
bool output = false;
tree fndecl;
struct cgraph_node *node;
/* Note that this queue may grow as its being processed, as the new
functions may generate new ones. */
while (cgraph_new_nodes)
{
node = cgraph_new_nodes;
fndecl = node->decl;
cgraph_new_nodes = cgraph_new_nodes->next_needed;
switch (cgraph_state)
{
case CGRAPH_STATE_CONSTRUCTION:
/* At construction time we just need to finalize function and move
it into reachable functions list. */
node->next_needed = NULL;
cgraph_finalize_function (fndecl, false);
cgraph_mark_reachable_node (node);
output = true;
break;
case CGRAPH_STATE_IPA:
/* When IPA optimization already started, do all essential
transformations that has been already performed on the whole
cgraph but not on this function. */
tree_register_cfg_hooks ();
if (!node->analyzed)
cgraph_analyze_function (node);
push_cfun (DECL_STRUCT_FUNCTION (fndecl));
current_function_decl = fndecl;
node->local.inlinable = tree_inlinable_function_p (fndecl);
node->local.self_insns = estimate_num_insns (fndecl);
node->local.disregard_inline_limits
= lang_hooks.tree_inlining.disregard_inline_limits (fndecl);
/* 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;
free_dominance_info (CDI_POST_DOMINATORS);
free_dominance_info (CDI_DOMINATORS);
pop_cfun ();
current_function_decl = NULL;
break;
case CGRAPH_STATE_EXPANSION:
/* Functions created during expansion shall be compiled
directly. */
node->output = 0;
cgraph_expand_function (node);
break;
default:
gcc_unreachable ();
break;
}
}
return output;
}
/* When not doing unit-at-a-time, output all functions enqueued.
Return true when such a functions were found. */
......@@ -288,18 +360,7 @@ cgraph_assemble_pending_functions (void)
cgraph_expand_function (n);
output = true;
}
}
/* Process CGRAPH_EXPAND_QUEUE, these are functions created during
the expansion process. Note that this queue may grow as its
being processed, as the new functions may generate new ones. */
while (cgraph_expand_queue)
{
struct cgraph_node *n = cgraph_expand_queue;
cgraph_expand_queue = cgraph_expand_queue->next_needed;
n->next_needed = NULL;
cgraph_finalize_function (n->decl, false);
output = true;
output |= cgraph_process_new_functions ();
}
return output;
......@@ -1161,21 +1222,10 @@ cgraph_expand_all_functions (void)
cgraph_expand_function (node);
}
}
cgraph_process_new_functions ();
free (order);
/* Process CGRAPH_EXPAND_QUEUE, these are functions created during
the expansion process. Note that this queue may grow as its
being processed, as the new functions may generate new ones. */
while (cgraph_expand_queue)
{
node = cgraph_expand_queue;
cgraph_expand_queue = cgraph_expand_queue->next_needed;
node->next_needed = NULL;
node->output = 0;
node->lowered = DECL_STRUCT_FUNCTION (node->decl)->cfg != NULL;
cgraph_expand_function (node);
}
}
/* This is used to sort the node types by the cgraph order number. */
......@@ -1383,6 +1433,9 @@ cgraph_optimize (void)
#endif
if (!flag_unit_at_a_time)
{
cgraph_assemble_pending_functions ();
cgraph_process_new_functions ();
cgraph_state = CGRAPH_STATE_FINISHED;
cgraph_output_pending_asms ();
varpool_assemble_pending_decls ();
varpool_output_debug_info ();
......@@ -1408,6 +1461,7 @@ cgraph_optimize (void)
fprintf (cgraph_dump_file, "Marked ");
dump_cgraph (cgraph_dump_file);
}
cgraph_state = CGRAPH_STATE_IPA;
/* Don't run the IPA passes if there was any error or sorry messages. */
if (errorcount == 0 && sorrycount == 0)
......@@ -1440,6 +1494,7 @@ cgraph_optimize (void)
cgraph_mark_functions_to_output ();
cgraph_state = CGRAPH_STATE_EXPANSION;
if (!flag_toplevel_reorder)
cgraph_output_in_order ();
else
......@@ -1452,6 +1507,8 @@ cgraph_optimize (void)
varpool_assemble_pending_decls ();
varpool_output_debug_info ();
}
cgraph_process_new_functions ();
cgraph_state = CGRAPH_STATE_FINISHED;
if (cgraph_dump_file)
{
......@@ -1581,14 +1638,8 @@ cgraph_build_static_cdtor (char which, tree body, int priority)
gimplify_function_tree (decl);
/* ??? We will get called LATE in the compilation process. */
if (cgraph_global_info_ready)
{
tree_lowering_passes (decl);
tree_rest_of_compilation (decl);
}
else
cgraph_finalize_function (decl, 0);
cgraph_add_new_function (decl, false);
cgraph_mark_needed_node (cgraph_node (decl));
if (targetm.have_ctors_dtors)
{
......
......@@ -2533,7 +2533,7 @@ expand_omp_parallel (struct omp_region *region)
single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
DECL_STRUCT_FUNCTION (child_fn)->curr_properties
= cfun->curr_properties;
cgraph_add_new_function (child_fn);
cgraph_add_new_function (child_fn, true);
/* Convert OMP_RETURN into a RETURN_EXPR. */
if (exit_bb)
......
......@@ -947,6 +947,9 @@ execute_one_pass (struct tree_opt_pass *pass)
/* Run post-pass cleanup and verification. */
execute_todo (todo_after | pass->todo_flags_finish);
if (!current_function_decl)
cgraph_process_new_functions ();
/* Flush and close dump file. */
if (dump_file_name)
{
......@@ -986,6 +989,8 @@ execute_ipa_pass_list (struct tree_opt_pass *pass)
gcc_assert (!cfun);
if (execute_one_pass (pass) && pass->sub)
do_per_function ((void (*)(void *))execute_pass_list, pass->sub);
if (!current_function_decl)
cgraph_process_new_functions ();
pass = pass->next;
}
while (pass);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment