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
/* 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);
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);
}
}
+#ifdef ENABLE_CHECKING
+ verify_stmts ();
+#endif
+
/* Dump a textual representation of the flowgraph. */
if (dump_file)
dump_tree_cfg (dump_file, dump_flags);
/* Fold COND_EXPR_COND of each COND_EXPR. */
-static void
+void
fold_cond_expr_cond (void)
{
basic_block bb;
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);
}
{
tree stmt;
block_stmt_iterator bsi;
+ tree phi;
if (!single_succ_p (a))
return false;
&& 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))
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. */
{
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);
{
release_defs (stmt);
- set_bb_for_stmt (stmt, NULL);
bsi_remove (&i);
}
edge exit_copy;
basic_block *doms;
edge redirected;
+ int total_freq, entry_freq;
if (!can_copy_bbs_p (region, n_region))
return false;
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)
{
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 %<noreturn%>",
- 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)
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 %<noreturn%>",
+ 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 */
+};