diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-05-08 19:19:51 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-05-08 19:19:51 +0000 |
commit | ccf4ab6ba79565bf35426a5aad3140e6354e0121 (patch) | |
tree | c97ec571988fc2c7380db58cdf7ad61782d357bf /gcc/cgraph.c | |
parent | 45c4e79882e6f8943a5fd2dafe9450a46d54247a (diff) | |
download | gcc-ccf4ab6ba79565bf35426a5aad3140e6354e0121.tar.gz |
* cgraphbuild.c (compute_call_stmt_bb_frequency): Accept function argument;
handle correctly when profile is absent.
(build_cgraph_edges): Update.
(rebuild_cgraph_edges): Update.
* cgraph.c: Do not include varrau.h
(cgraph_set_call_stmt_including_clones, cgraph_create_edge_including_clones):
New function
(cgraph_update_edges_for_call_stmt_node): New stati cfunction.
(cgraph_update_edges_for_call_stmt): Handle clones.
(cgraph_remove_node): Handle clone tree.
(cgraph_remove_node_and_inline_clones): New function.
(dump_cgraph_node): Dump clone tree.
(cgraph_clone_node): Handle clone tree.
(clone_function_name): Bring here from tree-inline.c
(cgraph_create_virtual_clone): New function.
* cgraph.h (ipa_replace_map): Move ehre from ipa.h
(cgraph_clone_info): New function
(strut cgraph_node): Add clone_info and new clone tree pointers.
(cgraph_remove_node_and_inline_clones, cgraph_set_call_stmt_including_clones,
cgraph_create_edge_including_clones, cgraph_create_virtual_clone): Declare.
(cgraph_function_versioning): Use VEC argument.
(compute_call_stmt_bb_frequency): Update prototype.
(cgraph_materialize_all_clones): New function.
* ipa-cp.c (ipcp_update_cloned_node): Remove.
(ipcp_create_replace_map): Update to VECtors.
(ipcp_update_callgraph): Use virtual clones.
(ipcp_update_bb_counts, ipcp_update_edges_counts): Remove.
(ipcp_update_profiling): Do not update local profiling.
(ipcp_insert_stage): Use VECtors and virtual clones.
* cgraphunit.c (verify_cgraph_node): Verify clone tree.
(clone_of_p): New function.
(cgraph_preserve_function_body_p): Use clone tree.
(cgraph_optimize): Materialize clones.
(cgraph_function_versioning): Update for VECtors.
(save_inline_function_body): Use clone tree.
(cgraph_materialize_clone, cgraph_materialize_all_clones): New functions.
* ipa-inline.c (cgraph_default_inline_p): Use analyzed flags.
* ipa.c: Include gimple.h.
(cgraph_remove_unreachable_nodes): Use clone tree.
* ipa-prop.c (ipa_note_param_call): Update call of compute_call_stmt_bb_frequency.
* ipa-prop.h (ipa_replace_map): Move to cgraph.h.
* tree-inline.c: Do not include varray.h; do not include gt-tree-inline.h
(copy_bb): Handle updating of clone tree; add new edge when new call
appears.
(expand_call_inline): Be strict about every call having edge.
(clone_fn_id_num, clone_function_name): Move to cgraph.c.
(delete_unreachable_blocks_update_callgraph): New function.
(tree_function_versioning): Use VECtors; always remove unreachable blocks
and fold conditionals.
* tree-inline.h: Do not include varray.h
(tree_function_versioning): Remove.
* Makefile.in (GTFILES): Remove tree-inline.c
* passes.c (do_per_function): Do only functions having body.
* ipa-struct-reorg.c (do_reorg_1, collect_data_accesses): Handle cone tree.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@147294 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r-- | gcc/cgraph.c | 337 |
1 files changed, 317 insertions, 20 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c index ce696e211b6..2f68d94e3dd 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -78,7 +78,6 @@ The callgraph: #include "target.h" #include "basic-block.h" #include "cgraph.h" -#include "varray.h" #include "output.h" #include "intl.h" #include "gimple.h" @@ -628,7 +627,7 @@ cgraph_edge (struct cgraph_node *node, gimple call_stmt) } -/* Change field call_smt of edge E to NEW_STMT. */ +/* Change field call_stmt of edge E to NEW_STMT. */ void cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt) @@ -655,6 +654,79 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt) } } +/* Like cgraph_set_call_stmt but walk the clone tree and update all clones sharing + same function body. */ + +void +cgraph_set_call_stmt_including_clones (struct cgraph_node *orig, + gimple old_stmt, gimple new_stmt) +{ + struct cgraph_node *node; + struct cgraph_edge *edge = cgraph_edge (orig, old_stmt); + + if (edge) + cgraph_set_call_stmt (edge, new_stmt); + if (orig->clones) + for (node = orig->clones; node != orig;) + { + struct cgraph_edge *edge = cgraph_edge (node, old_stmt); + if (edge) + cgraph_set_call_stmt (edge, new_stmt); + if (node->clones) + node = node->clones; + else if (node->next_sibling_clone) + node = node->next_sibling_clone; + else + { + while (node != orig && !node->next_sibling_clone) + node = node->clone_of; + if (node != orig) + node = node->next_sibling_clone; + } + } +} + +/* Like cgraph_create_edge walk the clone tree and update all clones sharing + same function body. + + TODO: COUNT and LOOP_DEPTH should be properly distributed based on relative + frequencies of the clones. + */ + +void +cgraph_create_edge_including_clones (struct cgraph_node *orig, struct cgraph_node *callee, + gimple stmt, gcov_type count, int freq, + int loop_depth, + cgraph_inline_failed_t reason) +{ + struct cgraph_node *node; + + cgraph_create_edge (orig, callee, stmt, count, freq, loop_depth)->inline_failed = + reason; + + if (orig->clones) + for (node = orig->clones; node != orig;) + { + /* It is possible that we already constant propagated into the clone + and turned indirect call into dirrect call. */ + if (!cgraph_edge (node, stmt)) + cgraph_create_edge (node, callee, stmt, count, freq, + loop_depth)->inline_failed = reason; + + if (node->clones) + node = node->clones; + else if (node->next_sibling_clone) + node = node->next_sibling_clone; + else + { + while (node != orig && !node->next_sibling_clone) + node = node->clone_of; + if (node != orig) + node = node->next_sibling_clone; + } + } +} + /* Give initial reasons why inlining would fail on EDGE. This gets either nullified or usually overwritten by more precise reasons later. */ @@ -828,12 +900,12 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n) /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL OLD_STMT changed into NEW_STMT. */ -void -cgraph_update_edges_for_call_stmt (gimple old_stmt, gimple new_stmt) +static void +cgraph_update_edges_for_call_stmt_node (struct cgraph_node *node, + gimple old_stmt, gimple new_stmt) { tree new_call = (is_gimple_call (new_stmt)) ? gimple_call_fn (new_stmt) : 0; tree old_call = (is_gimple_call (old_stmt)) ? gimple_call_fn (old_stmt) : 0; - struct cgraph_node *node = cgraph_node (cfun->decl); if (old_call != new_call) { @@ -870,6 +942,34 @@ cgraph_update_edges_for_call_stmt (gimple old_stmt, gimple new_stmt) } } +/* Update or remove the corresponding cgraph edge if a GIMPLE_CALL + OLD_STMT changed into NEW_STMT. */ + +void +cgraph_update_edges_for_call_stmt (gimple old_stmt, gimple new_stmt) +{ + struct cgraph_node *orig = cgraph_node (cfun->decl); + struct cgraph_node *node; + + cgraph_update_edges_for_call_stmt_node (orig, old_stmt, new_stmt); + if (orig->clones) + for (node = orig->clones; node != orig;) + { + cgraph_update_edges_for_call_stmt_node (node, old_stmt, new_stmt); + if (node->clones) + node = node->clones; + else if (node->next_sibling_clone) + node = node->next_sibling_clone; + else + { + while (node != orig && !node->next_sibling_clone) + node = node->clone_of; + if (node != orig) + node = node->next_sibling_clone; + } + } +} + /* Remove all callees from the node. */ @@ -998,24 +1098,100 @@ cgraph_remove_node (struct cgraph_node *node) slot = htab_find_slot (cgraph_hash, node, NO_INSERT); if (*slot == node) { - if (node->next_clone) - { - struct cgraph_node *new_node = node->next_clone; + struct cgraph_node *next_inline_clone; - *slot = new_node; - node->next_clone->prev_clone = NULL; - } + for (next_inline_clone = node->clones; + next_inline_clone && next_inline_clone->decl != node->decl; + next_inline_clone = next_inline_clone->next_sibling_clone) + ; + + /* If there is inline clone of the node being removed, we need + to put it into the position of removed node and reorganize all + other clones to be based on it. */ + if (next_inline_clone) + { + struct cgraph_node *n; + struct cgraph_node *new_clones; + + *slot = next_inline_clone; + + /* Unlink inline clone from the list of clones of removed node. */ + if (next_inline_clone->next_sibling_clone) + next_inline_clone->next_sibling_clone->prev_sibling_clone + = next_inline_clone->prev_sibling_clone; + if (next_inline_clone->prev_sibling_clone) + { + next_inline_clone->prev_sibling_clone->next_sibling_clone + = next_inline_clone->next_sibling_clone; + } + else + node->clones = next_inline_clone->next_sibling_clone; + + new_clones = node->clones; + node->clones = NULL; + + /* Copy clone info. */ + next_inline_clone->clone = node->clone; + + /* Now place it into clone tree at same level at NODE. */ + next_inline_clone->clone_of = node->clone_of; + next_inline_clone->prev_sibling_clone = NULL; + next_inline_clone->next_sibling_clone = NULL; + if (node->clone_of) + { + next_inline_clone->next_sibling_clone = node->clone_of->clones; + node->clone_of->clones = next_inline_clone; + } + + /* Merge the clone list. */ + if (new_clones) + { + if (!next_inline_clone->clones) + next_inline_clone->clones = new_clones; + else + { + n = next_inline_clone->clones; + while (n->next_sibling_clone) + n = n->next_sibling_clone; + n->next_sibling_clone = new_clones; + new_clones->prev_sibling_clone = n; + } + } + + /* Update clone_of pointers. */ + n = new_clones; + while (n) + { + n->clone_of = next_inline_clone; + n = n->next_sibling_clone; + } + } else { htab_clear_slot (cgraph_hash, slot); kill_body = true; } + } else + gcc_assert (node->clone_of); + if (node->prev_sibling_clone) + node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; + else if (node->clone_of) + node->clone_of->clones = node->next_sibling_clone; + if (node->next_sibling_clone) + node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone; + if (node->clones) { - node->prev_clone->next_clone = node->next_clone; - if (node->next_clone) - node->next_clone->prev_clone = node->prev_clone; + struct cgraph_node *n; + + for (n = node->clones; n->next_sibling_clone; n = n->next_sibling_clone) + n->clone_of = node->clone_of; + n->clone_of = node->clone_of; + n->next_sibling_clone = node->clone_of->clones; + if (node->clone_of->clones) + node->clone_of->clones->prev_sibling_clone = n; + node->clone_of->clones = node->clones; } /* While all the clones are removed after being proceeded, the function @@ -1025,7 +1201,7 @@ cgraph_remove_node (struct cgraph_node *node) if (!kill_body && *slot) { struct cgraph_node *n = (struct cgraph_node *) *slot; - if (!n->next_clone && !n->global.inlined_to + if (!n->clones && !n->clone_of && !n->global.inlined_to && (cgraph_global_info_ready && (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl)))) kill_body = true; @@ -1059,6 +1235,21 @@ cgraph_remove_node (struct cgraph_node *node) free_nodes = node; } +/* Remove the node from cgraph. */ + +void +cgraph_remove_node_and_inline_clones (struct cgraph_node *node) +{ + struct cgraph_edge *e, *next; + for (e = node->callees; e; e = next) + { + next = e->next_callee; + if (!e->inline_failed) + cgraph_remove_node_and_inline_clones (e->callee); + } + cgraph_remove_node (node); +} + /* Notify finalize_compilation_unit that given node is reachable. */ void @@ -1166,6 +1357,10 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf (f, " (inline copy in %s/%i)", cgraph_node_name (node->global.inlined_to), node->global.inlined_to->uid); + if (node->clone_of) + fprintf (f, " (clone of %s/%i)", + cgraph_node_name (node->clone_of), + node->clone_of->uid); if (cgraph_function_flags_ready) fprintf (f, " availability:%s", cgraph_availability_names [cgraph_function_body_availability (node)]); @@ -1382,6 +1577,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq, new_node->global = n->global; new_node->rtl = n->rtl; new_node->count = count; + new_node->clone = n->clone; if (n->count) { if (new_node->count > n->count) @@ -1402,16 +1598,117 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq, cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest, update_original); - new_node->next_clone = n->next_clone; - new_node->prev_clone = n; - n->next_clone = new_node; - if (new_node->next_clone) - new_node->next_clone->prev_clone = new_node; + new_node->next_sibling_clone = n->clones; + if (n->clones) + n->clones->prev_sibling_clone = new_node; + n->clones = new_node; + new_node->clone_of = n; cgraph_call_node_duplication_hooks (n, new_node); return new_node; } +/* Create a new name for omp child function. Returns an identifier. */ + +static GTY(()) unsigned int clone_fn_id_num; + +static tree +clone_function_name (tree decl) +{ + tree name = DECL_ASSEMBLER_NAME (decl); + size_t len = IDENTIFIER_LENGTH (name); + char *tmp_name, *prefix; + + prefix = XALLOCAVEC (char, len + strlen ("_clone") + 1); + memcpy (prefix, IDENTIFIER_POINTER (name), len); + strcpy (prefix + len, "_clone"); +#ifndef NO_DOT_IN_LABEL + prefix[len] = '.'; +#elif !defined NO_DOLLAR_IN_LABEL + prefix[len] = '$'; +#endif + ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++); + return get_identifier (tmp_name); +} + +/* Create callgraph node clone with new declaration. The actual body will + be copied later at compilation stage. + + TODO: after merging in ipa-sra use function call notes instead of args_to_skip + bitmap interface. + */ +struct cgraph_node * +cgraph_create_virtual_clone (struct cgraph_node *old_node, + VEC(cgraph_edge_p,heap) *redirect_callers, + VEC(ipa_replace_map_p,gc) *tree_map, + bitmap args_to_skip) +{ + tree old_decl = old_node->decl; + struct cgraph_node *new_node = NULL; + tree new_decl; + struct cgraph_node key, **slot; + unsigned i; + struct cgraph_edge *e; + + gcc_assert (tree_versionable_function_p (old_decl)); + + /* Make a new FUNCTION_DECL tree node */ + if (!args_to_skip) + new_decl = copy_node (old_decl); + else + new_decl = build_function_decl_skip_args (old_decl, args_to_skip); + DECL_STRUCT_FUNCTION (new_decl) = NULL; + + /* Generate a new name for the new version. */ + DECL_NAME (new_decl) = clone_function_name (old_decl); + SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); + SET_DECL_RTL (new_decl, NULL); + + new_node = cgraph_clone_node (old_node, old_node->count, + CGRAPH_FREQ_BASE, 0, false); + new_node->decl = new_decl; + /* Update the properties. + Make clone visible only within this translation unit. Make sure + that is not weak also. + ??? We cannot use COMDAT linkage because there is no + ABI support for this. */ + DECL_EXTERNAL (new_node->decl) = 0; + DECL_ONE_ONLY (new_node->decl) = 0; + TREE_PUBLIC (new_node->decl) = 0; + DECL_COMDAT (new_node->decl) = 0; + DECL_WEAK (new_node->decl) = 0; + new_node->clone.tree_map = tree_map; + new_node->clone.args_to_skip = args_to_skip; + new_node->local.externally_visible = 0; + new_node->local.local = 1; + new_node->lowered = true; + new_node->reachable = true; + + key.decl = new_decl; + slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT); + gcc_assert (!*slot); + *slot = new_node; + if (assembler_name_hash) + { + void **aslot; + tree name = DECL_ASSEMBLER_NAME (new_decl); + + aslot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + INSERT); + gcc_assert (!*aslot); + *aslot = new_node; + } + for (i = 0; VEC_iterate (cgraph_edge_p, redirect_callers, i, e); i++) + { + /* Redirect calls to the old version node to point to its new + version. */ + cgraph_redirect_edge_callee (e, new_node); + } + + return new_node; +} + /* NODE is no longer nested function; update cgraph accordingly. */ void cgraph_unnest_node (struct cgraph_node *node) |