This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Add "address_taken" flag into cgraph node
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 10 May 2009 17:12:36 +0200
- Subject: Add "address_taken" flag into cgraph node
Hi,
this patch adds code to callgraph to track if function has address taken.
I want to decompose current "needed" flag into individual reasons why function is
needed, i.e.
1) function is externally visible (there is externally_visible flag for that)
2) function has address taken
3) function is needed for some other reason, such as used attribute
The patch also improves oridering produced by cgraph_postorder in a way
that functions with addresses taken are ordered first. This makes it
possible for early optimizer to see thorough previously indirect calls
that folded into direct. It improves local-pure-const analysis
noticeably (about 300 new const/pures/nothrows are found in early pass
and no new ones are found at IPA pass that is what I hoped for given
that tramp3d has acyclic cgraph). This also makes it possible to handle
indirect inlining in early inliner.
Bootstrapped/regtested x86_64-linux, will commit it shortly.
* cgraphbuild.c (record_reference): Use cgraph_mark_address_taken_node.
* cgraph.c (cgraph_mark_address_taken_node): New function.
(dump_cgraph_node): Dump new flag.
* cgraph.h (struct cgraph_node): Add address_taken.
(cgraph_mark_address_taken_node): New function.
* cp/decl2.c (cxx_callgraph_analyze_expr): Use
cgraph_mark_address_taken.
* ipa.c (cgraph_postorder): Prioritize functions with address taken
since new direct calls can be born.
Index: cgraphbuild.c
===================================================================
*** cgraphbuild.c (revision 147338)
--- cgraphbuild.c (working copy)
*************** record_reference (tree *tp, int *walk_su
*** 58,64 ****
functions reachable unconditionally. */
decl = TREE_OPERAND (*tp, 0);
if (TREE_CODE (decl) == FUNCTION_DECL)
! cgraph_mark_needed_node (cgraph_node (decl));
break;
default:
--- 58,64 ----
functions reachable unconditionally. */
decl = TREE_OPERAND (*tp, 0);
if (TREE_CODE (decl) == FUNCTION_DECL)
! cgraph_mark_address_taken_node (cgraph_node (decl));
break;
default:
Index: cgraph.c
===================================================================
*** cgraph.c (revision 147338)
--- cgraph.c (working copy)
*************** cgraph_mark_needed_node (struct cgraph_n
*** 1293,1298 ****
--- 1293,1307 ----
cgraph_mark_reachable_node (node);
}
+ /* Likewise indicate that a node is having address taken. */
+
+ void
+ cgraph_mark_address_taken_node (struct cgraph_node *node)
+ {
+ node->address_taken = 1;
+ cgraph_mark_needed_node (node);
+ }
+
/* Return local info for the compiled function. */
struct cgraph_local_info *
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 1397,1402 ****
--- 1406,1413 ----
fprintf (f, " nested in: %s", cgraph_node_name (node->origin));
if (node->needed)
fprintf (f, " needed");
+ if (node->address_taken)
+ fprintf (f, " address_taken");
else if (node->reachable)
fprintf (f, " reachable");
if (gimple_has_body_p (node->decl))
Index: cgraph.h
===================================================================
*** cgraph.h (revision 147338)
--- cgraph.h (working copy)
*************** struct GTY((chain_next ("%h.next"), chai
*** 189,194 ****
--- 189,196 ----
/* Set when function must be output - it is externally visible
or its address is taken. */
unsigned needed : 1;
+ /* Set when function has address taken. */
+ unsigned address_taken : 1;
/* Set when decl is an abstract function pointed to by the
ABSTRACT_DECL_ORIGIN of a reachable function. */
unsigned abstract_and_needed : 1;
*************** void cgraph_mark_if_needed (tree);
*** 417,422 ****
--- 419,425 ----
void cgraph_finalize_compilation_unit (void);
void cgraph_optimize (void);
void cgraph_mark_needed_node (struct cgraph_node *);
+ void cgraph_mark_address_taken_node (struct cgraph_node *);
void cgraph_mark_reachable_node (struct cgraph_node *);
bool cgraph_inline_p (struct cgraph_edge *, cgraph_inline_failed_t *reason);
bool cgraph_preserve_function_body_p (tree);
Index: cp/decl2.c
===================================================================
*** cp/decl2.c (revision 147338)
--- cp/decl2.c (working copy)
*************** cxx_callgraph_analyze_expr (tree *tp, in
*** 3250,3260 ****
{
case PTRMEM_CST:
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
! cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (t)));
break;
case BASELINK:
if (TREE_CODE (BASELINK_FUNCTIONS (t)) == FUNCTION_DECL)
! cgraph_mark_needed_node (cgraph_node (BASELINK_FUNCTIONS (t)));
break;
case VAR_DECL:
if (DECL_VTABLE_OR_VTT_P (t))
--- 3250,3260 ----
{
case PTRMEM_CST:
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
! cgraph_mark_address_taken_node (cgraph_node (PTRMEM_CST_MEMBER (t)));
break;
case BASELINK:
if (TREE_CODE (BASELINK_FUNCTIONS (t)) == FUNCTION_DECL)
! cgraph_mark_address_taken_node (cgraph_node (BASELINK_FUNCTIONS (t)));
break;
case VAR_DECL:
if (DECL_VTABLE_OR_VTT_P (t))
Index: ipa.c
===================================================================
*** ipa.c (revision 147338)
--- ipa.c (working copy)
*************** cgraph_postorder (struct cgraph_node **o
*** 38,43 ****
--- 38,44 ----
int stack_size = 0;
int order_pos = 0;
struct cgraph_edge *edge, last;
+ int pass;
struct cgraph_node **stack =
XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
*************** cgraph_postorder (struct cgraph_node **o
*** 48,91 ****
right through inline functions. */
for (node = cgraph_nodes; node; node = node->next)
node->aux = NULL;
! for (node = cgraph_nodes; node; node = node->next)
! if (!node->aux)
! {
! node2 = node;
! if (!node->callers)
! node->aux = &last;
! else
! node->aux = node->callers;
! while (node2)
! {
! while (node2->aux != &last)
! {
! edge = (struct cgraph_edge *) node2->aux;
! if (edge->next_caller)
! node2->aux = edge->next_caller;
! else
! node2->aux = &last;
! if (!edge->caller->aux)
! {
! if (!edge->caller->callers)
! edge->caller->aux = &last;
! else
! edge->caller->aux = edge->caller->callers;
! stack[stack_size++] = node2;
! node2 = edge->caller;
! break;
! }
! }
! if (node2->aux == &last)
! {
! order[order_pos++] = node2;
! if (stack_size)
! node2 = stack[--stack_size];
! else
! node2 = NULL;
! }
! }
! }
free (stack);
for (node = cgraph_nodes; node; node = node->next)
node->aux = NULL;
--- 49,94 ----
right through inline functions. */
for (node = cgraph_nodes; node; node = node->next)
node->aux = NULL;
! for (pass = 0; pass < 2; pass++)
! for (node = cgraph_nodes; node; node = node->next)
! if (!node->aux
! && (pass || (node->needed && !node->address_taken)))
! {
! node2 = node;
! if (!node->callers)
! node->aux = &last;
! else
! node->aux = node->callers;
! while (node2)
! {
! while (node2->aux != &last)
! {
! edge = (struct cgraph_edge *) node2->aux;
! if (edge->next_caller)
! node2->aux = edge->next_caller;
! else
! node2->aux = &last;
! if (!edge->caller->aux)
! {
! if (!edge->caller->callers)
! edge->caller->aux = &last;
! else
! edge->caller->aux = edge->caller->callers;
! stack[stack_size++] = node2;
! node2 = edge->caller;
! break;
! }
! }
! if (node2->aux == &last)
! {
! order[order_pos++] = node2;
! if (stack_size)
! node2 = stack[--stack_size];
! else
! node2 = NULL;
! }
! }
! }
free (stack);
for (node = cgraph_nodes; node; node = node->next)
node->aux = NULL;