cgraph.c (dump_cgraph_node): Print new flags.
* cgraph.c (dump_cgraph_node): Print new flags. (dump_cgraph_varpool_node): Likewise. (decide_variable_is_needed): Initialize externally_visible flag. * cgraph.h (cgraph_local_info): Add externally_visible flag. (cgraph_varpool_node): Likewise. (cgraph_function_flags_ready): Declare. * cgraph.c (cgraph_mark_local_functions): Rename to ... (cgraph_function_and_variable_visibility) ... this one; handle externally_visible flags. (decide_is_function_needed): Set externally_visible flag. (cgraph_finalize_function): Deal properly with early cleanups. (cgraph_optimize): Update call of cgraph_function_and_variable_visibility. From-SVN: r100491
This commit is contained in:
parent
75c702541a
commit
e7d6beb0f8
|
@ -1,3 +1,19 @@
|
||||||
|
2005-06-02 Jan Hubicka <jh@suse.cz>
|
||||||
|
|
||||||
|
* cgraph.c (dump_cgraph_node): Print new flags.
|
||||||
|
(dump_cgraph_varpool_node): Likewise.
|
||||||
|
(decide_variable_is_needed): Initialize externally_visible flag.
|
||||||
|
* cgraph.h (cgraph_local_info): Add externally_visible flag.
|
||||||
|
(cgraph_varpool_node): Likewise.
|
||||||
|
(cgraph_function_flags_ready): Declare.
|
||||||
|
* cgraph.c (cgraph_mark_local_functions): Rename to ...
|
||||||
|
(cgraph_function_and_variable_visibility) ... this one; handle
|
||||||
|
externally_visible flags.
|
||||||
|
(decide_is_function_needed): Set externally_visible flag.
|
||||||
|
(cgraph_finalize_function): Deal properly with early cleanups.
|
||||||
|
(cgraph_optimize): Update call of
|
||||||
|
cgraph_function_and_variable_visibility.
|
||||||
|
|
||||||
2005-06-02 Steven Bosscher <stevenb@suse.de>
|
2005-06-02 Steven Bosscher <stevenb@suse.de>
|
||||||
Mostafa Hagog <mustafa@il.ibm.com>
|
Mostafa Hagog <mustafa@il.ibm.com>
|
||||||
|
|
||||||
|
|
17
gcc/cgraph.c
17
gcc/cgraph.c
|
@ -582,10 +582,16 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
|
||||||
fprintf (f, " output");
|
fprintf (f, " output");
|
||||||
if (node->local.local)
|
if (node->local.local)
|
||||||
fprintf (f, " local");
|
fprintf (f, " local");
|
||||||
|
if (node->local.externally_visible)
|
||||||
|
fprintf (f, " externally_visible");
|
||||||
|
if (node->local.finalized)
|
||||||
|
fprintf (f, " finalized");
|
||||||
if (node->local.disregard_inline_limits)
|
if (node->local.disregard_inline_limits)
|
||||||
fprintf (f, " always_inline");
|
fprintf (f, " always_inline");
|
||||||
else if (node->local.inlinable)
|
else if (node->local.inlinable)
|
||||||
fprintf (f, " inlinable");
|
fprintf (f, " inlinable");
|
||||||
|
if (node->local.redefined_extern_inline)
|
||||||
|
fprintf (f, " redefined_extern_inline");
|
||||||
if (TREE_ASM_WRITTEN (node->decl))
|
if (TREE_ASM_WRITTEN (node->decl))
|
||||||
fprintf (f, " asm_written");
|
fprintf (f, " asm_written");
|
||||||
|
|
||||||
|
@ -639,6 +645,8 @@ dump_cgraph_varpool_node (FILE *f, struct cgraph_varpool_node *node)
|
||||||
fprintf (f, " finalized");
|
fprintf (f, " finalized");
|
||||||
if (node->output)
|
if (node->output)
|
||||||
fprintf (f, " output");
|
fprintf (f, " output");
|
||||||
|
if (node->externally_visible)
|
||||||
|
fprintf (f, " externally_visible");
|
||||||
fprintf (f, "\n");
|
fprintf (f, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,8 +794,8 @@ decide_is_variable_needed (struct cgraph_varpool_node *node, tree decl)
|
||||||
if (node->needed)
|
if (node->needed)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Externally visible functions must be output. The exception is
|
/* Externally visible variables must be output. The exception is
|
||||||
COMDAT functions that must be output only when they are needed. */
|
COMDAT variables that must be output only when they are needed. */
|
||||||
if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
|
if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -824,6 +832,11 @@ cgraph_varpool_finalize_decl (tree decl)
|
||||||
|
|
||||||
if (decide_is_variable_needed (node, decl))
|
if (decide_is_variable_needed (node, decl))
|
||||||
cgraph_varpool_mark_needed_node (node);
|
cgraph_varpool_mark_needed_node (node);
|
||||||
|
/* Since we reclaim unrechable nodes at the end of every language
|
||||||
|
level unit, we need to be conservative about possible entry points
|
||||||
|
there. */
|
||||||
|
if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
|
||||||
|
cgraph_varpool_mark_needed_node (node);
|
||||||
if (cgraph_global_info_ready || !flag_unit_at_a_time)
|
if (cgraph_global_info_ready || !flag_unit_at_a_time)
|
||||||
cgraph_varpool_assemble_pending_decls ();
|
cgraph_varpool_assemble_pending_decls ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,9 @@ struct cgraph_local_info GTY(())
|
||||||
and its address is never taken. */
|
and its address is never taken. */
|
||||||
bool local;
|
bool local;
|
||||||
|
|
||||||
|
/* Set when function is visible by other units. */
|
||||||
|
bool externally_visible;
|
||||||
|
|
||||||
/* Set once it has been finalized so we consider it to be output. */
|
/* Set once it has been finalized so we consider it to be output. */
|
||||||
bool finalized;
|
bool finalized;
|
||||||
|
|
||||||
|
@ -177,6 +180,8 @@ struct cgraph_varpool_node GTY(())
|
||||||
bool finalized;
|
bool finalized;
|
||||||
/* Set when function is scheduled to be assembled. */
|
/* Set when function is scheduled to be assembled. */
|
||||||
bool output;
|
bool output;
|
||||||
|
/* Set when function is visible by other units. */
|
||||||
|
bool externally_visible;
|
||||||
/* Set for aliases once they got through assemble_alias. */
|
/* Set for aliases once they got through assemble_alias. */
|
||||||
bool alias;
|
bool alias;
|
||||||
};
|
};
|
||||||
|
@ -185,6 +190,7 @@ extern GTY(()) struct cgraph_node *cgraph_nodes;
|
||||||
extern GTY(()) int cgraph_n_nodes;
|
extern GTY(()) int cgraph_n_nodes;
|
||||||
extern GTY(()) int cgraph_max_uid;
|
extern GTY(()) int cgraph_max_uid;
|
||||||
extern bool cgraph_global_info_ready;
|
extern bool cgraph_global_info_ready;
|
||||||
|
extern bool cgraph_function_flags_ready;
|
||||||
extern GTY(()) struct cgraph_node *cgraph_nodes_queue;
|
extern GTY(()) struct cgraph_node *cgraph_nodes_queue;
|
||||||
|
|
||||||
extern GTY(()) struct cgraph_varpool_node *cgraph_varpool_first_unanalyzed_node;
|
extern GTY(()) struct cgraph_varpool_node *cgraph_varpool_first_unanalyzed_node;
|
||||||
|
|
|
@ -170,7 +170,6 @@ 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 tree record_reference (tree *, int *, void *);
|
||||||
static void cgraph_mark_local_functions (void);
|
|
||||||
static void cgraph_analyze_function (struct cgraph_node *node);
|
static void cgraph_analyze_function (struct cgraph_node *node);
|
||||||
|
|
||||||
/* Records tree nodes seen in record_reference. Simply using
|
/* Records tree nodes seen in record_reference. Simply using
|
||||||
|
@ -191,6 +190,17 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
|
||||||
{
|
{
|
||||||
tree origin;
|
tree origin;
|
||||||
|
|
||||||
|
/* If the user told us it is used, then it must be so. */
|
||||||
|
if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* ??? If the assembler name is set by hand, it is possible to assemble
|
||||||
|
the name later after finalizing the function and the fact is noticed
|
||||||
|
in assemble_name then. This is arguably a bug. */
|
||||||
|
if (DECL_ASSEMBLER_NAME_SET_P (decl)
|
||||||
|
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
|
||||||
|
return true;
|
||||||
|
|
||||||
/* If we decided it was needed before, but at the time we didn't have
|
/* If we decided it was needed before, but at the time we didn't have
|
||||||
the body of the function available, then it's still needed. We have
|
the body of the function available, then it's still needed. We have
|
||||||
to go back and re-check its dependencies now. */
|
to go back and re-check its dependencies now. */
|
||||||
|
@ -207,17 +217,6 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
|
||||||
if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl))
|
if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* If the user told us it is used, then it must be so. */
|
|
||||||
if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* ??? If the assembler name is set by hand, it is possible to assemble
|
|
||||||
the name later after finalizing the function and the fact is noticed
|
|
||||||
in assemble_name then. This is arguably a bug. */
|
|
||||||
if (DECL_ASSEMBLER_NAME_SET_P (decl)
|
|
||||||
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (flag_unit_at_a_time)
|
if (flag_unit_at_a_time)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -422,6 +421,12 @@ cgraph_finalize_function (tree decl, bool nested)
|
||||||
if (decide_is_function_needed (node, decl))
|
if (decide_is_function_needed (node, decl))
|
||||||
cgraph_mark_needed_node (node);
|
cgraph_mark_needed_node (node);
|
||||||
|
|
||||||
|
/* Since we reclaim unrechable nodes at the end of every language
|
||||||
|
level unit, we need to be conservative about possible entry points
|
||||||
|
there. */
|
||||||
|
if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
|
||||||
|
cgraph_mark_reachable_node (node);
|
||||||
|
|
||||||
/* If not unit at a time, go ahead and emit everything we've found
|
/* If not unit at a time, go ahead and emit everything we've found
|
||||||
to be reachable at this time. */
|
to be reachable at this time. */
|
||||||
if (!nested)
|
if (!nested)
|
||||||
|
@ -1016,25 +1021,47 @@ cgraph_expand_all_functions (void)
|
||||||
free (order);
|
free (order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark all local functions.
|
/* Mark visibility of all functions.
|
||||||
|
|
||||||
A local function is one whose calls can occur only in the current
|
A local function is one whose calls can occur only in the current
|
||||||
compilation unit and all its calls are explicit, so we can change
|
compilation unit and all its calls are explicit, so we can change
|
||||||
its calling convention. We simply mark all static functions whose
|
its calling convention. We simply mark all static functions whose
|
||||||
address is not taken as local. */
|
address is not taken as local.
|
||||||
|
|
||||||
|
We also change the TREE_PUBLIC flag of all declarations that are public
|
||||||
|
in language point of view but we want to overwrite this default
|
||||||
|
via visibilities for the backend point of view. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cgraph_mark_local_functions (void)
|
cgraph_function_and_variable_visibility (void)
|
||||||
{
|
{
|
||||||
struct cgraph_node *node;
|
struct cgraph_node *node;
|
||||||
|
struct cgraph_varpool_node *vnode;
|
||||||
|
|
||||||
/* Figure out functions we want to assemble. */
|
|
||||||
for (node = cgraph_nodes; node; node = node->next)
|
for (node = cgraph_nodes; node; node = node->next)
|
||||||
{
|
{
|
||||||
|
if (node->reachable
|
||||||
|
&& (DECL_COMDAT (node->decl)
|
||||||
|
|| (TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
|
||||||
|
node->local.externally_visible = 1;
|
||||||
node->local.local = (!node->needed
|
node->local.local = (!node->needed
|
||||||
&& DECL_SAVED_TREE (node->decl)
|
&& node->analyzed
|
||||||
&& !TREE_PUBLIC (node->decl));
|
&& node->local.externally_visible);
|
||||||
}
|
}
|
||||||
|
for (vnode = cgraph_varpool_nodes_queue; vnode; vnode = vnode->next_needed)
|
||||||
|
{
|
||||||
|
if (vnode->needed
|
||||||
|
&& (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
|
||||||
|
vnode->externally_visible = 1;
|
||||||
|
gcc_assert (TREE_STATIC (vnode->decl));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Because we have to be conservative on the boundaries of source
|
||||||
|
level units, it is possible that we marked some functions in
|
||||||
|
reachable just because they might be used later via external
|
||||||
|
linkage, but after making them local they are really unreachable
|
||||||
|
now. */
|
||||||
|
cgraph_remove_unreachable_nodes (true, cgraph_dump_file);
|
||||||
|
|
||||||
if (cgraph_dump_file)
|
if (cgraph_dump_file)
|
||||||
{
|
{
|
||||||
|
@ -1043,7 +1070,13 @@ cgraph_mark_local_functions (void)
|
||||||
if (node->local.local)
|
if (node->local.local)
|
||||||
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
|
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
|
||||||
fprintf (cgraph_dump_file, "\n\n");
|
fprintf (cgraph_dump_file, "\n\n");
|
||||||
|
fprintf (cgraph_dump_file, "\nMarking externally visible functions:");
|
||||||
|
for (node = cgraph_nodes; node; node = node->next)
|
||||||
|
if (node->local.externally_visible)
|
||||||
|
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
|
||||||
|
fprintf (cgraph_dump_file, "\n\n");
|
||||||
}
|
}
|
||||||
|
cgraph_function_flags_ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true when function body of DECL still needs to be kept around
|
/* Return true when function body of DECL still needs to be kept around
|
||||||
|
@ -1088,7 +1121,7 @@ cgraph_optimize (void)
|
||||||
if (!quiet_flag)
|
if (!quiet_flag)
|
||||||
fprintf (stderr, "Performing intraprocedural optimizations\n");
|
fprintf (stderr, "Performing intraprocedural optimizations\n");
|
||||||
|
|
||||||
cgraph_mark_local_functions ();
|
cgraph_function_and_variable_visibility ();
|
||||||
if (cgraph_dump_file)
|
if (cgraph_dump_file)
|
||||||
{
|
{
|
||||||
fprintf (cgraph_dump_file, "Marked ");
|
fprintf (cgraph_dump_file, "Marked ");
|
||||||
|
|
Loading…
Reference in New Issue