diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7ea088127ac..935aaa4214a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2009-05-10 Jan Hubicka + + * 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. + 2009-05-10 Joseph Myers * c-lex.c (c_lex_with_flags): Expect cpp_hashnode in diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 5d2cc1d6634..60ff1685dc9 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1293,6 +1293,15 @@ cgraph_mark_needed_node (struct cgraph_node *node) 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 * @@ -1397,6 +1406,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) 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)) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index c1a1a0ab922..2e4201ef51d 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -189,6 +189,8 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { /* 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; @@ -417,6 +419,7 @@ void cgraph_mark_if_needed (tree); 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); diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c index fb56ce5354a..a7a8bd2b314 100644 --- a/gcc/cgraphbuild.c +++ b/gcc/cgraphbuild.c @@ -58,7 +58,7 @@ record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) functions reachable unconditionally. */ decl = TREE_OPERAND (*tp, 0); if (TREE_CODE (decl) == FUNCTION_DECL) - cgraph_mark_needed_node (cgraph_node (decl)); + cgraph_mark_address_taken_node (cgraph_node (decl)); break; default: diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 8196b54f4dd..1f8e848bf2e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3250,11 +3250,11 @@ cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED) { case PTRMEM_CST: if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t))) - cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (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_needed_node (cgraph_node (BASELINK_FUNCTIONS (t))); + cgraph_mark_address_taken_node (cgraph_node (BASELINK_FUNCTIONS (t))); break; case VAR_DECL: if (DECL_VTABLE_OR_VTT_P (t)) diff --git a/gcc/ipa.c b/gcc/ipa.c index b51c219d1fb..fb3c74992f6 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -38,6 +38,7 @@ cgraph_postorder (struct cgraph_node **order) 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); @@ -48,44 +49,46 @@ cgraph_postorder (struct cgraph_node **order) 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; - } - } - } + 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;