X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gcc%2Fcgraphbuild.c;h=024424d0671b1057384077bc1e8da775094433ea;hb=2cd45f0e6826ddcc92216a508104b2802eddece3;hp=246be20df2ef283f0f9530836b580f37727a57e7;hpb=de61f46712258bf735c5173e92655569bc732f13;p=gcc.git diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c index 246be20df2e..024424d0671 100644 --- a/gcc/cgraphbuild.c +++ b/gcc/cgraphbuild.c @@ -1,5 +1,5 @@ /* Callgraph construction. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Jan Hubicka @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "ipa-utils.h" #include "except.h" +#include "ipa-inline.h" /* Context of record_reference. */ struct record_reference_ctx @@ -53,6 +54,12 @@ record_reference (tree *tp, int *walk_subtrees, void *data) tree decl; struct record_reference_ctx *ctx = (struct record_reference_ctx *)data; + t = canonicalize_constructor_val (t, NULL); + if (!t) + t = *tp; + else if (t != *tp) + *tp = t; + switch (TREE_CODE (t)) { case VAR_DECL: @@ -67,23 +74,19 @@ record_reference (tree *tp, int *walk_subtrees, void *data) decl = get_base_var (*tp); if (TREE_CODE (decl) == FUNCTION_DECL) { + struct cgraph_node *node = cgraph_get_create_node (decl); if (!ctx->only_vars) - cgraph_mark_address_taken_node (cgraph_node (decl)); - ipa_record_reference (NULL, ctx->varpool_node, - cgraph_node (decl), NULL, + cgraph_mark_address_taken_node (node); + ipa_record_reference ((symtab_node)ctx->varpool_node, + (symtab_node)node, IPA_REF_ADDR, NULL); } if (TREE_CODE (decl) == VAR_DECL) { - struct varpool_node *vnode = varpool_node (decl); - if (lang_hooks.callgraph.analyze_expr) - lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees); - varpool_mark_needed_node (vnode); - if (vnode->alias && vnode->extra_name) - vnode = vnode->extra_name; - ipa_record_reference (NULL, ctx->varpool_node, - NULL, vnode, + struct varpool_node *vnode = varpool_node_for_decl (decl); + ipa_record_reference ((symtab_node)ctx->varpool_node, + (symtab_node)vnode, IPA_REF_ADDR, NULL); } *walk_subtrees = 0; @@ -97,9 +100,6 @@ record_reference (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; break; } - - if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE) - return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees); break; } @@ -123,10 +123,9 @@ record_type_list (struct cgraph_node *node, tree list) type = TREE_OPERAND (type, 0); if (TREE_CODE (type) == VAR_DECL) { - struct varpool_node *vnode = varpool_node (type); - varpool_mark_needed_node (vnode); - ipa_record_reference (node, NULL, - NULL, vnode, + struct varpool_node *vnode = varpool_node_for_decl (type); + ipa_record_reference ((symtab_node)node, + (symtab_node)vnode, IPA_REF_ADDR, NULL); } } @@ -141,6 +140,15 @@ record_eh_tables (struct cgraph_node *node, struct function *fun) { eh_region i; + if (DECL_FUNCTION_PERSONALITY (node->symbol.decl)) + { + struct cgraph_node *per_node; + + per_node = cgraph_get_create_node (DECL_FUNCTION_PERSONALITY (node->symbol.decl)); + ipa_record_reference ((symtab_node)node, (symtab_node)per_node, IPA_REF_ADDR, NULL); + cgraph_mark_address_taken_node (per_node); + } + i = fun->eh->region_tree; if (!i) return; @@ -186,29 +194,6 @@ record_eh_tables (struct cgraph_node *node, struct function *fun) } } -/* Reset inlining information of all incoming call edges of NODE. */ - -void -reset_inline_failed (struct cgraph_node *node) -{ - struct cgraph_edge *e; - - for (e = node->callers; e; e = e->next_caller) - { - e->callee->global.inlined_to = NULL; - if (!node->analyzed) - e->inline_failed = CIF_BODY_NOT_AVAILABLE; - else if (node->local.redefined_extern_inline) - e->inline_failed = CIF_REDEFINED_EXTERN_INLINE; - else if (!node->local.inlinable) - e->inline_failed = CIF_FUNCTION_NOT_INLINABLE; - else if (e->call_stmt_cannot_inline_p) - e->inline_failed = CIF_MISMATCHED_ARGUMENTS; - else - e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED; - } -} - /* Computes the frequency of the call statement so that it can be stored in cgraph_edge. BB is the basic block of the call statement. */ int @@ -234,35 +219,25 @@ compute_call_stmt_bb_frequency (tree decl, basic_block bb) /* Mark address taken in STMT. */ static bool -mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr, - void *data ATTRIBUTE_UNUSED) +mark_address (gimple stmt, tree addr, void *data) { + addr = get_base_address (addr); if (TREE_CODE (addr) == FUNCTION_DECL) { - struct cgraph_node *node = cgraph_node (addr); + struct cgraph_node *node = cgraph_get_create_node (addr); cgraph_mark_address_taken_node (node); - ipa_record_reference ((struct cgraph_node *)data, NULL, - node, NULL, + ipa_record_reference ((symtab_node)data, + (symtab_node)node, IPA_REF_ADDR, stmt); } - else + else if (addr && TREE_CODE (addr) == VAR_DECL + && (TREE_STATIC (addr) || DECL_EXTERNAL (addr))) { - addr = get_base_address (addr); - if (addr && TREE_CODE (addr) == VAR_DECL - && (TREE_STATIC (addr) || DECL_EXTERNAL (addr))) - { - struct varpool_node *vnode = varpool_node (addr); - int walk_subtrees; - - if (lang_hooks.callgraph.analyze_expr) - lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees); - varpool_mark_needed_node (vnode); - if (vnode->alias && vnode->extra_name) - vnode = vnode->extra_name; - ipa_record_reference ((struct cgraph_node *)data, NULL, - NULL, vnode, - IPA_REF_ADDR, stmt); - } + struct varpool_node *vnode = varpool_node_for_decl (addr); + + ipa_record_reference ((symtab_node)data, + (symtab_node)vnode, + IPA_REF_ADDR, stmt); } return false; @@ -271,23 +246,26 @@ mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr, /* Mark load of T. */ static bool -mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t, - void *data ATTRIBUTE_UNUSED) +mark_load (gimple stmt, tree t, void *data) { t = get_base_address (t); - if (TREE_CODE (t) == VAR_DECL - && (TREE_STATIC (t) || DECL_EXTERNAL (t))) + if (t && TREE_CODE (t) == FUNCTION_DECL) + { + /* ??? This can happen on platforms with descriptors when these are + directly manipulated in the code. Pretend that it's an address. */ + struct cgraph_node *node = cgraph_get_create_node (t); + cgraph_mark_address_taken_node (node); + ipa_record_reference ((symtab_node)data, + (symtab_node)node, + IPA_REF_ADDR, stmt); + } + else if (t && TREE_CODE (t) == VAR_DECL + && (TREE_STATIC (t) || DECL_EXTERNAL (t))) { - struct varpool_node *vnode = varpool_node (t); - int walk_subtrees; - - if (lang_hooks.callgraph.analyze_expr) - lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees); - varpool_mark_needed_node (vnode); - if (vnode->alias && vnode->extra_name) - vnode = vnode->extra_name; - ipa_record_reference ((struct cgraph_node *)data, NULL, - NULL, vnode, + struct varpool_node *vnode = varpool_node_for_decl (t); + + ipa_record_reference ((symtab_node)data, + (symtab_node)vnode, IPA_REF_LOAD, stmt); } return false; @@ -296,24 +274,17 @@ mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t, /* Mark store of T. */ static bool -mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t, - void *data ATTRIBUTE_UNUSED) +mark_store (gimple stmt, tree t, void *data) { t = get_base_address (t); - if (TREE_CODE (t) == VAR_DECL + if (t && TREE_CODE (t) == VAR_DECL && (TREE_STATIC (t) || DECL_EXTERNAL (t))) { - struct varpool_node *vnode = varpool_node (t); - int walk_subtrees; - - if (lang_hooks.callgraph.analyze_expr) - lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees); - varpool_mark_needed_node (vnode); - if (vnode->alias && vnode->extra_name) - vnode = vnode->extra_name; - ipa_record_reference ((struct cgraph_node *)data, NULL, - NULL, vnode, - IPA_REF_STORE, NULL); + struct varpool_node *vnode = varpool_node_for_decl (t); + + ipa_record_reference ((symtab_node)data, + (symtab_node)vnode, + IPA_REF_STORE, stmt); } return false; } @@ -325,10 +296,11 @@ static unsigned int build_cgraph_edges (void) { basic_block bb; - struct cgraph_node *node = cgraph_node (current_function_decl); + struct cgraph_node *node = cgraph_get_node (current_function_decl); struct pointer_set_t *visited_nodes = pointer_set_create (); gimple_stmt_iterator gsi; - tree step; + tree decl; + unsigned ix; /* Create the callgraph edges and record the nodes referenced by the function. body. */ @@ -339,45 +311,54 @@ build_cgraph_edges (void) gimple stmt = gsi_stmt (gsi); tree decl; - if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) - cgraph_create_edge (node, cgraph_node (decl), stmt, - bb->count, - compute_call_stmt_bb_frequency - (current_function_decl, bb), - bb->loop_depth); + if (is_gimple_call (stmt)) + { + int freq = compute_call_stmt_bb_frequency (current_function_decl, + bb); + decl = gimple_call_fndecl (stmt); + if (decl) + cgraph_create_edge (node, cgraph_get_create_node (decl), + stmt, bb->count, freq); + else + cgraph_create_indirect_edge (node, stmt, + gimple_call_flags (stmt), + bb->count, freq); + } walk_stmt_load_store_addr_ops (stmt, node, mark_load, mark_store, mark_address); if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL && gimple_omp_parallel_child_fn (stmt)) { tree fn = gimple_omp_parallel_child_fn (stmt); - cgraph_mark_needed_node (cgraph_node (fn)); + ipa_record_reference ((symtab_node)node, + (symtab_node)cgraph_get_create_node (fn), + IPA_REF_ADDR, stmt); } if (gimple_code (stmt) == GIMPLE_OMP_TASK) { tree fn = gimple_omp_task_child_fn (stmt); if (fn) - cgraph_mark_needed_node (cgraph_node (fn)); + ipa_record_reference ((symtab_node)node, + (symtab_node) cgraph_get_create_node (fn), + IPA_REF_ADDR, stmt); fn = gimple_omp_task_copy_fn (stmt); if (fn) - cgraph_mark_needed_node (cgraph_node (fn)); + ipa_record_reference ((symtab_node)node, + (symtab_node)cgraph_get_create_node (fn), + IPA_REF_ADDR, stmt); } } - for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi)) + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, mark_load, mark_store, mark_address); } /* Look for initializers of constant variables and private statics. */ - for (step = cfun->local_decls; - step; - step = TREE_CHAIN (step)) - { - tree decl = TREE_VALUE (step); - if (TREE_CODE (decl) == VAR_DECL - && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))) - varpool_finalize_decl (decl); - } + FOR_EACH_LOCAL_DECL (cfun, ix, decl) + if (TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + && !DECL_HAS_VALUE_EXPR_P (decl)) + varpool_finalize_decl (decl); record_eh_tables (node, cfun); pointer_set_destroy (visited_nodes); @@ -389,6 +370,7 @@ struct gimple_opt_pass pass_build_cgraph_edges = { GIMPLE_PASS, "*build_cgraph_edges", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ NULL, /* gate */ build_cgraph_edges, /* execute */ NULL, /* sub */ @@ -411,7 +393,7 @@ void record_references_in_initializer (tree decl, bool only_vars) { struct pointer_set_t *visited_nodes = pointer_set_create (); - struct varpool_node *node = varpool_node (decl); + struct varpool_node *node = varpool_node_for_decl (decl); struct record_reference_ctx ctx = {false, NULL}; ctx.varpool_node = node; @@ -428,11 +410,11 @@ unsigned int rebuild_cgraph_edges (void) { basic_block bb; - struct cgraph_node *node = cgraph_node (current_function_decl); + struct cgraph_node *node = cgraph_get_node (current_function_decl); gimple_stmt_iterator gsi; cgraph_node_remove_callees (node); - ipa_remove_all_references (&node->ref_list); + ipa_remove_all_references (&node->symbol.ref_list); node->count = ENTRY_BLOCK_PTR->count; @@ -443,17 +425,24 @@ rebuild_cgraph_edges (void) gimple stmt = gsi_stmt (gsi); tree decl; - if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) - cgraph_create_edge (node, cgraph_node (decl), stmt, - bb->count, - compute_call_stmt_bb_frequency - (current_function_decl, bb), - bb->loop_depth); + if (is_gimple_call (stmt)) + { + int freq = compute_call_stmt_bb_frequency (current_function_decl, + bb); + decl = gimple_call_fndecl (stmt); + if (decl) + cgraph_create_edge (node, cgraph_get_create_node (decl), stmt, + bb->count, freq); + else + cgraph_create_indirect_edge (node, stmt, + gimple_call_flags (stmt), + bb->count, freq); + } walk_stmt_load_store_addr_ops (stmt, node, mark_load, mark_store, mark_address); } - for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi)) + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, mark_load, mark_store, mark_address); } @@ -463,17 +452,49 @@ rebuild_cgraph_edges (void) return 0; } +/* Rebuild cgraph edges for current function node. This needs to be run after + passes that don't update the cgraph. */ + +void +cgraph_rebuild_references (void) +{ + basic_block bb; + struct cgraph_node *node = cgraph_get_node (current_function_decl); + gimple_stmt_iterator gsi; + + ipa_remove_all_references (&node->symbol.ref_list); + + node->count = ENTRY_BLOCK_PTR->count; + + FOR_EACH_BB (bb) + { + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + + walk_stmt_load_store_addr_ops (stmt, node, mark_load, + mark_store, mark_address); + + } + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, + mark_load, mark_store, mark_address); + } + record_eh_tables (node, cfun); +} + struct gimple_opt_pass pass_rebuild_cgraph_edges = { { GIMPLE_PASS, "*rebuild_cgraph_edges", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ NULL, /* gate */ rebuild_cgraph_edges, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - TV_NONE, /* tv_id */ + TV_CGRAPH, /* tv_id */ PROP_cfg, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ @@ -486,7 +507,7 @@ struct gimple_opt_pass pass_rebuild_cgraph_edges = static unsigned int remove_cgraph_callee_edges (void) { - cgraph_node_remove_callees (cgraph_node (current_function_decl)); + cgraph_node_remove_callees (cgraph_get_node (current_function_decl)); return 0; } @@ -495,6 +516,7 @@ struct gimple_opt_pass pass_remove_cgraph_callee_edges = { GIMPLE_PASS, "*remove_cgraph_callee_edges", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ NULL, /* gate */ remove_cgraph_callee_edges, /* execute */ NULL, /* sub */