diff options
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r-- | gcc/cgraphunit.c | 207 |
1 files changed, 91 insertions, 116 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 2f83767..81436aa 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -169,15 +169,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA static void cgraph_expand_all_functions (void); static void cgraph_mark_functions_to_output (void); static void cgraph_expand_function (struct cgraph_node *); -static tree record_call_1 (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_create_edges (struct cgraph_node *node, tree body); -/* Records tree nodes seen in cgraph_create_edges. Simply using +/* 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_calls_1. */ + record_reference itself. */ static struct pointer_set_t *visited_nodes; static FILE *cgraph_dump_file; @@ -265,7 +264,12 @@ cgraph_varpool_analyze_pending_decls (void) cgraph_varpool_first_unanalyzed_node = cgraph_varpool_first_unanalyzed_node->next_needed; if (DECL_INITIAL (decl)) - cgraph_create_edges (NULL, DECL_INITIAL (decl)); + { + visited_nodes = pointer_set_create (); + walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes); + pointer_set_destroy (visited_nodes); + visited_nodes = NULL; + } changed = true; } timevar_pop (TV_CGRAPH); @@ -435,9 +439,6 @@ cgraph_finalize_function (tree decl, bool nested) do_warn_unused_parameter (decl); } -/* Used only while constructing the callgraph. */ -static basic_block current_basic_block; - void cgraph_lower_function (struct cgraph_node *node) { @@ -449,7 +450,7 @@ cgraph_lower_function (struct cgraph_node *node) /* Walk tree and record all calls. Called via walk_tree. */ static tree -record_call_1 (tree *tp, int *walk_subtrees, void *data) +record_reference (tree *tp, int *walk_subtrees, void *data) { tree t = *tp; @@ -480,29 +481,6 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data) } break; - case CALL_EXPR: - { - tree decl = get_callee_fndecl (*tp); - if (decl && TREE_CODE (decl) == FUNCTION_DECL) - { - cgraph_create_edge (data, cgraph_node (decl), *tp, - current_basic_block->count, - current_basic_block->loop_depth); - - /* When we see a function call, we don't want to look at the - function reference in the ADDR_EXPR that is hanging from - the CALL_EXPR we're examining here, because we would - conclude incorrectly that the function's address could be - taken by something that is not a function call. So only - walk the function parameter list, skip the other subtrees. */ - - walk_tree (&TREE_OPERAND (*tp, 1), record_call_1, data, - visited_nodes); - *walk_subtrees = 0; - } - break; - } - default: /* Save some cycles by not walking types and declaration as we won't find anything useful there anyway. */ @@ -525,97 +503,62 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data) static void cgraph_create_edges (struct cgraph_node *node, tree body) { - /* The nodes we're interested in are never shared, so walk - the tree ignoring duplicates. */ + basic_block bb; + + struct function *this_cfun = DECL_STRUCT_FUNCTION (body); + block_stmt_iterator bsi; + tree step; visited_nodes = pointer_set_create (); - gcc_assert (current_basic_block == NULL); - if (TREE_CODE (body) == FUNCTION_DECL) - { - struct function *this_cfun = DECL_STRUCT_FUNCTION (body); - block_stmt_iterator bsi; - tree step; - - /* Reach the trees by walking over the CFG, and note the - enclosing basic-blocks in the call edges. */ - FOR_EACH_BB_FN (current_basic_block, this_cfun) - for (bsi = bsi_start (current_basic_block); !bsi_end_p (bsi); bsi_next (&bsi)) - walk_tree (bsi_stmt_ptr (bsi), record_call_1, node, visited_nodes); - current_basic_block = NULL; - - /* Walk over any private statics that may take addresses of functions. */ - if (TREE_CODE (DECL_INITIAL (body)) == BLOCK) - { - for (step = BLOCK_VARS (DECL_INITIAL (body)); - step; - step = TREE_CHAIN (step)) - if (DECL_INITIAL (step)) - walk_tree (&DECL_INITIAL (step), record_call_1, node, visited_nodes); - } - /* Also look here for private statics. */ - if (DECL_STRUCT_FUNCTION (body)) - for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list; - step; - step = TREE_CHAIN (step)) + /* 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))) { - tree decl = TREE_VALUE (step); - if (DECL_INITIAL (decl) && TREE_STATIC (decl)) - walk_tree (&DECL_INITIAL (decl), record_call_1, node, visited_nodes); + 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) == MODIFY_EXPR) + walk_tree (&TREE_OPERAND (stmt, 0), + record_reference, node, visited_nodes); } + else + walk_tree (bsi_stmt_ptr (bsi), record_reference, node, visited_nodes); + } + + /* Walk over any private statics that may take addresses of functions. */ + if (TREE_CODE (DECL_INITIAL (body)) == BLOCK) + { + for (step = BLOCK_VARS (DECL_INITIAL (body)); + step; + step = TREE_CHAIN (step)) + if (DECL_INITIAL (step)) + walk_tree (&DECL_INITIAL (step), record_reference, node, visited_nodes); } - else - walk_tree (&body, record_call_1, node, visited_nodes); + + /* Also look here for private statics. */ + if (DECL_STRUCT_FUNCTION (body)) + for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list; + step; + step = TREE_CHAIN (step)) + { + tree decl = TREE_VALUE (step); + if (DECL_INITIAL (decl) && TREE_STATIC (decl)) + walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes); + } pointer_set_destroy (visited_nodes); visited_nodes = NULL; } -static bool error_found; - -/* Callback of verify_cgraph_node. Check that all call_exprs have - cgraph nodes. */ - -static tree -verify_cgraph_node_1 (tree *tp, int *walk_subtrees, void *data) -{ - tree t = *tp; - tree decl; - - if (TREE_CODE (t) == CALL_EXPR && (decl = get_callee_fndecl (t))) - { - struct cgraph_edge *e = cgraph_edge (data, t); - if (e) - { - if (e->aux) - { - error ("Shared call_expr:"); - debug_tree (t); - error_found = true; - } - if (e->callee->decl != cgraph_node (decl)->decl) - { - error ("Edge points to wrong declaration:"); - debug_tree (e->callee->decl); - fprintf (stderr," Instead of:"); - debug_tree (decl); - } - e->aux = (void *)1; - } - else - { - error ("Missing callgraph edge for call expr:"); - debug_tree (t); - error_found = true; - } - } - - /* 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; - - return NULL_TREE; -} /* Verify cgraph nodes of given cgraph node. */ void @@ -626,9 +569,9 @@ verify_cgraph_node (struct cgraph_node *node) struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl); basic_block this_block; block_stmt_iterator bsi; + bool error_found = false; timevar_push (TV_CGRAPH_VERIFY); - error_found = false; for (e = node->callees; e; e = e->next_callee) if (e->aux) { @@ -694,7 +637,38 @@ verify_cgraph_node (struct cgraph_node *node) enclosing basic-blocks in the call edges. */ FOR_EACH_BB_FN (this_block, this_cfun) for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi)) - walk_tree (bsi_stmt_ptr (bsi), verify_cgraph_node_1, node, visited_nodes); + { + tree stmt = bsi_stmt (bsi); + tree call = get_call_expr_in (stmt); + tree decl; + if (call && (decl = get_callee_fndecl (call))) + { + struct cgraph_edge *e = cgraph_edge (node, stmt); + if (e) + { + if (e->aux) + { + error ("Shared call_stmt:"); + debug_generic_stmt (stmt); + error_found = true; + } + if (e->callee->decl != cgraph_node (decl)->decl) + { + error ("Edge points to wrong declaration:"); + debug_tree (e->callee->decl); + fprintf (stderr," Instead of:"); + debug_tree (decl); + } + e->aux = (void *)1; + } + else + { + error ("Missing callgraph edge for call stmt:"); + debug_generic_stmt (stmt); + error_found = true; + } + } + } pointer_set_destroy (visited_nodes); visited_nodes = NULL; } @@ -706,9 +680,10 @@ verify_cgraph_node (struct cgraph_node *node) { if (!e->aux) { - error ("Edge %s->%s has no corresponding call_expr", + error ("Edge %s->%s has no corresponding call_stmt", cgraph_node_name (e->caller), cgraph_node_name (e->callee)); + debug_generic_stmt (e->call_stmt); error_found = true; } e->aux = 0; |