From 91382288079e2b47f7a18252051036e4f76c6ada Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 1 Jun 2010 17:43:27 +0200 Subject: cgraph.h (tree_function_versioning): Update prototype. * cgraph.h (tree_function_versioning): Update prototype. (cgraph_function_versioning): Update prototype. * cgraphunit.c (cgraph_copy_node_for_versioning): Accept bbs_to_copy bitmap. (cgraph_function_versioning): Accept new_entry_block and bbs_to_copy. (cgraph_materialize_clone, save_inline_function_body): Update use of tree_function_versioning. * tree-inline.c (copy_bb): Look for previous copied block to link after; fix debug output. (copy_cfg_body): Accept new_entry_block and bbs_to_copy. (copy_body): Likewise. (expand_call_inline): Update use of copy_body. (tree_function_versioning): Update use of copy body; accept blocks_to_copy and new_entry. From-SVN: r160110 --- gcc/ChangeLog | 17 ++++++++ gcc/cgraph.h | 6 ++- gcc/cgraphunit.c | 49 +++++++++++++-------- gcc/testsuite/gcc.dg/lto/noreturn-1_0.c | 21 +++++++++ gcc/testsuite/gcc.dg/lto/noreturn-1_1.c | 27 ++++++++++++ gcc/tree-inline.c | 76 +++++++++++++++++++++++---------- 6 files changed, 154 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/lto/noreturn-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/noreturn-1_1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c131796..0ff31f1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,22 @@ 2010-06-01 Jan Hubicka + * cgraph.h (tree_function_versioning): Update prototype. + (cgraph_function_versioning): Update prototype. + * cgraphunit.c (cgraph_copy_node_for_versioning): Accept bbs_to_copy + bitmap. + (cgraph_function_versioning): Accept new_entry_block and bbs_to_copy. + (cgraph_materialize_clone, save_inline_function_body): Update use of + tree_function_versioning. + * tree-inline.c (copy_bb): Look for previous copied block to link after; + fix debug output. + (copy_cfg_body): Accept new_entry_block and bbs_to_copy. + (copy_body): Likewise. + (expand_call_inline): Update use of copy_body. + (tree_function_versioning): Update use of copy body; accept + blocks_to_copy and new_entry. + +2010-06-01 Jan Hubicka + * gegenrtl.c: Remove unnecesary prototypes. (gendecl): Remove. (gendef): Produce static inline. diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 3c91f049..c82fc18 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -616,8 +616,10 @@ void init_cgraph (void); struct cgraph_node *cgraph_function_versioning (struct cgraph_node *, VEC(cgraph_edge_p,heap)*, VEC(ipa_replace_map_p,gc)*, - bitmap, const char *); -void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bitmap); + bitmap, bitmap, basic_block, + const char *); +void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bitmap, + bitmap, basic_block); struct cgraph_node *save_inline_function_body (struct cgraph_node *); void record_references_in_initializer (tree, bool); bool cgraph_process_new_functions (void); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 1d5ed0d..47686a4 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -2102,13 +2102,18 @@ update_call_expr (struct cgraph_node *new_version) edges which should be redirected to point to NEW_VERSION. ALL the callees edges of OLD_VERSION are cloned to the new version node. Return the new - version node. */ + version node. + + If non-NULL BLOCK_TO_COPY determine what basic blocks + was copied to prevent duplications of calls that are dead + in the clone. */ static struct cgraph_node * cgraph_copy_node_for_versioning (struct cgraph_node *old_version, tree new_decl, - VEC(cgraph_edge_p,heap) *redirect_callers) -{ + VEC(cgraph_edge_p,heap) *redirect_callers, + bitmap bbs_to_copy) + { struct cgraph_node *new_version; struct cgraph_edge *e; unsigned i; @@ -2128,15 +2133,19 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, new_version->count = old_version->count; for (e = old_version->callees; e; e=e->next_callee) - cgraph_clone_edge (e, new_version, e->call_stmt, - e->lto_stmt_uid, REG_BR_PROB_BASE, - CGRAPH_FREQ_BASE, - e->loop_nest, true); + if (!bbs_to_copy + || bitmap_bit_p (bbs_to_copy, gimple_bb (e->call_stmt)->index)) + cgraph_clone_edge (e, new_version, e->call_stmt, + e->lto_stmt_uid, REG_BR_PROB_BASE, + CGRAPH_FREQ_BASE, + e->loop_nest, true); for (e = old_version->indirect_calls; e; e=e->next_callee) - cgraph_clone_edge (e, new_version, e->call_stmt, - e->lto_stmt_uid, REG_BR_PROB_BASE, - CGRAPH_FREQ_BASE, - e->loop_nest, true); + if (!bbs_to_copy + || bitmap_bit_p (bbs_to_copy, gimple_bb (e->call_stmt)->index)) + cgraph_clone_edge (e, new_version, e->call_stmt, + e->lto_stmt_uid, REG_BR_PROB_BASE, + CGRAPH_FREQ_BASE, + e->loop_nest, true); 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 @@ -2159,14 +2168,18 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, new ones (according to results of prior analysis). OLD_VERSION_NODE is the node that is versioned. It returns the new version's cgraph node. - ARGS_TO_SKIP lists arguments to be omitted from functions - */ + If non-NULL ARGS_TO_SKIP determine function parameters to remove + from new version. + If non-NULL BLOCK_TO_COPY determine what basic blocks to copy. + If non_NULL NEW_ENTRY determine new entry BB of the clone. */ struct cgraph_node * cgraph_function_versioning (struct cgraph_node *old_version_node, VEC(cgraph_edge_p,heap) *redirect_callers, VEC (ipa_replace_map_p,gc)* tree_map, bitmap args_to_skip, + bitmap bbs_to_copy, + basic_block new_entry_block, const char *clone_name) { tree old_decl = old_version_node->decl; @@ -2193,10 +2206,11 @@ cgraph_function_versioning (struct cgraph_node *old_version_node, and update the edges of the new node. */ new_version_node = cgraph_copy_node_for_versioning (old_version_node, new_decl, - redirect_callers); + redirect_callers, bbs_to_copy); /* Copy the OLD_VERSION_NODE function tree to the new version. */ - tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip); + tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip, + bbs_to_copy, new_entry_block); /* Update the new version's properties. Make The new version visible only within this translation unit. Make sure @@ -2267,7 +2281,8 @@ save_inline_function_body (struct cgraph_node *node) } /* Copy the OLD_VERSION_NODE function tree to the new version. */ - tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL); + tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL, + NULL, NULL); DECL_EXTERNAL (first_clone->decl) = 0; DECL_COMDAT_GROUP (first_clone->decl) = NULL_TREE; @@ -2296,7 +2311,7 @@ cgraph_materialize_clone (struct cgraph_node *node) /* Copy the OLD_VERSION_NODE function tree to the new version. */ tree_function_versioning (node->clone_of->decl, node->decl, node->clone.tree_map, true, - node->clone.args_to_skip); + node->clone.args_to_skip, NULL, NULL); if (cgraph_dump_file) { dump_function_to_file (node->clone_of->decl, cgraph_dump_file, dump_flags); diff --git a/gcc/testsuite/gcc.dg/lto/noreturn-1_0.c b/gcc/testsuite/gcc.dg/lto/noreturn-1_0.c new file mode 100644 index 0000000..eb71c64 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/noreturn-1_0.c @@ -0,0 +1,21 @@ +void exit (int); +__attribute__ ((noreturn)) +int +call_me (void) +{ + exit (0); +} +void exit (int); +__attribute__ ((noreturn)) +int +call_me (void) +{ + exit (0); +} +void exit (int); +__attribute__ ((noreturn)) +int +call_me (void) +{ + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/lto/noreturn-1_1.c b/gcc/testsuite/gcc.dg/lto/noreturn-1_1.c new file mode 100644 index 0000000..8e8b060 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/noreturn-1_1.c @@ -0,0 +1,27 @@ +/* { dg-lto-do run } */ +/* { dg-lto-options {{-O2 -fwhopr} } } */ + +int call_me (void); +int +main(void) +{ + return call_me (); +} +/* { dg-lto-do run } */ +/* { dg-lto-options {{-O2 -fwhopr} } } */ + +int call_me (void); +int +main(void) +{ + return call_me (); +} +/* { dg-lto-do run } */ +/* { dg-lto-options {{-O2 -fwhopr} } } */ + +int call_me (void); +int +main(void) +{ + return call_me (); +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 4ac1b3f..fce6ae5 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1488,11 +1488,17 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, basic_block copy_basic_block; tree decl; gcov_type freq; + basic_block prev; + + /* Search for previous copied basic block. */ + prev = bb->prev_bb; + while (!prev->aux) + prev = prev->prev_bb; /* create_basic_block() will append every new block to basic_block_info automatically. */ copy_basic_block = create_basic_block (NULL, (void *) 0, - (basic_block) bb->prev_bb->aux); + (basic_block) prev->aux); copy_basic_block->count = bb->count * count_scale / REG_BR_PROB_BASE; /* We are going to rebuild frequencies from scratch. These values @@ -1728,7 +1734,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, = CIF_ORIGINALLY_INDIRECT_CALL; if (dump_file) { - fprintf (dump_file, "Created new direct edge to %s", + fprintf (dump_file, "Created new direct edge to %s\n", cgraph_node_name (dest)); } } @@ -2131,7 +2137,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb) static tree copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale, - basic_block entry_block_map, basic_block exit_block_map) + basic_block entry_block_map, basic_block exit_block_map, + bitmap blocks_to_copy, basic_block new_entry) { tree callee_fndecl = id->src_fn; /* Original cfun for the callee, doesn't change. */ @@ -2170,32 +2177,46 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale, /* Use aux pointers to map the original blocks to copy. */ FOR_EACH_BB_FN (bb, cfun_to_copy) - { - basic_block new_bb = copy_bb (id, bb, frequency_scale, count_scale); - bb->aux = new_bb; - new_bb->aux = bb; - } + if (!blocks_to_copy || bitmap_bit_p (blocks_to_copy, bb->index)) + { + basic_block new_bb = copy_bb (id, bb, frequency_scale, count_scale); + bb->aux = new_bb; + new_bb->aux = bb; + } last = last_basic_block; /* Now that we've duplicated the blocks, duplicate their edges. */ FOR_ALL_BB_FN (bb, cfun_to_copy) - need_debug_cleanup |= copy_edges_for_bb (bb, count_scale, exit_block_map); + if (!blocks_to_copy + || (bb->index > 0 && bitmap_bit_p (blocks_to_copy, bb->index))) + need_debug_cleanup |= copy_edges_for_bb (bb, count_scale, exit_block_map); if (gimple_in_ssa_p (cfun)) FOR_ALL_BB_FN (bb, cfun_to_copy) - copy_phis_for_bb (bb, id); + if (!blocks_to_copy + || (bb->index > 0 && bitmap_bit_p (blocks_to_copy, bb->index))) + copy_phis_for_bb (bb, id); - FOR_ALL_BB_FN (bb, cfun_to_copy) + if (new_entry) { - if (need_debug_cleanup - && bb->index != ENTRY_BLOCK - && bb->index != EXIT_BLOCK) - maybe_move_debug_stmts_to_successors (id, (basic_block) bb->aux); - ((basic_block)bb->aux)->aux = NULL; - bb->aux = NULL; + edge e; + e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU); + e->probability = REG_BR_PROB_BASE; + e->count = entry_block_map->count; } + FOR_ALL_BB_FN (bb, cfun_to_copy) + if (bb->aux) + { + if (need_debug_cleanup + && bb->index != ENTRY_BLOCK + && bb->index != EXIT_BLOCK) + maybe_move_debug_stmts_to_successors (id, (basic_block) bb->aux); + ((basic_block)bb->aux)->aux = NULL; + bb->aux = NULL; + } + /* Zero out AUX fields of newly created block during EH edge insertion. */ for (; last < last_basic_block; last++) @@ -2317,14 +2338,16 @@ copy_tree_body (copy_body_data *id) static tree copy_body (copy_body_data *id, gcov_type count, int frequency_scale, - basic_block entry_block_map, basic_block exit_block_map) + basic_block entry_block_map, basic_block exit_block_map, + bitmap blocks_to_copy, basic_block new_entry) { tree fndecl = id->src_fn; tree body; /* If this body has a CFG, walk CFG and copy. */ gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (fndecl))); - body = copy_cfg_body (id, count, frequency_scale, entry_block_map, exit_block_map); + body = copy_cfg_body (id, count, frequency_scale, entry_block_map, exit_block_map, + blocks_to_copy, new_entry); copy_debug_stmts (id); return body; @@ -3924,7 +3947,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id) duplicate our body before altering anything. */ copy_body (id, bb->count, cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE, - bb, return_block); + bb, return_block, NULL, NULL); /* Reset the escaped solution. */ if (cfun->gimple_df) @@ -4957,11 +4980,18 @@ update_clone_info (copy_body_data * id) tree with another tree while duplicating the function's body, TREE_MAP represents the mapping between these trees. If UPDATE_CLONES is set, the call_stmt fields - of edges of clones of the function will be updated. */ + of edges of clones of the function will be updated. + + If non-NULL ARGS_TO_SKIP determine function parameters to remove + from new version. + If non-NULL BLOCK_TO_COPY determine what basic blocks to copy. + If non_NULL NEW_ENTRY determine new entry BB of the clone. +*/ void tree_function_versioning (tree old_decl, tree new_decl, VEC(ipa_replace_map_p,gc)* tree_map, - bool update_clones, bitmap args_to_skip) + bool update_clones, bitmap args_to_skip, + bitmap blocks_to_copy, basic_block new_entry) { struct cgraph_node *old_version_node; struct cgraph_node *new_version_node; @@ -5113,7 +5143,7 @@ tree_function_versioning (tree old_decl, tree new_decl, /* Copy the Function's body. */ copy_body (&id, old_entry_block->count, REG_BR_PROB_BASE, - ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR); + ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, blocks_to_copy, new_entry); if (DECL_RESULT (old_decl) != NULL_TREE) { -- cgit v1.1