static int tree_verify_flow_info (void);
static void tree_make_forwarder_block (edge);
static void tree_cfg2vcg (FILE *);
+static inline void change_bb_for_stmt (tree t, basic_block bb);
/* Flowgraph optimization and cleanup. */
static void tree_merge_blocks (basic_block, basic_block);
0 /* letter */
};
-/* Search the CFG for any computed gotos. If found, factor them to a
+/* Search the CFG for any computed gotos. If found, factor them to a
common computed goto site. Also record the location of that site so
- that we can un-factor the gotos after we have converted back to
+ that we can un-factor the gotos after we have converted back to
normal form. */
static void
/* We know there are one or more computed gotos in this function.
Examine the last statement in each basic block to see if the block
ends with a computed goto. */
-
+
FOR_EACH_BB (bb)
{
block_stmt_iterator bsi = bsi_last (bb);
/* If this function receives a nonlocal goto, then we need to
make edges from this call site to all the nonlocal goto
handlers. */
- if (TREE_SIDE_EFFECTS (last)
- && current_function_has_nonlocal_label)
- make_goto_expr_edges (bb);
+ if (tree_can_make_abnormal_goto (last))
+ make_abnormal_goto_edges (bb, true);
/* If this statement has reachable exception handlers, then
create abnormal edges to them. */
/* A MODIFY_EXPR may have a CALL_EXPR on its RHS and the
CALL_EXPR may have an abnormal edge. Search the RHS for
this case and create any required edges. */
- tree op = get_call_expr_in (last);
- if (op && TREE_SIDE_EFFECTS (op)
- && current_function_has_nonlocal_label)
- make_goto_expr_edges (bb);
+ if (tree_can_make_abnormal_goto (last))
+ make_abnormal_goto_edges (bb, true);
make_eh_edges (last);
}
}
}
break;
-
+
default:
gcc_unreachable ();
}
/* Called for each element in the hash table (P) as we delete the
edge to cases hash table.
- Clear all the TREE_CHAINs to prevent problems with copying of
+ Clear all the TREE_CHAINs to prevent problems with copying of
SWITCH_EXPRs and structure sharing rules, then free the hash table
element. */
chains available. Return NULL so the caller can detect this case. */
if (!recording_case_labels_p ())
return NULL;
-
+
restart:
elt.e = e;
elt.case_labels = NULL;
and undefined variable warnings quite right. */
if ((errorcount || sorrycount) && uid < 0)
{
- block_stmt_iterator bsi =
+ block_stmt_iterator bsi =
bsi_start (BASIC_BLOCK (NUM_FIXED_BLOCKS));
tree stmt;
return VEC_index (basic_block, ifun->cfg->x_label_to_block_map, uid);
}
+/* Create edges for an abnormal goto statement at block BB. If FOR_CALL
+ is true, the source statement is a CALL_EXPR instead of a GOTO_EXPR. */
+
+void
+make_abnormal_goto_edges (basic_block bb, bool for_call)
+{
+ basic_block target_bb;
+ block_stmt_iterator bsi;
+
+ FOR_EACH_BB (target_bb)
+ for (bsi = bsi_start (target_bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree target = bsi_stmt (bsi);
+
+ if (TREE_CODE (target) != LABEL_EXPR)
+ break;
+
+ target = LABEL_EXPR_LABEL (target);
+
+ /* Make an edge to every label block that has been marked as a
+ potential target for a computed goto or a non-local goto. */
+ if ((FORCED_LABEL (target) && !for_call)
+ || (DECL_NONLOCAL (target) && for_call))
+ {
+ make_edge (bb, target_bb, EDGE_ABNORMAL);
+ break;
+ }
+ }
+}
+
/* Create edges for a goto statement at block BB. */
static void
make_goto_expr_edges (basic_block bb)
{
- tree goto_t;
- basic_block target_bb;
- bool for_call;
block_stmt_iterator last = bsi_last (bb);
+ tree goto_t = bsi_stmt (last);
- goto_t = bsi_stmt (last);
-
- /* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR,
- CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
- from a nonlocal goto. */
- if (TREE_CODE (goto_t) != GOTO_EXPR)
- for_call = true;
- else
+ /* A simple GOTO creates normal edges. */
+ if (simple_goto_p (goto_t))
{
tree dest = GOTO_DESTINATION (goto_t);
- for_call = false;
-
- /* A GOTO to a local label creates normal edges. */
- if (simple_goto_p (goto_t))
- {
- edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+ edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
#ifdef USE_MAPPED_LOCATION
- e->goto_locus = EXPR_LOCATION (goto_t);
+ e->goto_locus = EXPR_LOCATION (goto_t);
#else
- e->goto_locus = EXPR_LOCUS (goto_t);
+ e->goto_locus = EXPR_LOCUS (goto_t);
#endif
- bsi_remove (&last, true);
- return;
- }
-
- /* Nothing more to do for nonlocal gotos. */
- if (TREE_CODE (dest) == LABEL_DECL)
- return;
-
- /* Computed gotos remain. */
+ bsi_remove (&last, true);
+ return;
}
- /* Look for the block starting with the destination label. In the
- case of a computed goto, make an edge to any label block we find
- in the CFG. */
- FOR_EACH_BB (target_bb)
- {
- block_stmt_iterator bsi;
-
- for (bsi = bsi_start (target_bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- tree target = bsi_stmt (bsi);
-
- if (TREE_CODE (target) != LABEL_EXPR)
- break;
-
- if (
- /* Computed GOTOs. Make an edge to every label block that has
- been marked as a potential target for a computed goto. */
- (FORCED_LABEL (LABEL_EXPR_LABEL (target)) && !for_call)
- /* Nonlocal GOTO target. Make an edge to every label block
- that has been marked as a potential target for a nonlocal
- goto. */
- || (DECL_NONLOCAL (LABEL_EXPR_LABEL (target)) && for_call))
- {
- make_edge (bb, target_bb, EDGE_ABNORMAL);
- break;
- }
- }
- }
+ /* A computed GOTO creates abnormal edges. */
+ make_abnormal_goto_edges (bb, false);
}
break;
}
-
+
case SWITCH_EXPR:
{
size_t i;
tree vec = SWITCH_LABELS (stmt);
size_t n = TREE_VEC_LENGTH (vec);
-
+
/* Replace all destination labels. */
for (i = 0; i < n; ++i)
{
int old_size = TREE_VEC_LENGTH (labels);
int i, j, new_size = old_size;
tree default_case = TREE_VEC_ELT (labels, old_size - 1);
- tree default_label;
+ tree default_label;
/* The default label is always the last case in a switch
statement after gimplification. */
if (b == EXIT_BLOCK_PTR)
return false;
-
+
/* If A ends by a statement causing exceptions or something similar, we
cannot merge the blocks. */
stmt = last_stmt (a);
tree stmt;
edge e;
unsigned i;
- VEC(tree,heap) *stmts = VEC_alloc (tree, heap, 20);
- FOR_EACH_IMM_USE_SAFE (use, imm_iter, name)
+
+ FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
{
- stmt = USE_STMT (use);
- replace_exp (use, val);
+ FOR_EACH_IMM_USE_ON_STMT (use, imm_iter)
+ {
+ replace_exp (use, val);
- if (TREE_CODE (stmt) == PHI_NODE)
- {
- e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use));
- if (e->flags & EDGE_ABNORMAL)
+ if (TREE_CODE (stmt) == PHI_NODE)
{
- /* 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;
+ 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);
+ if (TREE_CODE (stmt) != PHI_NODE)
+ {
+ tree rhs;
- rhs = get_rhs (stmt);
- if (TREE_CODE (rhs) == ADDR_EXPR)
- recompute_tree_invariant_for_addr_expr (rhs);
+ fold_stmt_inplace (stmt);
+ rhs = get_rhs (stmt);
+ if (TREE_CODE (rhs) == ADDR_EXPR)
+ recompute_tree_invariant_for_addr_expr (rhs);
- maybe_clean_or_replace_eh_stmt (stmt, stmt);
- mark_new_vars_to_rename (stmt);
+ maybe_clean_or_replace_eh_stmt (stmt, stmt);
+ mark_new_vars_to_rename (stmt);
+ }
}
- VEC_free (tree, heap, stmts);
+ gcc_assert (num_imm_uses (name) == 0);
/* Also update the trees stored in loop structures. */
if (current_loops)
}
else
{
- set_bb_for_stmt (bsi_stmt (bsi), a);
+ change_bb_for_stmt (bsi_stmt (bsi), a);
bsi_next (&bsi);
}
}
reached by a complex edge, if there is one. Else, return BB. We use
this in optimizations that use post-dominators for their heuristics,
to catch the cases in C++ where function calls are involved. */
-
+
basic_block
-single_noncomplex_succ (basic_block bb)
+single_noncomplex_succ (basic_block bb)
{
edge e0, e1;
if (EDGE_COUNT (bb->succs) != 2)
return bb;
-
+
e0 = EDGE_SUCC (bb, 0);
e1 = EDGE_SUCC (bb, 1);
if (e0->flags & EDGE_COMPLEX)
return e1->dest;
if (e1->flags & EDGE_COMPLEX)
return e0->dest;
-
+
return bb;
-}
-
+}
/* Walk the function tree removing unnecessary statements.
/* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
decl. This allows us to eliminate redundant or useless
- calls to "const" functions.
+ calls to "const" functions.
Gimplifier already does the same operation, but we may notice functions
being const and pure once their calls has been gimplified, so we need
tsi_delink (&i);
continue;
}
-
+
remove_useless_stmts_1 (tsi_stmt_ptr (i), data);
t = tsi_stmt (i);
}
-struct tree_opt_pass pass_remove_useless_stmts =
+struct tree_opt_pass pass_remove_useless_stmts =
{
"useless", /* name */
NULL, /* gate */
DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)) = 0;
FORCED_LABEL (LABEL_EXPR_LABEL (stmt)) = 1;
}
-
+
new_bb = bb->prev_bb;
new_bsi = bsi_start (new_bb);
bsi_remove (&i, false);
edge true_edge, false_edge;
extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
-
+
gcc_assert (TREE_CODE (val) == INTEGER_CST);
return (zero_p (val) ? false_edge : true_edge);
}
{
debug_tree_bb (BASIC_BLOCK (n));
return BASIC_BLOCK (n);
-}
+}
/* Dump the CFG on stderr.
FLAGS are the same used by the tree dumping functions
- (see TDF_* in tree.h). */
+ (see TDF_* in tree-pass.h). */
void
debug_tree_cfg (int flags)
}
-/* Checks whether EXPR is a simple local goto. */
+/* Return true if T is a simple local goto. */
bool
-simple_goto_p (tree expr)
+simple_goto_p (tree t)
{
- return (TREE_CODE (expr) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL);
+ return (TREE_CODE (t) == GOTO_EXPR
+ && TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL);
+}
+
+
+/* Return true if T can make an abnormal transfer of control flow.
+ Transfers of control flow associated with EH are excluded. */
+
+bool
+tree_can_make_abnormal_goto (tree t)
+{
+ if (computed_goto_p (t))
+ return true;
+ if (TREE_CODE (t) == MODIFY_EXPR)
+ t = TREE_OPERAND (t, 1);
+ if (TREE_CODE (t) == WITH_SIZE_EXPR)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == CALL_EXPR)
+ return TREE_SIDE_EFFECTS (t) && current_function_has_nonlocal_label;
+ return false;
}
}
}
+/* Faster version of set_bb_for_stmt that assume that statement is being moved
+ from one basic block to another.
+ For BB splitting we can run into quadratic case, so performance is quite
+ important and knowing that the tables are big enough, change_bb_for_stmt
+ can inline as leaf function. */
+static inline void
+change_bb_for_stmt (tree t, basic_block bb)
+{
+ get_stmt_ann (t)->bb = bb;
+ if (TREE_CODE (t) == LABEL_EXPR)
+ VEC_replace (basic_block, label_to_block_map,
+ LABEL_DECL_UID (LABEL_EXPR_LABEL (t)), bb);
+}
+
/* Finds iterator for STMT. */
extern block_stmt_iterator
/* Remove the statement pointed to by iterator I. The iterator is updated
- to the next statement.
+ to the next statement.
When REMOVE_EH_INFO is true we remove the statement pointed to by
iterator I from the EH tables. Otherwise we do not modify the EH
/* Move the statement at FROM so it comes right after the statement at TO. */
-void
+void
bsi_move_after (block_stmt_iterator *from, block_stmt_iterator *to)
{
tree stmt = bsi_stmt (*from);
bsi_remove (from, false);
bsi_insert_after (to, stmt, BSI_SAME_STMT);
-}
+}
/* Move the statement at FROM so it comes right before the statement at TO. */
-void
+void
bsi_move_before (block_stmt_iterator *from, block_stmt_iterator *to)
{
tree stmt = bsi_stmt (*from);
bsi_move_to_bb_end (block_stmt_iterator *from, basic_block bb)
{
block_stmt_iterator last = bsi_last (bb);
-
+
/* Have to check bsi_end_p because it could be an empty block. */
if (!bsi_end_p (last) && is_ctrl_stmt (bsi_stmt (last)))
bsi_move_before (from, &last);
/* Replace the contents of the statement pointed to by iterator BSI
with STMT. If UPDATE_EH_INFO is true, the exception handling
information of the original statement is moved to the new statement. */
-
void
bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool update_eh_info)
restart:
/* If the destination has one predecessor which has no PHI nodes,
- insert there. Except for the exit block.
+ insert there. Except for the exit block.
The requirement for no PHI nodes could be relaxed. Basically we
would have to examine the PHIs to prove that none of them used
if (!PENDING_STMT (old_edge))
return;
-
+
for (var = PENDING_STMT (old_edge), phi = phi_nodes (new_edge->dest);
var && phi;
var = TREE_CHAIN (var), phi = PHI_CHAIN (phi))
PENDING_STMT (old_edge) = NULL;
}
-/* Returns the basic block after that the new basic block created
+/* Returns the basic block after which the new basic block created
by splitting edge EDGE_IN should be placed. Tries to keep the new block
near its "logical" location. This is of most help to humans looking
at debugging dumps. */
static basic_block
tree_split_edge (edge edge_in)
{
- basic_block new_bb, after_bb, dest, src;
+ basic_block new_bb, after_bb, dest;
edge new_edge, e;
/* Abnormal edges cannot be split. */
gcc_assert (!(edge_in->flags & EDGE_ABNORMAL));
- src = edge_in->src;
dest = edge_in->dest;
after_bb = split_edge_bb_loc (edge_in);
if (TYPE_P (t))
*walk_subtrees = 0;
-
+
/* Check operand N for being valid GIMPLE and give error MSG if not. */
#define CHECK_OP(N, MSG) \
do { if (!is_gimple_val (TREE_OPERAND (t, N))) \
case NOP_EXPR:
case CONVERT_EXPR:
case FIX_TRUNC_EXPR:
- case FIX_CEIL_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
case FLOAT_EXPR:
case NEGATE_EXPR:
case ABS_EXPR:
}
}
+ if (TREE_CODE (stmt) != COND_EXPR)
+ {
+ /* Verify that there are no edges with EDGE_TRUE/FALSE_FLAG set
+ after anything else but if statement. */
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
+ {
+ error ("true/false edge after a non-COND_EXPR in bb %d",
+ bb->index);
+ err = 1;
+ }
+ }
+
switch (TREE_CODE (stmt))
{
case COND_EXPR:
if (simple_goto_p (stmt))
{
error ("explicit goto at end of bb %d", bb->index);
- err = 1;
+ err = 1;
}
else
{
- /* FIXME. We should double check that the labels in the
+ /* FIXME. We should double check that the labels in the
destination blocks have their address taken. */
FOR_EACH_EDGE (e, ei, bb->succs)
if ((e->flags & (EDGE_FALLTHRU | EDGE_TRUE_VALUE
edge ret;
tree label, stmt;
- if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
+ if (e->flags & EDGE_ABNORMAL)
return NULL;
- if (e->src != ENTRY_BLOCK_PTR
+ if (e->src != ENTRY_BLOCK_PTR
&& (ret = tree_try_redirect_by_replacing_jump (e, dest)))
return ret;
static basic_block
tree_split_block (basic_block bb, void *stmt)
{
- block_stmt_iterator bsi, bsi_tgt;
+ block_stmt_iterator bsi;
+ tree_stmt_iterator tsi_tgt;
tree act;
basic_block new_bb;
edge e;
}
}
- bsi_tgt = bsi_start (new_bb);
- while (!bsi_end_p (bsi))
- {
- act = bsi_stmt (bsi);
- bsi_remove (&bsi, false);
- bsi_insert_after (&bsi_tgt, act, BSI_NEW_STMT);
- }
+ if (bsi_end_p (bsi))
+ return new_bb;
+
+ /* Split the statement list - avoid re-creating new containers as this
+ brings ugly quadratic memory consumption in the inliner.
+ (We are still quadratic since we need to update stmt BB pointers,
+ sadly.) */
+ new_bb->stmt_list = tsi_split_statement_list_before (&bsi.tsi);
+ for (tsi_tgt = tsi_start (new_bb->stmt_list);
+ !tsi_end_p (tsi_tgt); tsi_next (&tsi_tgt))
+ change_bb_for_stmt (tsi_stmt (tsi_tgt), new_bb);
return new_bb;
}
edge e, e_copy;
edge_iterator ei;
tree phi, phi_copy, phi_next, def;
-
+
bb = get_bb_original (bb_copy);
FOR_EACH_EDGE (e_copy, ei, bb_copy->succs)
total_count - entry_count,
total_count);
scale_bbs_frequencies_gcov_type (region_copy, n_region, entry_count,
- total_count);
+ total_count);
}
else
{
original array of blocks and placed in DEST_FN's array of blocks.
If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is
updated to reflect the moved edges.
-
+
On exit, local variables that need to be removed from
CFUN->UNEXPANDED_VAR_LIST will have been added to VARS_TO_REMOVE. */
basic_block bb, int region)
{
block_stmt_iterator si;
-
+
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{
tree stmt = bsi_stmt (si);
int stmt_region;
- stmt_region = lookup_stmt_eh_region_fn (src_cfun, stmt);
- if (stmt_region > 0
- && (region < 0 || eh_region_outer_p (src_cfun, stmt_region, region)))
- region = stmt_region;
+ if (TREE_CODE (stmt) == RESX_EXPR)
+ stmt_region = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0));
+ else
+ stmt_region = lookup_stmt_eh_region_fn (src_cfun, stmt);
+ if (stmt_region > 0)
+ {
+ if (region < 0)
+ region = stmt_region;
+ else if (stmt_region != region)
+ {
+ region = eh_region_outermost (src_cfun, stmt_region, region);
+ gcc_assert (region != -1);
+ }
+ }
}
return region;
/* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
region. */
gcc_assert (entry_bb != exit_bb
- && dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb));
+ && (!exit_bb
+ || dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb)));
bbs = NULL;
VEC_safe_push (basic_block, heap, bbs, entry_bb);
remove_edge (e);
}
- num_exit_edges = EDGE_COUNT (exit_bb->succs);
- exit_succ = (basic_block *) xcalloc (num_exit_edges, sizeof (basic_block));
- exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int));
- i = 0;
- for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;)
+ if (exit_bb)
{
- exit_flag[i] = e->flags;
- exit_succ[i++] = e->dest;
- remove_edge (e);
+ num_exit_edges = EDGE_COUNT (exit_bb->succs);
+ exit_succ = (basic_block *) xcalloc (num_exit_edges,
+ sizeof (basic_block));
+ exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int));
+ i = 0;
+ for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;)
+ {
+ exit_flag[i] = e->flags;
+ exit_succ[i++] = e->dest;
+ remove_edge (e);
+ }
+ }
+ else
+ {
+ num_exit_edges = 0;
+ exit_succ = NULL;
+ exit_flag = NULL;
}
/* Switch context to the child function to initialize DEST_FN's CFG. */
these helpers. */
cfun = dest_cfun;
make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU);
- make_edge (exit_bb, EXIT_BLOCK_PTR, 0);
+ if (exit_bb)
+ make_edge (exit_bb, EXIT_BLOCK_PTR, 0);
cfun = saved_cfun;
/* Back in the original function, the SESE region has disappeared,
for (i = 0; i < num_exit_edges; i++)
make_edge (bb, exit_succ[i], exit_flag[i]);
- free (exit_flag);
+ if (exit_bb)
+ {
+ free (exit_flag);
+ free (exit_succ);
+ }
free (entry_flag);
free (entry_pred);
- free (exit_succ);
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
VEC_free (basic_block, heap, bbs);
basic_block bb;
tree chain;
struct function *saved_cfun;
-
+
fprintf (file, "%s (", lang_hooks.decl_printable_name (fn, 2));
arg = DECL_ARGUMENTS (fn);
FOR_EACH_BB (bb)
dump_generic_bb (file, bb, 2, flags);
-
+
fprintf (file, "}\n");
check_bb_profile (EXIT_BLOCK_PTR, file);
}
{
char *s_indent;
basic_block bb;
-
+
if (loop == NULL)
return;
/* Print the loop's header. */
fprintf (file, "%sloop_%d\n", s_indent, loop->num);
-
+
/* Print the loop's body. */
fprintf (file, "%s{\n", s_indent);
FOR_EACH_BB (bb)
fprintf (file, "}, succs = {");
print_succ_bbs (file, bb);
fprintf (file, "})\n");
-
+
/* Print the basic_block's body. */
fprintf (file, "%s {\n", s_indent);
tree_dump_bb (bb, file, indent + 4);
fprintf (file, "%s }\n", s_indent);
}
-
+
print_loop (file, loop->inner, indent + 2);
fprintf (file, "%s}\n", s_indent);
print_loop (file, loop->next, indent);
/* Follow a CFG edge from the entry point of the program, and on entry
of a loop, pretty print the loop structure on FILE. */
-void
+void
print_loop_ir (FILE *file)
{
basic_block bb;
-
+
bb = BASIC_BLOCK (NUM_FIXED_BLOCKS);
if (bb && bb->loop_father)
print_loop (file, bb->loop_father, 0);
/* Debugging loops structure at tree level. */
-void
+void
debug_loop_ir (void)
{
print_loop_ir (stderr);
return blocks_split;
}
+/* Purge dead abnormal call edges from basic block BB. */
+
+bool
+tree_purge_dead_abnormal_call_edges (basic_block bb)
+{
+ bool changed = tree_purge_dead_eh_edges (bb);
+
+ if (current_function_has_nonlocal_label)
+ {
+ tree stmt = last_stmt (bb);
+ edge_iterator ei;
+ edge e;
+
+ if (!(stmt && tree_can_make_abnormal_goto (stmt)))
+ for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+ {
+ if (e->flags & EDGE_ABNORMAL)
+ {
+ remove_edge (e);
+ changed = true;
+ }
+ else
+ ei_next (&ei);
+ }
+
+ /* See tree_purge_dead_eh_edges below. */
+ if (changed)
+ free_dominance_info (CDI_DOMINATORS);
+ }
+
+ return changed;
+}
+
+/* Purge dead EH edges from basic block BB. */
+
bool
tree_purge_dead_eh_edges (basic_block bb)
{
of 'first'. Both of them are dominated by 'new_head' basic block. When
'new_head' was created by 'second's incoming edge it received phi arguments
on the edge by split_edge(). Later, additional edge 'e' was created to
- connect 'new_head' and 'first'. Now this routine adds phi args on this
- additional edge 'e' that new_head to second edge received as part of edge
+ connect 'new_head' and 'first'. Now this routine adds phi args on this
+ additional edge 'e' that new_head to second edge received as part of edge
splitting.
*/
/* Browse all 'second' basic block phi nodes and add phi args to
edge 'e' for 'first' head. PHI args are always in correct order. */
- for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
- phi2 && phi1;
+ for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
+ phi2 && phi1;
phi2 = PHI_CHAIN (phi2), phi1 = PHI_CHAIN (phi1))
{
tree def = PHI_ARG_DEF (phi2, e2->dest_idx);
}
}
-/* Adds a if else statement to COND_BB with condition COND_EXPR.
- SECOND_HEAD is the destination of the THEN and FIRST_HEAD is
+/* Adds a if else statement to COND_BB with condition COND_EXPR.
+ SECOND_HEAD is the destination of the THEN and FIRST_HEAD is
the destination of the ELSE part. */
static void
tree_lv_add_condition_to_bb (basic_block first_head, basic_block second_head,
goto2 = build1 (GOTO_EXPR, void_type_node, tree_block_label (second_head));
new_cond_expr = build3 (COND_EXPR, void_type_node, cond_expr, goto1, goto2);
- /* Add new cond in cond_bb. */
- bsi = bsi_start (cond_bb);
+ /* Add new cond in cond_bb. */
+ bsi = bsi_start (cond_bb);
bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT);
/* Adjust edges appropriately to connect new head with first head
as well as second head. */
tree_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
tree_lv_adjust_loop_header_phi, /* lv_adjust_loop_header_phi*/
extract_true_false_edges_from_block, /* extract_cond_bb_edges */
- flush_pending_stmts /* flush_pending_stmts */
+ flush_pending_stmts /* flush_pending_stmts */
};
return 0;
}
-struct tree_opt_pass pass_split_crit_edges =
+struct tree_opt_pass pass_split_crit_edges =
{
"crited", /* name */
NULL, /* gate */
TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
+ if (in_ssa_p)
+ mark_new_vars_to_rename (new_stmt);
return t;
}