/* Control flow graph manipulation code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
insert_insn_on_edge, commit_edge_insertions
- CFG updating after insn simplification
purge_dead_edges, purge_all_dead_edges
+ - CFG fixing after coarse manipulation
+ fixup_abnormal_edges
Functions not supposed for generic use:
- Infrastructure to determine quickly basic block for insn
#include "cfglayout.h"
#include "expr.h"
#include "target.h"
+#include "common/common-target.h"
#include "cfgloop.h"
#include "ggc.h"
#include "tree-pass.h"
/* When expanding this BB might actually contain multiple
jumps (i.e. not yet split by find_many_sub_basic_blocks).
Redirect all of those that match our label. */
- for (insn = BB_HEAD (src); insn != NEXT_INSN (BB_END (src));
- insn = NEXT_INSN (insn))
+ FOR_BB_INSNS (src, insn)
if (JUMP_P (insn) && !patch_jump_insn (insn, old_label, target))
return NULL;
BB_COPY_PARTITION (jump_block, e->src);
if (flag_reorder_blocks_and_partition
- && targetm.have_named_sections
+ && targetm_common.have_named_sections
&& JUMP_P (BB_END (jump_block))
&& !any_condjump_p (BB_END (jump_block))
&& (EDGE_SUCC (jump_block, 0)->flags & EDGE_CROSSING))
(and possibly create new basic block) to make edge non-fallthru.
Return newly created BB or NULL if none. */
-basic_block
-force_nonfallthru (edge e)
+static basic_block
+rtl_force_nonfallthru (edge e)
{
return force_nonfallthru_and_redirect (e, e->dest);
}
commit_one_edge_insertion (edge e)
{
rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
- basic_block bb = NULL;
+ basic_block bb;
/* Pull the insns off the edge now since the edge might go away. */
insns = e->insns.r;
e->insns.r = NULL_RTX;
- if (!before && !after)
- {
- /* Figure out where to put these things. If the destination has
- one predecessor, insert there. Except for the exit block. */
- if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
- {
- bb = e->dest;
-
- /* Get the location correct wrt a code label, and "nice" wrt
- a basic block note, and before everything else. */
- tmp = BB_HEAD (bb);
- if (LABEL_P (tmp))
- tmp = NEXT_INSN (tmp);
- if (NOTE_INSN_BASIC_BLOCK_P (tmp))
- tmp = NEXT_INSN (tmp);
- if (tmp == BB_HEAD (bb))
- before = tmp;
- else if (tmp)
- after = PREV_INSN (tmp);
- else
- after = get_last_insn ();
- }
-
- /* If the source has one successor and the edge is not abnormal,
- insert there. Except for the entry block. */
- else if ((e->flags & EDGE_ABNORMAL) == 0
- && single_succ_p (e->src)
- && e->src != ENTRY_BLOCK_PTR)
- {
- bb = e->src;
+ /* Figure out where to put these insns. If the destination has
+ one predecessor, insert there. Except for the exit block. */
+ if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
+ {
+ bb = e->dest;
+
+ /* Get the location correct wrt a code label, and "nice" wrt
+ a basic block note, and before everything else. */
+ tmp = BB_HEAD (bb);
+ if (LABEL_P (tmp))
+ tmp = NEXT_INSN (tmp);
+ if (NOTE_INSN_BASIC_BLOCK_P (tmp))
+ tmp = NEXT_INSN (tmp);
+ if (tmp == BB_HEAD (bb))
+ before = tmp;
+ else if (tmp)
+ after = PREV_INSN (tmp);
+ else
+ after = get_last_insn ();
+ }
- /* It is possible to have a non-simple jump here. Consider a target
- where some forms of unconditional jumps clobber a register. This
- happens on the fr30 for example.
+ /* If the source has one successor and the edge is not abnormal,
+ insert there. Except for the entry block. */
+ else if ((e->flags & EDGE_ABNORMAL) == 0
+ && single_succ_p (e->src)
+ && e->src != ENTRY_BLOCK_PTR)
+ {
+ bb = e->src;
- We know this block has a single successor, so we can just emit
- the queued insns before the jump. */
- if (JUMP_P (BB_END (bb)))
- before = BB_END (bb);
- else
- {
- /* We'd better be fallthru, or we've lost track of
- what's what. */
- gcc_assert (e->flags & EDGE_FALLTHRU);
+ /* It is possible to have a non-simple jump here. Consider a target
+ where some forms of unconditional jumps clobber a register. This
+ happens on the fr30 for example.
- after = BB_END (bb);
- }
- }
- /* Otherwise we must split the edge. */
+ We know this block has a single successor, so we can just emit
+ the queued insns before the jump. */
+ if (JUMP_P (BB_END (bb)))
+ before = BB_END (bb);
else
{
- bb = split_edge (e);
- after = BB_END (bb);
+ /* We'd better be fallthru, or we've lost track of what's what. */
+ gcc_assert (e->flags & EDGE_FALLTHRU);
- if (flag_reorder_blocks_and_partition
- && targetm.have_named_sections
- && e->src != ENTRY_BLOCK_PTR
- && BB_PARTITION (e->src) == BB_COLD_PARTITION
- && !(e->flags & EDGE_CROSSING)
- && JUMP_P (after)
- && !any_condjump_p (after)
- && (single_succ_edge (bb)->flags & EDGE_CROSSING))
- add_reg_note (after, REG_CROSSING_JUMP, NULL_RTX);
+ after = BB_END (bb);
}
}
- /* Now that we've found the spot, do the insertion. */
+ /* Otherwise we must split the edge. */
+ else
+ {
+ bb = split_edge (e);
+ after = BB_END (bb);
+ if (flag_reorder_blocks_and_partition
+ && targetm_common.have_named_sections
+ && e->src != ENTRY_BLOCK_PTR
+ && BB_PARTITION (e->src) == BB_COLD_PARTITION
+ && !(e->flags & EDGE_CROSSING)
+ && JUMP_P (after)
+ && !any_condjump_p (after)
+ && (single_succ_edge (bb)->flags & EDGE_CROSSING))
+ add_reg_note (after, REG_CROSSING_JUMP, NULL_RTX);
+ }
+
+ /* Now that we've found the spot, do the insertion. */
if (before)
{
emit_insn_before_noloc (insns, before, bb);
}
else
gcc_assert (!JUMP_P (last));
-
- /* Mark the basic block for find_many_sub_basic_blocks. */
- if (current_ir_type () != IR_RTL_CFGLAYOUT)
- bb->aux = &bb->aux;
}
/* Update the CFG for all queued instructions. */
commit_edge_insertions (void)
{
basic_block bb;
- sbitmap blocks;
- bool changed = false;
#ifdef ENABLE_CHECKING
verify_flow_info ();
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->insns.r)
- {
- changed = true;
- commit_one_edge_insertion (e);
- }
+ commit_one_edge_insertion (e);
}
-
- if (!changed)
- return;
-
- /* In the old rtl CFG API, it was OK to insert control flow on an
- edge, apparently? In cfglayout mode, this will *not* work, and
- the caller is responsible for making sure that control flow is
- valid at all times. */
- if (current_ir_type () == IR_RTL_CFGLAYOUT)
- return;
-
- blocks = sbitmap_alloc (last_basic_block);
- sbitmap_zero (blocks);
- FOR_EACH_BB (bb)
- if (bb->aux)
- {
- SET_BIT (blocks, bb->index);
- /* Check for forgotten bb->aux values before commit_edge_insertions
- call. */
- gcc_assert (bb->aux == &bb->aux);
- bb->aux = NULL;
- }
- find_many_sub_basic_blocks (blocks);
- sbitmap_free (blocks);
}
\f
return purged;
}
+/* This is used by a few passes that emit some instructions after abnormal
+ calls, moving the basic block's end, while they in fact do want to emit
+ them on the fallthru edge. Look for abnormal call edges, find backward
+ the call in the block and insert the instructions on the edge instead.
+
+ Similarly, handle instructions throwing exceptions internally.
+
+ Return true when instructions have been found and inserted on edges. */
+
+bool
+fixup_abnormal_edges (void)
+{
+ bool inserted = false;
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ edge e;
+ edge_iterator ei;
+
+ /* Look for cases we are interested in - calls or instructions causing
+ exceptions. */
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if ((e->flags & EDGE_ABNORMAL_CALL)
+ || ((e->flags & (EDGE_ABNORMAL | EDGE_EH))
+ == (EDGE_ABNORMAL | EDGE_EH)))
+ break;
+
+ if (e && !CALL_P (BB_END (bb)) && !can_throw_internal (BB_END (bb)))
+ {
+ rtx insn;
+
+ /* Get past the new insns generated. Allow notes, as the insns
+ may be already deleted. */
+ insn = BB_END (bb);
+ while ((NONJUMP_INSN_P (insn) || NOTE_P (insn))
+ && !can_throw_internal (insn)
+ && insn != BB_HEAD (bb))
+ insn = PREV_INSN (insn);
+
+ if (CALL_P (insn) || can_throw_internal (insn))
+ {
+ rtx stop, next;
+
+ e = find_fallthru_edge (bb->succs);
+
+ stop = NEXT_INSN (BB_END (bb));
+ BB_END (bb) = insn;
+
+ for (insn = NEXT_INSN (insn); insn != stop; insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (INSN_P (insn))
+ {
+ delete_insn (insn);
+
+ /* Sometimes there's still the return value USE.
+ If it's placed after a trapping call (i.e. that
+ call is the last insn anyway), we have no fallthru
+ edge. Simply delete this use and don't try to insert
+ on the non-existent edge. */
+ if (GET_CODE (PATTERN (insn)) != USE)
+ {
+ /* We're not deleting it, we're moving it. */
+ INSN_DELETED_P (insn) = 0;
+ PREV_INSN (insn) = NULL_RTX;
+ NEXT_INSN (insn) = NULL_RTX;
+
+ insert_insn_on_edge (insn, e);
+ inserted = true;
+ }
+ }
+ else if (!BARRIER_P (insn))
+ set_block_for_insn (insn, NULL);
+ }
+ }
+
+ /* It may be that we don't find any trapping insn. In this
+ case we discovered quite late that the insn that had been
+ marked as can_throw_internal in fact couldn't trap at all.
+ So we should in fact delete the EH edges out of the block. */
+ else
+ purge_dead_edges (bb);
+ }
+ }
+
+ return inserted;
+}
+
/* Same as split_block but update cfg_layout structures. */
static basic_block
e->flags &= ~EDGE_FALLTHRU;
redirected = redirect_branch_edge (e, dest);
gcc_assert (redirected);
- e->flags |= EDGE_FALLTHRU;
- df_set_bb_dirty (e->src);
- return e;
+ redirected->flags |= EDGE_FALLTHRU;
+ df_set_bb_dirty (redirected->src);
+ return redirected;
}
/* In case we are redirecting fallthru edge to the branch edge
of conditional jump, remove it. */
&& onlyjump_p (BB_END (src)))
delete_insn (BB_END (src));
}
- ret = redirect_edge_succ_nodup (e, dest);
if (dump_file)
- fprintf (dump_file, "Fallthru edge %i->%i redirected to %i\n",
+ fprintf (dump_file, "Redirecting fallthru edge %i->%i to %i\n",
e->src->index, e->dest->index, dest->index);
+ ret = redirect_edge_succ_nodup (e, dest);
}
else
ret = redirect_branch_edge (e, dest);
rtl_split_edge,
rtl_make_forwarder_block,
rtl_tidy_fallthru_edge,
+ rtl_force_nonfallthru,
rtl_block_ends_with_call_p,
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,
cfg_layout_duplicate_bb,
cfg_layout_split_edge,
rtl_make_forwarder_block,
- NULL,
+ NULL, /* tidy_fallthru_edge */
+ rtl_force_nonfallthru,
rtl_block_ends_with_call_p,
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,