#include "cfgloop.h"
#include "cfglayout.h"
#include "hashtab.h"
+#include "tree-ssa-propagate.h"
/* This file contains functions for building the Control Flow Graph (CFG)
for a function tree. */
static edge tree_redirect_edge_and_branch (edge, basic_block);
static edge tree_try_redirect_by_replacing_jump (edge, basic_block);
static void split_critical_edges (void);
-static bool remove_fallthru_edge (VEC(edge) *);
+static bool remove_fallthru_edge (VEC(edge,gc) *);
/* Various helpers. */
static inline bool stmt_starts_bb_p (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
/* 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;
gcc_assert (last);
switch (TREE_CODE (last))
{
+ case RESX_EXPR:
+ break;
case CALL_EXPR:
/* If this function receives a nonlocal goto, then we need to
make edges from this call site to all the nonlocal goto
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);
}
/* This usually does nothing. But sometimes parts of cfg that originally
were inside a loop get out of it due to edge removal (since they
become unreachable by back edges from latch). */
- rewrite_into_loop_closed_ssa (changed_bbs);
+ rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa);
BITMAP_FREE (changed_bbs);
{
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++)
+ {
+ tree rhs;
+
+ fold_stmt_inplace (stmt);
+
+ rhs = get_rhs (stmt);
+ if (TREE_CODE (rhs) == ADDR_EXPR)
+ recompute_tree_invarant_for_addr_expr (rhs);
+
+ 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);
location_t loc = EXPR_LOCATION (stmt);
if (LOCATION_LINE (loc) > 0)
{
- warning ("%Hwill never be executed", &loc);
+ warning (0, "%Hwill never be executed", &loc);
return true;
}
}
{
release_defs (stmt);
- set_bb_for_stmt (stmt, NULL);
bsi_remove (&i);
}
loop above, so the last statement we process is the first statement
in the block. */
#ifdef USE_MAPPED_LOCATION
- if (warn_notreached && loc > BUILTINS_LOCATION)
- warning ("%Hwill never be executed", &loc);
+ if (loc > BUILTINS_LOCATION)
+ warning (OPT_Wunreachable_code, "%Hwill never be executed", &loc);
#else
- if (warn_notreached && loc)
- warning ("%Hwill never be executed", loc);
+ if (loc)
+ warning (OPT_Wunreachable_code, "%Hwill never be executed", loc);
#endif
remove_phi_nodes_and_edges_for_unreachable_block (bb);
happens, all the instructions after the call are no longer
reachable and must be deleted as dead. */
-VEC(tree) *modified_noreturn_calls;
+VEC(tree,gc) *modified_noreturn_calls;
/* Try to remove superfluous control structures. */
/* Remove any fallthru edge from EV. Return true if an edge was removed. */
static bool
-remove_fallthru_edge (VEC(edge) *ev)
+remove_fallthru_edge (VEC(edge,gc) *ev)
{
edge_iterator ei;
edge e;
add_stmt_to_eh_region (stmt, eh_region);
}
+ delink_stmt_imm_use (orig_stmt);
*bsi_stmt_ptr (*bsi) = stmt;
mark_stmt_modified (stmt);
update_modified_stmts (stmt);
break;
case ADDR_EXPR:
- /* ??? tree-ssa-alias.c may have overlooked dead PHI nodes, missing
- dead PHIs that take the address of something. But if the PHI
- result is dead, the fact that it takes the address of anything
- is irrelevant. Because we can not tell from here if a PHI result
- is dead, we just skip this check for PHIs altogether. This means
- we may be missing "valid" checks, but what can you do?
- This was PR19217. */
- if (in_phi)
- break;
+ {
+ bool old_invariant;
+ bool old_constant;
+ bool old_side_effects;
+ bool new_invariant;
+ bool new_constant;
+ bool new_side_effects;
+
+ /* ??? tree-ssa-alias.c may have overlooked dead PHI nodes, missing
+ dead PHIs that take the address of something. But if the PHI
+ result is dead, the fact that it takes the address of anything
+ is irrelevant. Because we can not tell from here if a PHI result
+ is dead, we just skip this check for PHIs altogether. This means
+ we may be missing "valid" checks, but what can you do?
+ This was PR19217. */
+ if (in_phi)
+ break;
- /* Skip any references (they will be checked when we recurse down the
- tree) and ensure that any variable used as a prefix is marked
- addressable. */
- for (x = TREE_OPERAND (t, 0);
- handled_component_p (x);
- x = TREE_OPERAND (x, 0))
- ;
-
- if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
- return NULL;
- if (!TREE_ADDRESSABLE (x))
- {
- error ("address taken, but ADDRESSABLE bit not set");
- return x;
- }
- break;
+ old_invariant = TREE_INVARIANT (t);
+ old_constant = TREE_CONSTANT (t);
+ old_side_effects = TREE_SIDE_EFFECTS (t);
+
+ recompute_tree_invarant_for_addr_expr (t);
+ new_invariant = TREE_INVARIANT (t);
+ new_side_effects = TREE_SIDE_EFFECTS (t);
+ new_constant = TREE_CONSTANT (t);
+
+ if (old_invariant != new_invariant)
+ {
+ error ("invariant not recomputed when ADDR_EXPR changed");
+ return t;
+ }
+
+ if (old_constant != new_constant)
+ {
+ error ("constant not recomputed when ADDR_EXPR changed");
+ return t;
+ }
+ if (old_side_effects != new_side_effects)
+ {
+ error ("side effects not recomputed when ADDR_EXPR changed");
+ return t;
+ }
+
+ /* Skip any references (they will be checked when we recurse down the
+ tree) and ensure that any variable used as a prefix is marked
+ addressable. */
+ for (x = TREE_OPERAND (t, 0);
+ handled_component_p (x);
+ x = TREE_OPERAND (x, 0))
+ ;
+
+ if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
+ return NULL;
+ if (!TREE_ADDRESSABLE (x))
+ {
+ error ("address taken, but ADDRESSABLE bit not set");
+ return x;
+ }
+ break;
+ }
case COND_EXPR:
x = COND_EXPR_COND (t);
stmt = bsi_stmt (bsi);
+ err |= verify_eh_edges (stmt);
+
if (is_ctrl_stmt (stmt))
{
FOR_EACH_EDGE (e, ei, bb->succs)
/* Now walk through the statements backward. We can ignore labels,
anything else means this is not a forwarder block. */
- for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
{
tree stmt = bsi_stmt (bsi);
return true;
}
+
/* Create a duplicate of the basic block BB. NOTE: This does not
preserve SSA form. */
{
basic_block new_bb;
block_stmt_iterator bsi, bsi_tgt;
- tree phi, val;
- ssa_op_iter op_iter;
+ tree phi;
new_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb);
- /* First copy the phi nodes. We do not copy phi node arguments here,
- since the edges are not ready yet. Keep the chain of phi nodes in
- the same order, so that we can add them later. */
+ /* Copy the PHI nodes. We ignore PHI node arguments here because
+ the incoming edges have not been setup yet. */
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
- mark_for_rewrite (PHI_RESULT (phi));
- create_phi_node (PHI_RESULT (phi), new_bb);
+ tree copy = create_phi_node (PHI_RESULT (phi), new_bb);
+ create_new_def_for (PHI_RESULT (copy), copy, PHI_RESULT_PTR (copy));
}
+
+ /* Keep the chain of PHI nodes in the same order so that they can be
+ updated by ssa_redirect_edge. */
set_phi_nodes (new_bb, phi_reverse (phi_nodes (new_bb)));
bsi_tgt = bsi_start (new_bb);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
- tree stmt = bsi_stmt (bsi);
- tree copy;
+ def_operand_p def_p;
+ ssa_op_iter op_iter;
+ tree stmt, copy;
+ int region;
+ stmt = bsi_stmt (bsi);
if (TREE_CODE (stmt) == LABEL_EXPR)
continue;
- FOR_EACH_SSA_TREE_OPERAND (val, stmt, op_iter, SSA_OP_ALL_DEFS)
- mark_for_rewrite (val);
-
+ /* Create a new copy of STMT and duplicate STMT's virtual
+ operands. */
copy = unshare_expr (stmt);
-
- /* Copy also the virtual operands. */
- get_stmt_ann (copy);
- copy_virtual_operands (copy, stmt);
-
bsi_insert_after (&bsi_tgt, copy, BSI_NEW_STMT);
+ copy_virtual_operands (copy, stmt);
+ region = lookup_stmt_eh_region (stmt);
+ if (region >= 0)
+ add_stmt_to_eh_region (copy, region);
+
+ /* Create new names for all the definitions created by COPY and
+ add replacement mappings for each new name. */
+ FOR_EACH_SSA_DEF_OPERAND (def_p, copy, op_iter, SSA_OP_ALL_DEFS)
+ create_new_def_for (DEF_FROM_PTR (def_p), copy, def_p);
}
return new_bb;
}
+
/* Basic block BB_COPY was created by code duplication. Add phi node
arguments for edges going out of BB_COPY. The blocks that were
duplicated have rbi->duplicated set to one. */
phi = phi_next, phi_copy = PHI_CHAIN (phi_copy))
{
phi_next = PHI_CHAIN (phi);
-
- gcc_assert (PHI_RESULT (phi) == PHI_RESULT (phi_copy));
def = PHI_ARG_DEF_FROM_EDGE (phi, e);
add_phi_arg (phi_copy, def, e_copy);
}
region_copy[i]->rbi->duplicated = 0;
}
-/* Maps the old ssa name FROM_NAME to TO_NAME. */
-
-struct ssa_name_map_entry
-{
- tree from_name;
- tree to_name;
-};
-
-/* Hash function for ssa_name_map_entry. */
-
-static hashval_t
-ssa_name_map_entry_hash (const void *entry)
-{
- const struct ssa_name_map_entry *en = entry;
- return SSA_NAME_VERSION (en->from_name);
-}
-
-/* Equality function for ssa_name_map_entry. */
-
-static int
-ssa_name_map_entry_eq (const void *in_table, const void *ssa_name)
-{
- const struct ssa_name_map_entry *en = in_table;
-
- return en->from_name == ssa_name;
-}
-
-/* Allocate duplicates of ssa names in list DEFINITIONS and store the mapping
- to MAP. */
-
-void
-allocate_ssa_names (bitmap definitions, htab_t *map)
-{
- tree name;
- struct ssa_name_map_entry *entry;
- PTR *slot;
- unsigned ver;
- bitmap_iterator bi;
-
- if (!*map)
- *map = htab_create (10, ssa_name_map_entry_hash,
- ssa_name_map_entry_eq, free);
- EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver, bi)
- {
- name = ssa_name (ver);
- slot = htab_find_slot_with_hash (*map, name, SSA_NAME_VERSION (name),
- INSERT);
- if (*slot)
- entry = *slot;
- else
- {
- entry = xmalloc (sizeof (struct ssa_name_map_entry));
- entry->from_name = name;
- *slot = entry;
- }
- entry->to_name = duplicate_ssa_name (name, SSA_NAME_DEF_STMT (name));
- }
-}
-
-/* Rewrite the definition DEF in statement STMT to new ssa name as specified
- by the mapping MAP. */
-
-static void
-rewrite_to_new_ssa_names_def (def_operand_p def, tree stmt, htab_t map)
-{
- tree name = DEF_FROM_PTR (def);
- struct ssa_name_map_entry *entry;
-
- gcc_assert (TREE_CODE (name) == SSA_NAME);
-
- entry = htab_find_with_hash (map, name, SSA_NAME_VERSION (name));
- if (!entry)
- return;
-
- SET_DEF (def, entry->to_name);
- SSA_NAME_DEF_STMT (entry->to_name) = stmt;
-}
-
-/* Rewrite the USE to new ssa name as specified by the mapping MAP. */
-
-static void
-rewrite_to_new_ssa_names_use (use_operand_p use, htab_t map)
-{
- tree name = USE_FROM_PTR (use);
- struct ssa_name_map_entry *entry;
-
- if (TREE_CODE (name) != SSA_NAME)
- return;
-
- entry = htab_find_with_hash (map, name, SSA_NAME_VERSION (name));
- if (!entry)
- return;
-
- SET_USE (use, entry->to_name);
-}
-
-/* Rewrite the ssa names in basic block BB to new ones as specified by the
- mapping MAP. */
-
-void
-rewrite_to_new_ssa_names_bb (basic_block bb, htab_t map)
-{
- unsigned i;
- edge e;
- edge_iterator ei;
- tree phi, stmt;
- block_stmt_iterator bsi;
- use_optype uses;
- vuse_optype vuses;
- def_optype defs;
- v_may_def_optype v_may_defs;
- v_must_def_optype v_must_defs;
- stmt_ann_t ann;
-
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (e->flags & EDGE_ABNORMAL)
- break;
-
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- {
- rewrite_to_new_ssa_names_def (PHI_RESULT_PTR (phi), phi, map);
- if (e)
- SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
- }
-
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- stmt = bsi_stmt (bsi);
- ann = stmt_ann (stmt);
-
- uses = USE_OPS (ann);
- for (i = 0; i < NUM_USES (uses); i++)
- rewrite_to_new_ssa_names_use (USE_OP_PTR (uses, i), map);
-
- defs = DEF_OPS (ann);
- for (i = 0; i < NUM_DEFS (defs); i++)
- rewrite_to_new_ssa_names_def (DEF_OP_PTR (defs, i), stmt, map);
-
- vuses = VUSE_OPS (ann);
- for (i = 0; i < NUM_VUSES (vuses); i++)
- rewrite_to_new_ssa_names_use (VUSE_OP_PTR (vuses, i), map);
-
- v_may_defs = V_MAY_DEF_OPS (ann);
- for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
- {
- rewrite_to_new_ssa_names_use
- (V_MAY_DEF_OP_PTR (v_may_defs, i), map);
- rewrite_to_new_ssa_names_def
- (V_MAY_DEF_RESULT_PTR (v_may_defs, i), stmt, map);
- }
-
- v_must_defs = V_MUST_DEF_OPS (ann);
- for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
- {
- rewrite_to_new_ssa_names_def
- (V_MUST_DEF_RESULT_PTR (v_must_defs, i), stmt, map);
- rewrite_to_new_ssa_names_use
- (V_MUST_DEF_KILL_PTR (v_must_defs, i), map);
- }
- }
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
- {
- rewrite_to_new_ssa_names_use
- (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), map);
-
- if (e->flags & EDGE_ABNORMAL)
- {
- tree op = PHI_ARG_DEF_FROM_EDGE (phi, e);
- SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
- }
- }
-}
-
-/* Rewrite the ssa names in N_REGION blocks REGION to the new ones as specified
- by the mapping MAP. */
-
-void
-rewrite_to_new_ssa_names (basic_block *region, unsigned n_region, htab_t map)
-{
- unsigned r;
-
- for (r = 0; r < n_region; r++)
- rewrite_to_new_ssa_names_bb (region[r], map);
-}
-
/* Duplicates a REGION (set of N_REGION basic blocks) with just a single
important exit edge EXIT. By important we mean that no SSA name defined
inside region is live over the other exit edges of the region. All entry
basic_block *region, unsigned n_region,
basic_block *region_copy)
{
- unsigned i, n_doms, ver;
+ unsigned i, n_doms;
bool free_region_copy = false, copying_header = false;
struct loop *loop = entry->dest->loop_father;
edge exit_copy;
- bitmap definitions;
- tree phi;
basic_block *doms;
- htab_t ssa_name_map = NULL;
edge redirected;
- bitmap_iterator bi;
+ int total_freq, entry_freq;
if (!can_copy_bbs_p (region, n_region))
return false;
missuses of the functions. I.e. if you ask to copy something weird,
it will work, but the state of structures probably will not be
correct. */
-
for (i = 0; i < n_region; i++)
{
/* We do not handle subloops, i.e. all the blocks must belong to the
free_region_copy = true;
}
- gcc_assert (!any_marked_for_rewrite_p ());
+ 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);
- definitions = marked_ssa_names ();
+ 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)
{
flush_pending_stmts (entry);
/* Concerning updating of dominators: We must recount dominators
- for entry block and its copy. Anything that is outside of the region, but
- was dominated by something inside needs recounting as well. */
+ for entry block and its copy. Anything that is outside of the
+ region, but was dominated by something inside needs recounting as
+ well. */
set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
doms[n_doms++] = entry->dest->rbi->original;
iterate_fix_dominators (CDI_DOMINATORS, doms, n_doms);
free (doms);
- /* Add the other phi node arguments. */
+ /* Add the other PHI node arguments. */
add_phi_args_after_copy (region_copy, n_region);
- /* Add phi nodes for definitions at exit. TODO -- once we have immediate
- uses, it should be possible to emit phi nodes just for definitions that
- are used outside region. */
- EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver, bi)
- {
- tree name = ssa_name (ver);
-
- phi = create_phi_node (name, exit->dest);
- add_phi_arg (phi, name, exit);
- add_phi_arg (phi, name, exit_copy);
-
- SSA_NAME_DEF_STMT (name) = phi;
- }
-
- /* And create new definitions inside region and its copy. TODO -- once we
- have immediate uses, it might be better to leave definitions in region
- unchanged, create new ssa names for phi nodes on exit, and rewrite
- the uses, to avoid changing the copied region. */
- allocate_ssa_names (definitions, &ssa_name_map);
- rewrite_to_new_ssa_names (region, n_region, ssa_name_map);
- allocate_ssa_names (definitions, &ssa_name_map);
- rewrite_to_new_ssa_names (region_copy, n_region, ssa_name_map);
- htab_delete (ssa_name_map);
+ /* Update the SSA web. */
+ update_ssa (TODO_update_ssa);
if (free_region_copy)
free (region_copy);
- unmark_all_for_rewrite ();
- BITMAP_FREE (definitions);
-
return true;
}
+
/* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree.h) */
void
}
fprintf (file, ")\n");
+ if (flags & TDF_DETAILS)
+ dump_eh_tree (file, DECL_STRUCT_FUNCTION (fn));
if (flags & TDF_RAW)
{
dump_node (fn, TDF_SLIM | flags, file);
/* When GIMPLE is lowered, the variables are no longer available in
BIND_EXPRs, so display them separately. */
- if (cfun && cfun->unexpanded_var_list)
+ if (cfun && cfun->decl == fn && cfun->unexpanded_var_list)
{
ignore_topmost_bind = true;
}
}
- if (basic_block_info)
+ if (cfun && cfun->decl == fn && cfun->cfg && basic_block_info)
{
/* Make a CFG based dump. */
check_bb_profile (ENTRY_BLOCK_PTR, file);
static bool
tree_block_ends_with_condjump_p (basic_block bb)
{
- tree stmt = tsi_stmt (bsi_last (bb).tsi);
- return (TREE_CODE (stmt) == COND_EXPR);
+ tree stmt = last_stmt (bb);
+ return (stmt && TREE_CODE (stmt) == COND_EXPR);
}
basic_block new_head, edge e)
{
tree phi1, phi2;
+ edge e2 = find_edge (new_head, second);
+
+ /* Because NEW_HEAD has been created by splitting SECOND's incoming
+ edge, we should always have an edge from NEW_HEAD to SECOND. */
+ gcc_assert (e2 != NULL);
/* Browse all 'second' basic block phi nodes and add phi args to
edge 'e' for 'first' head. PHI args are always in correct order. */
phi2 && phi1;
phi2 = PHI_CHAIN (phi2), phi1 = PHI_CHAIN (phi1))
{
- edge e2 = find_edge (new_head, second);
-
- if (e2)
- {
- tree def = PHI_ARG_DEF (phi2, e2->dest_idx);
- add_phi_arg (phi1, def, e);
- }
+ tree def = PHI_ARG_DEF (phi2, e2->dest_idx);
+ add_phi_arg (phi1, def, e);
}
}
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 ("%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)
#ifdef USE_MAPPED_LOCATION
if (location == UNKNOWN_LOCATION)
location = cfun->function_end_locus;
- warning ("%H%<noreturn%> function does return", &location);
+ warning (0, "%H%<noreturn%> function does return", &location);
#else
if (!locus)
locus = &cfun->function_end_locus;
- warning ("%H%<noreturn%> function does return", locus);
+ warning (0, "%H%<noreturn%> function does return", locus);
#endif
}
location = EXPR_LOCATION (last);
if (location == UNKNOWN_LOCATION)
location = cfun->function_end_locus;
- warning ("%Hcontrol reaches end of non-void function", &location);
+ warning (0, "%Hcontrol reaches end of non-void function", &location);
#else
locus = EXPR_LOCUS (last);
if (!locus)
locus = &cfun->function_end_locus;
- warning ("%Hcontrol reaches end of non-void function", locus);
+ warning (0, "%Hcontrol reaches end of non-void function", locus);
#endif
TREE_NO_WARNING (cfun->decl) = 1;
break;
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 */
+};