/* Control flow graph manipulation code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
static bool back_edge_of_syntactic_loop_p (basic_block, basic_block);
basic_block force_nonfallthru_and_redirect (edge, basic_block);
static basic_block rtl_split_edge (edge);
+static bool rtl_move_block_after (basic_block, basic_block);
static int rtl_verify_flow_info (void);
-static edge cfg_layout_split_block (basic_block, void *);
+static basic_block cfg_layout_split_block (basic_block, void *);
static bool cfg_layout_redirect_edge_and_branch (edge, basic_block);
static basic_block cfg_layout_redirect_edge_and_branch_force (edge, basic_block);
static void cfg_layout_delete_block (basic_block);
static void rtl_delete_block (basic_block);
static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
static bool rtl_redirect_edge_and_branch (edge, basic_block);
-static edge rtl_split_block (basic_block, void *);
-static void rtl_dump_bb (basic_block, FILE *);
+static basic_block rtl_split_block (basic_block, void *);
+static void rtl_dump_bb (basic_block, FILE *, int);
static int rtl_verify_flow_info_1 (void);
static void mark_killed_regs (rtx, rtx, void *);
+static void rtl_make_forwarder_block (edge);
\f
/* Return true if NOTE is not one of the ones that must be kept paired,
so that we may simply delete it. */
basic_block bb;
/* Place the new block just after the end. */
- VARRAY_GROW (basic_block_info, last_basic_block+1);
+ VARRAY_GROW (basic_block_info, last_basic_block + 1);
n_basic_blocks++;
/* Selectively delete the entire chain. */
BB_HEAD (b) = NULL;
delete_insn_chain (insn, end);
-
- /* Remove the edges into and out of this block. Note that there may
- indeed be edges in, if we are removing an unreachable loop. */
- while (b->pred != NULL)
- remove_edge (b->pred);
- while (b->succ != NULL)
- remove_edge (b->succ);
-
- b->pred = NULL;
- b->succ = NULL;
-
- /* Remove the basic block from the array. */
- expunge_block (b);
}
\f
/* Records the basic block struct in BLOCK_FOR_INSN for every insn. */
}
}
\f
-/* Split a block BB after insn INSN creating a new fallthru edge.
- Return the new edge. Note that to keep other parts of the compiler happy,
- this function renumbers all the basic blocks so that the new
- one has a number one greater than the block split. */
+/* Creates a new basic block just after basic block B by splitting
+ everything after specified instruction I. */
-static edge
+static basic_block
rtl_split_block (basic_block bb, void *insnp)
{
basic_block new_bb;
- edge new_edge;
- edge e;
rtx insn = insnp;
+ edge e;
+
+ if (!insn)
+ {
+ insn = first_insn_after_basic_block_note (bb);
- /* There is no point splitting the block after its end. */
- if (BB_END (bb) == insn)
- return 0;
+ if (insn)
+ insn = PREV_INSN (insn);
+ else
+ insn = get_last_insn ();
+ }
+
+ /* We probably should check type of the insn so that we do not create
+ inconsistent cfg. It is checked in verify_flow_info anyway, so do not
+ bother. */
+ if (insn == BB_END (bb))
+ emit_note_after (NOTE_INSN_DELETED, insn);
/* Create the new basic block. */
new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
- new_bb->count = bb->count;
- new_bb->frequency = bb->frequency;
- new_bb->loop_depth = bb->loop_depth;
BB_END (bb) = insn;
/* Redirect the outgoing edges. */
for (e = new_bb->succ; e; e = e->succ_next)
e->src = new_bb;
- new_edge = make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
-
if (bb->global_live_at_start)
{
new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
#endif
}
- return new_edge;
-}
-
-/* Assume that the code of basic block B has been merged into A.
- Do corresponding CFG updates: redirect edges accordingly etc. */
-static void
-update_cfg_after_block_merging (basic_block a, basic_block b)
-{
- edge e;
-
- /* Normally there should only be one successor of A and that is B, but
- partway though the merge of blocks for conditional_execution we'll
- be merging a TEST block with THEN and ELSE successors. Free the
- whole lot of them and hope the caller knows what they're doing. */
- while (a->succ)
- remove_edge (a->succ);
-
- /* Adjust the edges out of B for the new owner. */
- for (e = b->succ; e; e = e->succ_next)
- e->src = a;
- a->succ = b->succ;
- a->flags |= b->flags;
-
- /* B hasn't quite yet ceased to exist. Attempt to prevent mishap. */
- b->pred = b->succ = NULL;
- a->global_live_at_end = b->global_live_at_end;
-
- expunge_block (b);
+ return new_bb;
}
/* Blocks A and B are to be merged into a single block A. The insns
else if (GET_CODE (NEXT_INSN (a_end)) == BARRIER)
del_first = NEXT_INSN (a_end);
- update_cfg_after_block_merging (a, b);
-
/* Delete everything marked above as well as crap that might be
hanging out between the two blocks. */
+ BB_HEAD (b) = NULL;
delete_insn_chain (del_first, del_last);
/* Reassociate the insns of B with A. */
/* If the jump insn has side effects,
we can't kill the edge. */
&& (GET_CODE (BB_END (a)) != JUMP_INSN
- || (flow2_completed
+ || (reload_completed
? simplejump_p (BB_END (a)) : onlyjump_p (BB_END (a)))));
}
\f
apply only if all edges now point to the same block. The parameters and
return values are equivalent to redirect_edge_and_branch. */
-static bool
+bool
try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
{
basic_block src = e->src;
if (tmp || !onlyjump_p (insn))
return false;
- if ((!optimize || flow2_completed) && tablejump_p (insn, NULL, NULL))
+ if ((!optimize || reload_completed) && tablejump_p (insn, NULL, NULL))
return false;
/* Avoid removing branch with side effects. */
if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
return false;
+ if (e->dest == target)
+ return true;
+
if (try_redirect_by_replacing_jump (e, target, false))
return true;
- /* Do this fast path late, as we want above code to simplify for cases
- where called on single edge leaving basic block containing nontrivial
- jump insn. */
- else if (e->dest == target)
- return false;
- else if (!redirect_branch_edge (e, target))
+ if (!redirect_branch_edge (e, target))
return false;
return true;
/* The given edge should potentially be a fallthru edge. If that is in
fact true, delete the jump and barriers that are in the way. */
-void
-tidy_fallthru_edge (edge e, basic_block b, basic_block c)
+static void
+rtl_tidy_fallthru_edge (edge e)
{
rtx q;
+ basic_block b = e->src, c = b->next_bb;
+
+ /* If the jump insn has side effects, we can't tidy the edge. */
+ if (GET_CODE (BB_END (b)) == JUMP_INSN
+ && !onlyjump_p (BB_END (b)))
+ return;
/* ??? In a late-running flow pass, other folks may have deleted basic
blocks by nopping out blocks, leaving multiple BARRIERs between here
e->flags |= EDGE_FALLTHRU;
}
-
-/* Fix up edges that now fall through, or rather should now fall through
- but previously required a jump around now deleted blocks. Simplify
- the search by only examining blocks numerically adjacent, since this
- is how find_basic_blocks created them. */
-
-void
-tidy_fallthru_edges (void)
-{
- basic_block b, c;
-
- if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
- return;
-
- FOR_BB_BETWEEN (b, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR->prev_bb, next_bb)
- {
- edge s;
-
- c = b->next_bb;
-
- /* We care about simple conditional or unconditional jumps with
- a single successor.
-
- If we had a conditional branch to the next instruction when
- find_basic_blocks was called, then there will only be one
- out edge for the block which ended with the conditional
- branch (since we do not create duplicate edges).
-
- Furthermore, the edge will be marked as a fallthru because we
- merge the flags for the duplicate edges. So we do not want to
- check that the edge is not a FALLTHRU edge. */
-
- if ((s = b->succ) != NULL
- && ! (s->flags & EDGE_COMPLEX)
- && s->succ_next == NULL
- && s->dest == c
- /* If the jump insn has side effects, we can't tidy the edge. */
- && (GET_CODE (BB_END (b)) != JUMP_INSN
- || onlyjump_p (BB_END (b))))
- tidy_fallthru_edge (s, b, c);
- }
-}
\f
/* Helper function for split_edge. Return true in case edge BB2 to BB1
is back edge of syntactic loop. */
return count >= 0;
}
+/* Should move basic block BB after basic block AFTER. NIY. */
+
+static bool
+rtl_move_block_after (basic_block bb ATTRIBUTE_UNUSED,
+ basic_block after ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
/* Split a (typically critical) edge. Return the new block.
Abort on abnormal edges.
before = NULL_RTX;
bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
- bb->count = edge_in->count;
- bb->frequency = EDGE_FREQUENCY (edge_in);
/* ??? This info is likely going to be out of date very soon. */
if (edge_in->dest->global_live_at_start)
SET_REGNO_REG_SET (killed, regno);
else
{
- for (i = 0; i < (int) HARD_REGNO_NREGS (regno, GET_MODE (reg)); i++)
+ for (i = 0; i < (int) hard_regno_nregs[regno][GET_MODE (reg)]; i++)
SET_REGNO_REG_SET (killed, regno + i);
}
}
sbitmap_free (blocks);
}
\f
-/* Print out one basic block with live information at start and end. */
+/* Print out RTL-specific basic block information (live information
+ at start and end). */
static void
-rtl_dump_bb (basic_block bb, FILE *outf)
+rtl_dump_bb (basic_block bb, FILE *outf, int indent)
{
rtx insn;
rtx last;
+ char *s_indent;
+
+ s_indent = (char *) alloca ((size_t) indent + 1);
+ memset ((void *) s_indent, ' ', (size_t) indent);
+ s_indent[indent] = '\0';
- fputs (";; Registers live at start:", outf);
+ fprintf (outf, ";;%s Registers live at start: ", s_indent);
dump_regset (bb->global_live_at_start, outf);
putc ('\n', outf);
insn = NEXT_INSN (insn))
print_rtl_single (outf, insn);
- fputs (";; Registers live at end:", outf);
+ fprintf (outf, ";;%s Registers live at end: ", s_indent);
dump_regset (bb->global_live_at_end, outf);
putc ('\n', outf);
}
In future it can be extended check a lot of other stuff as well
(reachability of basic blocks, life information, etc. etc.). */
+
static int
rtl_verify_flow_info_1 (void)
{
}
/* Same as split_block but update cfg_layout structures. */
-static edge
+
+static basic_block
cfg_layout_split_block (basic_block bb, void *insnp)
{
rtx insn = insnp;
+ basic_block new_bb = rtl_split_block (bb, insn);
- edge fallthru = rtl_split_block (bb, insn);
+ new_bb->rbi->footer = bb->rbi->footer;
+ bb->rbi->footer = NULL;
- fallthru->dest->rbi->footer = fallthru->src->rbi->footer;
- fallthru->src->rbi->footer = NULL;
- return fallthru;
+ return new_bb;
}
if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
return false;
- if (e->src != ENTRY_BLOCK_PTR
- && try_redirect_by_replacing_jump (e, dest, true))
+ if (e->dest == dest)
return true;
- if (e->dest == dest)
+ if (e->src != ENTRY_BLOCK_PTR
+ && try_redirect_by_replacing_jump (e, dest, true))
return true;
if (e->src == ENTRY_BLOCK_PTR
return NULL;
}
-/* Same as flow_delete_block but update cfg_layout structures. */
+/* Same as delete_basic_block but update cfg_layout structures. */
+
static void
cfg_layout_delete_block (basic_block bb)
{
/* If the jump insn has side effects,
we can't kill the edge. */
&& (GET_CODE (BB_END (a)) != JUMP_INSN
- || (flow2_completed
+ || (reload_completed
? simplejump_p (BB_END (a)) : onlyjump_p (BB_END (a)))));
}
/* We should have fallthru edge in a, or we can do dummy redirection to get
it cleaned up. */
if (GET_CODE (BB_END (a)) == JUMP_INSN)
- redirect_edge_and_branch (a->succ, b);
+ try_redirect_by_replacing_jump (a->succ, b, true);
if (GET_CODE (BB_END (a)) == JUMP_INSN)
abort ();
if (rtl_dump_file)
fprintf (rtl_dump_file, "Merged blocks %d and %d.\n",
a->index, b->index);
-
- update_cfg_after_block_merging (a, b);
}
/* Split edge E. */
+
static basic_block
cfg_layout_split_edge (edge e)
{
? NEXT_INSN (BB_END (e->src)) : get_insns (),
NULL_RTX, e->src);
- new_bb->count = e->count;
- new_bb->frequency = EDGE_FREQUENCY (e);
-
new_e = make_edge (new_bb, e->dest, EDGE_FALLTHRU);
- new_e->probability = REG_BR_PROB_BASE;
- new_e->count = e->count;
redirect_edge_and_branch_force (e, new_bb);
return new_bb;
}
+/* Do postprocessing after making a forwarder block joined by edge FALLTHRU. */
+
+static void
+rtl_make_forwarder_block (edge fallthru ATTRIBUTE_UNUSED)
+{
+}
+
/* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = {
+ "rtl",
rtl_verify_flow_info,
rtl_dump_bb,
rtl_create_basic_block,
rtl_redirect_edge_and_branch_force,
rtl_delete_block,
rtl_split_block,
+ rtl_move_block_after,
rtl_can_merge_blocks, /* can_merge_blocks_p */
rtl_merge_blocks,
- rtl_split_edge
+ rtl_split_edge,
+ rtl_make_forwarder_block,
+ rtl_tidy_fallthru_edge
};
/* Implementation of CFG manipulation for cfg layout RTL, where
This representation will hopefully become the default one in future
version of the compiler. */
struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
+ "cfglayout mode",
rtl_verify_flow_info_1,
rtl_dump_bb,
cfg_layout_create_basic_block,
cfg_layout_redirect_edge_and_branch_force,
cfg_layout_delete_block,
cfg_layout_split_block,
+ rtl_move_block_after,
cfg_layout_can_merge_blocks_p,
cfg_layout_merge_blocks,
- cfg_layout_split_edge
+ cfg_layout_split_edge,
+ rtl_make_forwarder_block,
+ NULL
};