X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-cfg.c;h=9eeb78392873a64dfafde04f6ab7e6db0b58bbf4;hb=576aff9d272cd8ebec2b93b10dcf5eae125e9667;hp=26dced0b69afad20bc3cdbdd547066c7be385893;hpb=31c59bca2fb5735d55ab94b3b3ebaab3f6a7cc28;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 26dced0b69a..9eeb7839287 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -132,6 +132,26 @@ static tree find_case_label_for_value (tree, tree); static bool phi_alternatives_equal (basic_block, edge, edge); static bool cleanup_forwarder_blocks (void); +void +init_empty_tree_cfg (void) +{ + /* Initialize the basic block array. */ + init_flow (); + profile_status = PROFILE_ABSENT; + n_basic_blocks = 0; + last_basic_block = 0; + VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info"); + + /* Build a mapping of labels to their associated blocks. */ + VARRAY_BB_INIT (label_to_block_map, initial_cfg_capacity, + "label to block map"); + + ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; + EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; + + create_block_annotation (ENTRY_BLOCK_PTR); + create_block_annotation (EXIT_BLOCK_PTR); +} /*--------------------------------------------------------------------------- Create basic blocks @@ -146,20 +166,9 @@ build_tree_cfg (tree *tp) /* Register specific tree functions. */ tree_register_cfg_hooks (); - /* Initialize the basic block array. */ - init_flow (); - profile_status = PROFILE_ABSENT; - n_basic_blocks = 0; - last_basic_block = 0; - VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info"); memset ((void *) &cfg_stats, 0, sizeof (cfg_stats)); - /* Build a mapping of labels to their associated blocks. */ - VARRAY_BB_INIT (label_to_block_map, initial_cfg_capacity, - "label to block map"); - - ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; - EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; + init_empty_tree_cfg (); found_computed_goto = 0; make_blocks (*tp); @@ -176,9 +185,6 @@ build_tree_cfg (tree *tp) if (n_basic_blocks == 0) create_empty_bb (ENTRY_BLOCK_PTR); - create_block_annotation (ENTRY_BLOCK_PTR); - create_block_annotation (EXIT_BLOCK_PTR); - /* Adjust the size of the array. */ VARRAY_GROW (basic_block_info, n_basic_blocks); @@ -206,6 +212,10 @@ build_tree_cfg (tree *tp) } } +#ifdef ENABLE_CHECKING + verify_stmts (); +#endif + /* Dump a textual representation of the flowgraph. */ if (dump_file) dump_tree_cfg (dump_file, dump_flags); @@ -436,7 +446,7 @@ create_bb (void *h, void *e, basic_block after) /* Fold COND_EXPR_COND of each COND_EXPR. */ -static void +void fold_cond_expr_cond (void) { basic_block bb; @@ -823,6 +833,8 @@ label_to_block_fn (struct function *ifun, tree dest) bsi_insert_before (&bsi, stmt, BSI_NEW_STMT); uid = LABEL_DECL_UID (dest); } + if (VARRAY_SIZE (ifun->cfg->x_label_to_block_map) <= (unsigned int)uid) + return NULL; return VARRAY_BB (ifun->cfg->x_label_to_block_map, uid); } @@ -1249,6 +1261,7 @@ tree_can_merge_blocks_p (basic_block a, basic_block b) { tree stmt; block_stmt_iterator bsi; + tree phi; if (!single_succ_p (a)) return false; @@ -1276,9 +1289,19 @@ tree_can_merge_blocks_p (basic_block a, basic_block b) && DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt))) return false; - /* There may be no PHI nodes at the start of B. */ - if (phi_nodes (b)) - return false; + /* It must be possible to eliminate all phi nodes in B. If ssa form + is not up-to-date, we cannot eliminate any phis. */ + phi = phi_nodes (b); + if (phi) + { + if (need_ssa_update_p ()) + return false; + + for (; phi; phi = PHI_CHAIN (phi)) + if (!is_gimple_reg (PHI_RESULT (phi)) + && !may_propagate_copy (PHI_RESULT (phi), PHI_ARG_DEF (phi, 0))) + return false; + } /* Do not remove user labels. */ for (bsi = bsi_start (b); !bsi_end_p (bsi); bsi_next (&bsi)) @@ -1298,6 +1321,55 @@ tree_can_merge_blocks_p (basic_block a, basic_block b) return true; } +/* Replaces all uses of NAME by VAL. */ + +void +replace_uses_by (tree name, tree val) +{ + imm_use_iterator imm_iter; + use_operand_p use; + tree stmt; + edge e; + unsigned i; + VEC(tree,heap) *stmts = VEC_alloc (tree, heap, 20); + + FOR_EACH_IMM_USE_SAFE (use, imm_iter, name) + { + stmt = USE_STMT (use); + + SET_USE (use, val); + + if (TREE_CODE (stmt) == PHI_NODE) + { + e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use)); + if (e->flags & EDGE_ABNORMAL) + { + /* This can only occur for virtual operands, since + for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name)) + would prevent replacement. */ + gcc_assert (!is_gimple_reg (name)); + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1; + } + } + else + VEC_safe_push (tree, heap, stmts, stmt); + } + + /* We do not update the statements in the loop above. Consider + x = w * w; + + If we performed the update in the first loop, the statement + would be rescanned after first occurrence of w is replaced, + the new uses would be placed to the beginning of the list, + and we would never process them. */ + for (i = 0; VEC_iterate (tree, stmts, i, stmt); i++) + { + fold_stmt_inplace (stmt); + update_stmt (stmt); + } + + VEC_free (tree, heap, stmts); +} /* Merge block B into block A. */ @@ -1306,10 +1378,40 @@ tree_merge_blocks (basic_block a, basic_block b) { block_stmt_iterator bsi; tree_stmt_iterator last; + tree phi; if (dump_file) fprintf (dump_file, "Merging blocks %d and %d\n", a->index, b->index); + /* Remove the phi nodes. */ + bsi = bsi_last (a); + for (phi = phi_nodes (b); phi; phi = phi_nodes (b)) + { + tree def = PHI_RESULT (phi), use = PHI_ARG_DEF (phi, 0); + tree copy; + + if (!may_propagate_copy (def, use) + /* Propagating pointers might cause the set of vops for statements + to be changed, and thus require ssa form update. */ + || (is_gimple_reg (def) + && POINTER_TYPE_P (TREE_TYPE (def)))) + { + gcc_assert (is_gimple_reg (def)); + + /* Note that just emitting the copies is fine -- there is no problem + with ordering of phi nodes. This is because A is the single + predecessor of B, therefore results of the phi nodes cannot + appear as arguments of the phi nodes. */ + copy = build2 (MODIFY_EXPR, void_type_node, def, use); + bsi_insert_after (&bsi, copy, BSI_NEW_STMT); + SET_PHI_RESULT (phi, NULL_TREE); + SSA_NAME_DEF_STMT (def) = copy; + } + else + replace_uses_by (def, use); + remove_phi_node (phi, NULL); + } + /* Ensure that B follows A. */ move_block_after (b, a); @@ -1974,7 +2076,6 @@ remove_bb (basic_block bb) { release_defs (stmt); - set_bb_for_stmt (stmt, NULL); bsi_remove (&i); } @@ -4848,6 +4949,7 @@ tree_duplicate_sese_region (edge entry, edge exit, edge exit_copy; basic_block *doms; edge redirected; + int total_freq, entry_freq; if (!can_copy_bbs_p (region, n_region)) return false; @@ -4894,12 +4996,24 @@ tree_duplicate_sese_region (edge entry, edge exit, gcc_assert (!need_ssa_update_p ()); - /* Record blocks outside the region that are duplicated by something + /* Record blocks outside the region that are dominated by something inside. */ doms = xmalloc (sizeof (basic_block) * n_basic_blocks); n_doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region, doms); + total_freq = entry->dest->frequency; + entry_freq = EDGE_FREQUENCY (entry); + /* Fix up corner cases, to avoid division by zero or creation of negative + frequencies. */ + if (total_freq == 0) + total_freq = 1; + else if (entry_freq > total_freq) + entry_freq = total_freq; + copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop); + scale_bbs_frequencies_int (region, n_region, total_freq - entry_freq, + total_freq); + scale_bbs_frequencies_int (region_copy, n_region, entry_freq, total_freq); if (copying_header) { @@ -5606,14 +5720,6 @@ execute_warn_function_return (void) edge e; edge_iterator ei; - if (warn_missing_noreturn - && !TREE_THIS_VOLATILE (cfun->decl) - && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0 - && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl)) - warning (0, "%Jfunction might be possible candidate for " - "attribute %", - cfun->decl); - /* If we have a path to EXIT, then we do return. */ if (TREE_THIS_VOLATILE (cfun->decl) && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0) @@ -5717,3 +5823,34 @@ struct tree_opt_pass pass_warn_function_return = 0, /* todo_flags_finish */ 0 /* letter */ }; + +/* Emit noreturn warnings. */ + +static void +execute_warn_function_noreturn (void) +{ + if (warn_missing_noreturn + && !TREE_THIS_VOLATILE (cfun->decl) + && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0 + && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl)) + warning (0, "%Jfunction might be possible candidate for " + "attribute %", + cfun->decl); +} + +struct tree_opt_pass pass_warn_function_noreturn = +{ + NULL, /* name */ + NULL, /* gate */ + execute_warn_function_noreturn, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +};