Mercurial > hg > CbC > CbC_gcc
diff gcc/cgraphbuild.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
line wrap: on
line diff
--- a/gcc/cgraphbuild.c Fri Feb 12 23:41:23 2010 +0900 +++ b/gcc/cgraphbuild.c Mon May 24 12:47:05 2010 +0900 @@ -31,6 +31,15 @@ #include "intl.h" #include "gimple.h" #include "tree-pass.h" +#include "ipa-utils.h" +#include "except.h" + +/* Context of record_reference. */ +struct record_reference_ctx +{ + bool only_vars; + struct varpool_node *varpool_node; +}; /* Walk tree and record all calls and references to functions/variables. Called via walk_tree: TP is pointer to tree to be examined. @@ -42,26 +51,42 @@ { tree t = *tp; tree decl; - bool do_callgraph = data != NULL; + struct record_reference_ctx *ctx = (struct record_reference_ctx *)data; switch (TREE_CODE (t)) { case VAR_DECL: - if (TREE_STATIC (t) || DECL_EXTERNAL (t)) - { - varpool_mark_needed_node (varpool_node (t)); - if (lang_hooks.callgraph.analyze_expr) - return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees); - } + case FUNCTION_DECL: + gcc_unreachable (); break; case FDESC_EXPR: case ADDR_EXPR: /* Record dereferences to the functions. This makes the functions reachable unconditionally. */ - decl = TREE_OPERAND (*tp, 0); - if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph) - cgraph_mark_address_taken_node (cgraph_node (decl)); + decl = get_base_var (*tp); + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (!ctx->only_vars) + cgraph_mark_address_taken_node (cgraph_node (decl)); + ipa_record_reference (NULL, ctx->varpool_node, + cgraph_node (decl), NULL, + 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, + IPA_REF_ADDR, NULL); + } + *walk_subtrees = 0; break; default: @@ -81,6 +106,86 @@ return NULL_TREE; } +/* Record references to typeinfos in the type list LIST. */ + +static void +record_type_list (struct cgraph_node *node, tree list) +{ + for (; list; list = TREE_CHAIN (list)) + { + tree type = TREE_VALUE (list); + + if (TYPE_P (type)) + type = lookup_type_for_runtime (type); + STRIP_NOPS (type); + if (TREE_CODE (type) == ADDR_EXPR) + { + 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, + IPA_REF_ADDR, NULL); + } + } + } +} + +/* Record all references we will introduce by producing EH tables + for NODE. */ + +static void +record_eh_tables (struct cgraph_node *node, struct function *fun) +{ + eh_region i; + + i = fun->eh->region_tree; + if (!i) + return; + + while (1) + { + switch (i->type) + { + case ERT_CLEANUP: + case ERT_MUST_NOT_THROW: + break; + + case ERT_TRY: + { + eh_catch c; + for (c = i->u.eh_try.first_catch; c; c = c->next_catch) + record_type_list (node, c->type_list); + } + break; + + case ERT_ALLOWED_EXCEPTIONS: + record_type_list (node, i->u.allowed.type_list); + break; + } + /* If there are sub-regions, process them. */ + if (i->inner) + i = i->inner; + /* If there are peers, process them. */ + else if (i->next_peer) + i = i->next_peer; + /* Otherwise, step back up the tree to the next peer. */ + else + { + do + { + i = i->outer; + if (i == NULL) + return; + } + while (i->next_peer == NULL); + i = i->next_peer; + } + } +} + /* Reset inlining information of all incoming call edges of NODE. */ void @@ -126,6 +231,93 @@ return freq; } +/* Mark address taken in STMT. */ + +static bool +mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr, + void *data ATTRIBUTE_UNUSED) +{ + if (TREE_CODE (addr) == FUNCTION_DECL) + { + struct cgraph_node *node = cgraph_node (addr); + cgraph_mark_address_taken_node (node); + ipa_record_reference ((struct cgraph_node *)data, NULL, + node, NULL, + IPA_REF_ADDR, stmt); + } + else + { + 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); + } + } + + return false; +} + +/* Mark load of T. */ + +static bool +mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t, + void *data ATTRIBUTE_UNUSED) +{ + t = get_base_address (t); + if (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_LOAD, stmt); + } + return false; +} + +/* Mark store of T. */ + +static bool +mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t, + void *data ATTRIBUTE_UNUSED) +{ + t = get_base_address (t); + if (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); + } + return false; +} + /* Create cgraph edges for function calls. Also look for functions and variables having addresses taken. */ @@ -141,49 +333,49 @@ /* Create the callgraph edges and record the nodes referenced by the function. body. */ FOR_EACH_BB (bb) - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple stmt = gsi_stmt (gsi); - tree decl; + { + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + tree decl; - if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) - { - size_t i; - size_t n = gimple_call_num_args (stmt); - cgraph_create_edge (node, cgraph_node (decl), stmt, - bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb), - bb->loop_depth); - for (i = 0; i < n; i++) - walk_tree (gimple_call_arg_ptr (stmt, i), record_reference, - node, visited_nodes); - if (gimple_call_lhs (stmt)) - walk_tree (gimple_call_lhs_ptr (stmt), record_reference, node, - visited_nodes); - } - else - { - struct walk_stmt_info wi; - memset (&wi, 0, sizeof (wi)); - wi.info = node; - wi.pset = visited_nodes; - walk_gimple_op (stmt, record_reference, &wi); - if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL - && gimple_omp_parallel_child_fn (stmt)) - { - tree fn = gimple_omp_parallel_child_fn (stmt); + 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_node (decl), stmt, + bb->count, freq, + bb->loop_depth); + else + cgraph_create_indirect_edge (node, stmt, + gimple_call_flags (stmt), + bb->count, freq, + bb->loop_depth); + } + 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)); + } + if (gimple_code (stmt) == GIMPLE_OMP_TASK) + { + tree fn = gimple_omp_task_child_fn (stmt); + if (fn) cgraph_mark_needed_node (cgraph_node (fn)); - } - if (gimple_code (stmt) == GIMPLE_OMP_TASK) - { - tree fn = gimple_omp_task_child_fn (stmt); - if (fn) - cgraph_mark_needed_node (cgraph_node (fn)); - fn = gimple_omp_task_copy_fn (stmt); - if (fn) - cgraph_mark_needed_node (cgraph_node (fn)); - } - } - } + fn = gimple_omp_task_copy_fn (stmt); + if (fn) + cgraph_mark_needed_node (cgraph_node (fn)); + } + } + for (gsi = gsi_start (phi_nodes (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; @@ -194,9 +386,8 @@ if (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))) varpool_finalize_decl (decl); - else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl)) - walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes); } + record_eh_tables (node, cfun); pointer_set_destroy (visited_nodes); return 0; @@ -229,8 +420,13 @@ 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 record_reference_ctx ctx = {false, NULL}; + + ctx.varpool_node = node; + ctx.only_vars = only_vars; walk_tree (&DECL_INITIAL (decl), record_reference, - only_vars ? NULL : decl, visited_nodes); + &ctx, visited_nodes); pointer_set_destroy (visited_nodes); } @@ -245,28 +441,77 @@ gimple_stmt_iterator gsi; cgraph_node_remove_callees (node); + ipa_remove_all_references (&node->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); - tree decl; + { + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + 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_node (decl), stmt, + bb->count, freq, + bb->loop_depth); + else + cgraph_create_indirect_edge (node, stmt, + gimple_call_flags (stmt), + bb->count, freq, + bb->loop_depth); + } + 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)) + walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, + mark_load, mark_store, mark_address); + } + record_eh_tables (node, cfun); gcc_assert (!node->global.inlined_to); 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_node (current_function_decl); + gimple_stmt_iterator gsi; + + ipa_remove_all_references (&node->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 (phi_nodes (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 = { {