X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-inline.c;h=f79ba75808816aaf09cb1f7c2cc855d0aa686920;hb=9dab78b8626157fec12a16727e729bd61a6969ef;hp=ed947da759a0ba20cfbe3bd7b76533aabc794eb5;hpb=389dd41bd043170e7dc7660304f14a5f16af3562;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index ed947da759a..f79ba758088 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -603,7 +603,12 @@ copy_statement_list (tree *tp) *tp = new_tree; for (; !tsi_end_p (oi); tsi_next (&oi)) - tsi_link_after (&ni, tsi_stmt (oi), TSI_NEW_STMT); + { + tree stmt = tsi_stmt (oi); + if (TREE_CODE (stmt) == STATEMENT_LIST) + copy_statement_list (&stmt); + tsi_link_after (&ni, stmt, TSI_CONTINUE_LINKING); + } } static void @@ -921,7 +926,8 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data) } else if (TREE_CODE (*tp) == STATEMENT_LIST) copy_statement_list (tp); - else if (TREE_CODE (*tp) == SAVE_EXPR) + else if (TREE_CODE (*tp) == SAVE_EXPR + || TREE_CODE (*tp) == TARGET_EXPR) remap_save_expr (tp, id->decl_map, walk_subtrees); else if (TREE_CODE (*tp) == LABEL_DECL && (! DECL_CONTEXT (*tp) @@ -1377,8 +1383,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, { tree new_rhs; new_rhs = force_gimple_operand_gsi (&seq_gsi, - gimple_assign_rhs1 (stmt), - true, NULL, true, GSI_SAME_STMT); + gimple_assign_rhs1 (stmt), + true, NULL, false, GSI_NEW_STMT); gimple_assign_set_rhs1 (stmt, new_rhs); id->regimplify = false; } @@ -1490,67 +1496,69 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, callgraph edges and update or duplicate them. */ if (is_gimple_call (stmt)) { - struct cgraph_edge *edge = cgraph_edge (id->src_node, orig_stmt); + struct cgraph_edge *edge; int flags; switch (id->transform_call_graph_edges) { - case CB_CGE_DUPLICATE: - if (edge) - cgraph_clone_edge (edge, id->dst_node, stmt, - REG_BR_PROB_BASE, 1, - edge->frequency, true); - break; - - case CB_CGE_MOVE_CLONES: - cgraph_set_call_stmt_including_clones (id->dst_node, orig_stmt, stmt); - break; - - case CB_CGE_MOVE: - if (edge) - cgraph_set_call_stmt (edge, stmt); - break; - - default: - gcc_unreachable (); + case CB_CGE_DUPLICATE: + edge = cgraph_edge (id->src_node, orig_stmt); + if (edge) + edge = cgraph_clone_edge (edge, id->dst_node, stmt, + REG_BR_PROB_BASE, 1, + edge->frequency, true); + break; + + case CB_CGE_MOVE_CLONES: + cgraph_set_call_stmt_including_clones (id->dst_node, + orig_stmt, stmt); + edge = cgraph_edge (id->dst_node, stmt); + break; + + case CB_CGE_MOVE: + edge = cgraph_edge (id->dst_node, orig_stmt); + if (edge) + cgraph_set_call_stmt (edge, stmt); + break; + + default: + gcc_unreachable (); } - edge = cgraph_edge (id->src_node, orig_stmt); - /* Constant propagation on argument done during inlining - may create new direct call. Produce an edge for it. */ - if ((!edge - || (edge->indirect_call - && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)) - && is_gimple_call (stmt) - && (fn = gimple_call_fndecl (stmt)) != NULL) - { - struct cgraph_node *dest = cgraph_node (fn); - - /* We have missing edge in the callgraph. This can happen in one case - where previous inlining turned indirect call into direct call by - constant propagating arguments. In all other cases we hit a bug - (incorrect node sharing is most common reason for missing edges. */ - gcc_assert (dest->needed || !dest->analyzed); - if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES) - cgraph_create_edge_including_clones (id->dst_node, dest, stmt, - bb->count, - compute_call_stmt_bb_frequency (id->dst_node->decl, bb), - bb->loop_depth, - CIF_ORIGINALLY_INDIRECT_CALL); - else - cgraph_create_edge (id->dst_node, dest, stmt, - bb->count, CGRAPH_FREQ_BASE, - bb->loop_depth)->inline_failed - = CIF_ORIGINALLY_INDIRECT_CALL; - if (dump_file) - { - fprintf (dump_file, "Created new direct edge to %s", - cgraph_node_name (dest)); - } - } + /* Constant propagation on argument done during inlining + may create new direct call. Produce an edge for it. */ + if ((!edge + || (edge->indirect_call + && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)) + && is_gimple_call (stmt) + && (fn = gimple_call_fndecl (stmt)) != NULL) + { + struct cgraph_node *dest = cgraph_node (fn); + + /* We have missing edge in the callgraph. This can happen + when previous inlining turned an indirect call into a + direct call by constant propagating arguments. In all + other cases we hit a bug (incorrect node sharing is the + most common reason for missing edges). */ + gcc_assert (dest->needed || !dest->analyzed); + if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES) + cgraph_create_edge_including_clones + (id->dst_node, dest, stmt, bb->count, + compute_call_stmt_bb_frequency (id->dst_node->decl, bb), + bb->loop_depth, CIF_ORIGINALLY_INDIRECT_CALL); + else + cgraph_create_edge (id->dst_node, dest, stmt, + bb->count, CGRAPH_FREQ_BASE, + bb->loop_depth)->inline_failed + = CIF_ORIGINALLY_INDIRECT_CALL; + if (dump_file) + { + fprintf (dump_file, "Created new direct edge to %s", + cgraph_node_name (dest)); + } + } flags = gimple_call_flags (stmt); - if (flags & ECF_MAY_BE_ALLOCA) cfun->calls_alloca = true; if (flags & ECF_RETURNS_TWICE) @@ -1820,7 +1828,8 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id) new_arg = force_gimple_operand (new_arg, &stmts, true, NULL); gsi_insert_seq_on_edge_immediate (new_edge, stmts); } - add_phi_arg (new_phi, new_arg, new_edge); + add_phi_arg (new_phi, new_arg, new_edge, + gimple_phi_arg_location_from_edge (phi, old_edge)); } } } @@ -3919,7 +3928,8 @@ unsave_r (tree *tp, int *walk_subtrees, void *data) gcc_unreachable (); else if (TREE_CODE (*tp) == BIND_EXPR) copy_bind_expr (tp, walk_subtrees, id); - else if (TREE_CODE (*tp) == SAVE_EXPR) + else if (TREE_CODE (*tp) == SAVE_EXPR + || TREE_CODE (*tp) == TARGET_EXPR) remap_save_expr (tp, st, walk_subtrees); else { @@ -4342,7 +4352,8 @@ copy_static_chain (tree static_chain, copy_body_data * id) bool tree_versionable_function_p (tree fndecl) { - return copy_forbidden (DECL_STRUCT_FUNCTION (fndecl), fndecl) == NULL; + return (!lookup_attribute ("noclone", DECL_ATTRIBUTES (fndecl)) + && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl), fndecl) == NULL); } /* Delete all unreachable basic blocks and update callgraph. @@ -4439,6 +4450,42 @@ delete_unreachable_blocks_update_callgraph (copy_body_data *id) return changed; } +/* Update clone info after duplication. */ + +static void +update_clone_info (copy_body_data * id) +{ + struct cgraph_node *node; + if (!id->dst_node->clones) + return; + for (node = id->dst_node->clones; node != id->dst_node;) + { + /* First update replace maps to match the new body. */ + if (node->clone.tree_map) + { + unsigned int i; + for (i = 0; i < VEC_length (ipa_replace_map_p, node->clone.tree_map); i++) + { + struct ipa_replace_map *replace_info; + replace_info = VEC_index (ipa_replace_map_p, node->clone.tree_map, i); + walk_tree (&replace_info->old_tree, copy_tree_body_r, id, NULL); + walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL); + } + } + if (node->clones) + node = node->clones; + else if (node->next_sibling_clone) + node = node->next_sibling_clone; + else + { + while (node != id->dst_node && !node->next_sibling_clone) + node = node->clone_of; + if (node != id->dst_node) + node = node->next_sibling_clone; + } + } +} + /* Create a copy of a function's tree. OLD_DECL and NEW_DECL are FUNCTION_DECL tree nodes of the original function and the new copied function @@ -4595,6 +4642,7 @@ tree_function_versioning (tree old_decl, tree new_decl, while (VEC_length (gimple, init_stmts)) insert_init_stmt (bb, VEC_pop (gimple, init_stmts)); } + update_clone_info (&id); /* Remap the nonlocal_goto_save_area, if any. */ if (cfun->nonlocal_goto_save_area)