Makefile.in (cfghooks.o): Add TIMEVAR_H and toplev.h dependency.

* Makefile.in (cfghooks.o): Add TIMEVAR_H and toplev.h dependency.
	* basic-block.h (tidy_fallthru_edge, tidy_fallthru_edges, dump_bb,
	verify_flow_info): Declaration removed.
	* cfg.c (verify_flow_info, dump_bb): Moved to cfghooks.c.
	(debug_bb, debug_bb_n): Add argument to dump_bb call.
	* cfgcleanup.c (try_simplify_condjump, try_crossjump_to_edge,
	try_optimize_cfg, delete_unreachable_blocks): Use delete_basic_block
	instead of delete_block.
	* cfghooks.c: Include timevar.h and toplev.h.
	(cfg_hooks): Define here.
	(verify_flow_info, dump_bb): Moved from cfg.c.
	(redirect_edge_and_branch, redirect_edge_and_branch_force,
	split_block, split_block_after_labels, move_block_after,
	delete_basic_block, split_edge, create_basic_block,
	create_empty_bb, can_merge_blocks_p, merge_blocks,
	make_forwarder_block, tidy_fallthru_edge, tidy_fallthru_edges):
	New functions.
	* cfghooks.h (struct cfg_hooks): Added fields name,
	make_forwarder_block, tidy_fallthru_edge and
	move_block_after. Changed type of verify_flow_info, dump_bb,
	split_block fields. Renamed cfgh_split_edge and delete_block
	fields.
	(redirect_edge_and_branch, redirect_edge_and_branch_force,
	split_block, delete_block, split_edge, create_basic_block,
	can_merge_blocks_p, merge_blocks): Macros removed.
	(cfg_hooks): Do not export.
	(verify_flow_info, dump_bb, redirect_edge_and_branch,
	redirect_edge_and_branch_force, split_block, split_block_after_labels,
	move_block_after, delete_basic_block, split_edge, create_basic_block,
	create_empty_bb, can_merge_blocks_p, merge_blocks,
	make_forwarder_block, tidy_fallthru_edge, tidy_fallthru_edges):
	Declare.
	(cfg_layout_rtl_cfg_hooks): Declare.
	* cfgloop.c (update_latch_info, mfb_keep_just, mfb_keep_nonlatch):
	New functions.
	(canonicalize_loop_headers): Use new semantics of make_forwarder_block.
	(redirect_edge_with_latch_update): Removed.
	(make_forwarder_block): Moved to cfghooks.c, semantics changed.
	* cfgloopmanip.c (remove_bbs): Do not update dominators here.
	* cfgrtl.c (cfg_layout_split_block, rtl_split_block, rtl_dump_bb,
	rtl_delete_block, rtl_split_block, rtl_merge_blocks,
	tidy_fallthru_edge, rtl_split_edge, cfg_layout_delete_block,
	cfg_layout_merge_blocks, cfg_layout_split_edge): Partly moved to
	cfghooks.c.
	(rtl_create_basic_block): Coding style fix.
	(rtl_tidy_fallthru_edge, rtl_move_block_after,
	rtl_make_forwarder_block): New functions.
	(update_cfg_after_block_merging): Removed.
	(rtl_cfg_hooks, cfg_layout_rtl_cfg_hooks): Fill in new entries.
	* flow.c (verify_wide_reg, verify_local_live_at_start): Add argument
	to dump_bb.
	* ifcvt.c (merge_if_block, find_cond_trap, find_if_case_1,
	find_if_case_2): Don't update dominators.
	* timevar.def (TV_CFG_VERIFY): New.
	* loop-unswitch.c (unswitch_loop): Don't call add_to_dominance_info.
	* cfglayout.c (copy_bbs): Don't call add_to_dominance_info.
	* cfgloopmanip.c (split_loop_bb): Don't update dominators.
	(remove_bbs): Don't call remove_bbs.
	(create_preheader): Use make_forwarder_block.
	(mfb_keep_just, mfb_update_loops): New static functions.

From-SVN: r76851
This commit is contained in:
Zdenek Dvorak 2004-01-29 08:47:56 +01:00 committed by Zdenek Dvorak
parent 3cea478846
commit f470c378ac
15 changed files with 825 additions and 494 deletions

View File

@ -1,3 +1,66 @@
2004-01-29 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* Makefile.in (cfghooks.o): Add TIMEVAR_H and toplev.h dependency.
* basic-block.h (tidy_fallthru_edge, tidy_fallthru_edges, dump_bb,
verify_flow_info): Declaration removed.
* cfg.c (verify_flow_info, dump_bb): Moved to cfghooks.c.
(debug_bb, debug_bb_n): Add argument to dump_bb call.
* cfgcleanup.c (try_simplify_condjump, try_crossjump_to_edge,
try_optimize_cfg, delete_unreachable_blocks): Use delete_basic_block
instead of delete_block.
* cfghooks.c: Include timevar.h and toplev.h.
(cfg_hooks): Define here.
(verify_flow_info, dump_bb): Moved from cfg.c.
(redirect_edge_and_branch, redirect_edge_and_branch_force,
split_block, split_block_after_labels, move_block_after,
delete_basic_block, split_edge, create_basic_block,
create_empty_bb, can_merge_blocks_p, merge_blocks,
make_forwarder_block, tidy_fallthru_edge, tidy_fallthru_edges):
New functions.
* cfghooks.h (struct cfg_hooks): Added fields name,
make_forwarder_block, tidy_fallthru_edge and
move_block_after. Changed type of verify_flow_info, dump_bb,
split_block fields. Renamed cfgh_split_edge and delete_block
fields.
(redirect_edge_and_branch, redirect_edge_and_branch_force,
split_block, delete_block, split_edge, create_basic_block,
can_merge_blocks_p, merge_blocks): Macros removed.
(cfg_hooks): Do not export.
(verify_flow_info, dump_bb, redirect_edge_and_branch,
redirect_edge_and_branch_force, split_block, split_block_after_labels,
move_block_after, delete_basic_block, split_edge, create_basic_block,
create_empty_bb, can_merge_blocks_p, merge_blocks,
make_forwarder_block, tidy_fallthru_edge, tidy_fallthru_edges):
Declare.
(cfg_layout_rtl_cfg_hooks): Declare.
* cfgloop.c (update_latch_info, mfb_keep_just, mfb_keep_nonlatch):
New functions.
(canonicalize_loop_headers): Use new semantics of make_forwarder_block.
(redirect_edge_with_latch_update): Removed.
(make_forwarder_block): Moved to cfghooks.c, semantics changed.
* cfgloopmanip.c (remove_bbs): Do not update dominators here.
* cfgrtl.c (cfg_layout_split_block, rtl_split_block, rtl_dump_bb,
rtl_delete_block, rtl_split_block, rtl_merge_blocks,
tidy_fallthru_edge, rtl_split_edge, cfg_layout_delete_block,
cfg_layout_merge_blocks, cfg_layout_split_edge): Partly moved to
cfghooks.c.
(rtl_create_basic_block): Coding style fix.
(rtl_tidy_fallthru_edge, rtl_move_block_after,
rtl_make_forwarder_block): New functions.
(update_cfg_after_block_merging): Removed.
(rtl_cfg_hooks, cfg_layout_rtl_cfg_hooks): Fill in new entries.
* flow.c (verify_wide_reg, verify_local_live_at_start): Add argument
to dump_bb.
* ifcvt.c (merge_if_block, find_cond_trap, find_if_case_1,
find_if_case_2): Don't update dominators.
* timevar.def (TV_CFG_VERIFY): New.
* loop-unswitch.c (unswitch_loop): Don't call add_to_dominance_info.
* cfglayout.c (copy_bbs): Don't call add_to_dominance_info.
* cfgloopmanip.c (split_loop_bb): Don't update dominators.
(remove_bbs): Don't call remove_bbs.
(create_preheader): Use make_forwarder_block.
(mfb_keep_just, mfb_update_loops): New static functions.
2004-01-29 Kazu Hirata <kazu@cs.umass.edu>
* config/avr/avr.h: Remove target-independent comments about

View File

@ -1686,7 +1686,7 @@ cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h insn-
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h
cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
$(BASIC_BLOCK_H) cfglayout.h
$(BASIC_BLOCK_H) cfglayout.h $(TIMEVAR_H) toplev.h
cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \
insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
function.h except.h $(GGC_H) $(TM_P_H) insn-config.h $(EXPR_H)

View File

@ -363,8 +363,6 @@ extern edge redirect_edge_succ_nodup (edge, basic_block);
extern void redirect_edge_pred (edge, basic_block);
extern basic_block create_basic_block_structure (rtx, rtx, rtx, basic_block);
extern void clear_bb_flags (void);
extern void tidy_fallthru_edge (edge, basic_block, basic_block);
extern void tidy_fallthru_edges (void);
extern void flow_reverse_top_sort_order_compute (int *);
extern int flow_depth_first_order_compute (int *, int *);
extern void flow_preorder_transversal_compute (int *);
@ -537,7 +535,6 @@ extern bool probably_never_executed_bb_p (basic_block);
/* In flow.c */
extern void init_flow (void);
extern void dump_bb (basic_block, FILE *);
extern void debug_bb (basic_block);
extern basic_block debug_bb_n (int);
extern void dump_regset (regset, FILE *);
@ -570,11 +567,6 @@ extern void alloc_aux_for_edges (int);
extern void clear_aux_for_edges (void);
extern void free_aux_for_edges (void);
/* This function is always defined so it can be called from the
debugger, and it is declared extern so we don't get warnings about
it being unused. */
extern void verify_flow_info (void);
typedef struct conflict_graph_def *conflict_graph;
/* Callback function when enumerating conflicts. The arguments are

173
gcc/cfg.c
View File

@ -810,185 +810,16 @@ free_aux_for_edges (void)
clear_aux_for_edges ();
}
/* Verify the CFG consistency.
Currently it does following checks edge and basic block list correctness
and calls into IL dependent checking then. */
void
verify_flow_info (void)
{
size_t *edge_checksum;
int num_bb_notes, err = 0;
basic_block bb, last_bb_seen;
basic_block *last_visited;
last_visited = xcalloc (last_basic_block + 2, sizeof (basic_block));
edge_checksum = xcalloc (last_basic_block + 2, sizeof (size_t));
/* Check bb chain & numbers. */
last_bb_seen = ENTRY_BLOCK_PTR;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, NULL, next_bb)
{
if (bb != EXIT_BLOCK_PTR
&& bb != BASIC_BLOCK (bb->index))
{
error ("bb %d on wrong place", bb->index);
err = 1;
}
if (bb->prev_bb != last_bb_seen)
{
error ("prev_bb of %d should be %d, not %d",
bb->index, last_bb_seen->index, bb->prev_bb->index);
err = 1;
}
last_bb_seen = bb;
}
/* Now check the basic blocks (boundaries etc.) */
FOR_EACH_BB_REVERSE (bb)
{
int n_fallthru = 0;
edge e;
if (bb->count < 0)
{
error ("verify_flow_info: Wrong count of block %i %i",
bb->index, (int)bb->count);
err = 1;
}
if (bb->frequency < 0)
{
error ("verify_flow_info: Wrong frequency of block %i %i",
bb->index, bb->frequency);
err = 1;
}
for (e = bb->succ; e; e = e->succ_next)
{
if (last_visited [e->dest->index + 2] == bb)
{
error ("verify_flow_info: Duplicate edge %i->%i",
e->src->index, e->dest->index);
err = 1;
}
if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
{
error ("verify_flow_info: Wrong probability of edge %i->%i %i",
e->src->index, e->dest->index, e->probability);
err = 1;
}
if (e->count < 0)
{
error ("verify_flow_info: Wrong count of edge %i->%i %i",
e->src->index, e->dest->index, (int)e->count);
err = 1;
}
last_visited [e->dest->index + 2] = bb;
if (e->flags & EDGE_FALLTHRU)
n_fallthru++;
if (e->src != bb)
{
error ("verify_flow_info: Basic block %d succ edge is corrupted",
bb->index);
fprintf (stderr, "Predecessor: ");
dump_edge_info (stderr, e, 0);
fprintf (stderr, "\nSuccessor: ");
dump_edge_info (stderr, e, 1);
fprintf (stderr, "\n");
err = 1;
}
edge_checksum[e->dest->index + 2] += (size_t) e;
}
if (n_fallthru > 1)
{
error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
err = 1;
}
for (e = bb->pred; e; e = e->pred_next)
{
if (e->dest != bb)
{
error ("basic block %d pred edge is corrupted", bb->index);
fputs ("Predecessor: ", stderr);
dump_edge_info (stderr, e, 0);
fputs ("\nSuccessor: ", stderr);
dump_edge_info (stderr, e, 1);
fputc ('\n', stderr);
err = 1;
}
edge_checksum[e->dest->index + 2] -= (size_t) e;
}
}
/* Complete edge checksumming for ENTRY and EXIT. */
{
edge e;
for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
edge_checksum[e->dest->index + 2] += (size_t) e;
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
edge_checksum[e->dest->index + 2] -= (size_t) e;
}
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
if (edge_checksum[bb->index + 2])
{
error ("basic block %i edge lists are corrupted", bb->index);
err = 1;
}
num_bb_notes = 0;
last_bb_seen = ENTRY_BLOCK_PTR;
/* Clean up. */
free (last_visited);
free (edge_checksum);
err |= cfg_hooks->cfgh_verify_flow_info ();
if (err)
internal_error ("verify_flow_info failed");
}
/* Print out one basic block with live information at start and end. */
void
dump_bb (basic_block bb, FILE *outf)
{
edge e;
fprintf (outf, ";; Basic block %d, loop depth %d, count ",
bb->index, bb->loop_depth);
fprintf (outf, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
putc ('\n', outf);
fputs (";; Predecessors: ", outf);
for (e = bb->pred; e; e = e->pred_next)
dump_edge_info (outf, e, 0);
putc ('\n', outf);
cfg_hooks->dump_bb (bb, outf);
fputs (";; Successors: ", outf);
for (e = bb->succ; e; e = e->succ_next)
dump_edge_info (outf, e, 1);
putc ('\n', outf);
}
void
debug_bb (basic_block bb)
{
dump_bb (bb, stderr);
dump_bb (bb, stderr, 0);
}
basic_block
debug_bb_n (int n)
{
basic_block bb = BASIC_BLOCK (n);
dump_bb (bb, stderr);
dump_bb (bb, stderr, 0);
return bb;
}

View File

@ -194,8 +194,8 @@ try_simplify_condjump (basic_block cbranch_block)
}
}
/* Delete the block with the unconditional jump, and clean up the mess. */
delete_block (jump_block);
tidy_fallthru_edge (cbranch_jump_edge, cbranch_block, cbranch_dest_block);
delete_basic_block (jump_block);
tidy_fallthru_edge (cbranch_jump_edge);
return true;
}
@ -1530,7 +1530,7 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
to_remove = redirect_from->succ->dest;
redirect_edge_and_branch_force (redirect_from->succ, redirect_to);
delete_block (to_remove);
delete_basic_block (to_remove);
update_forwarder_flag (redirect_from);
@ -1694,7 +1694,7 @@ try_optimize_cfg (int mode)
fprintf (rtl_dump_file, "Deleting block %i.\n",
b->index);
delete_block (b);
delete_basic_block (b);
if (!(mode & CLEANUP_CFGLAYOUT))
changed = true;
b = c;
@ -1755,7 +1755,7 @@ try_optimize_cfg (int mode)
c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
redirect_edge_succ_nodup (b->pred, b->succ->dest);
delete_block (b);
delete_basic_block (b);
changed = true;
b = c;
}
@ -1873,7 +1873,7 @@ delete_unreachable_blocks (void)
if (!(b->flags & BB_REACHABLE))
{
delete_block (b);
delete_basic_block (b);
changed = true;
}
}

View File

@ -26,12 +26,11 @@ Boston, MA 02111-1307, USA. */
#include "tree.h"
#include "rtl.h"
#include "basic-block.h"
extern struct cfg_hooks rtl_cfg_hooks;
extern struct cfg_hooks cfg_layout_rtl_cfg_hooks;
#include "timevar.h"
#include "toplev.h"
/* A pointer to one of the hooks containers. */
struct cfg_hooks *cfg_hooks;
static struct cfg_hooks *cfg_hooks;
/* Initialization of functions specific to the rtl IR. */
void
@ -46,3 +45,532 @@ cfg_layout_rtl_register_cfg_hooks (void)
{
cfg_hooks = &cfg_layout_rtl_cfg_hooks;
}
/* Verify the CFG consistency.
Currently it does following: checks edge and basic block list correctness
and calls into IL dependent checking then. */
void
verify_flow_info (void)
{
size_t *edge_checksum;
int num_bb_notes, err = 0;
basic_block bb, last_bb_seen;
basic_block *last_visited;
timevar_push (TV_CFG_VERIFY);
last_visited = xcalloc (last_basic_block + 2, sizeof (basic_block));
edge_checksum = xcalloc (last_basic_block + 2, sizeof (size_t));
/* Check bb chain & numbers. */
last_bb_seen = ENTRY_BLOCK_PTR;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, NULL, next_bb)
{
if (bb != EXIT_BLOCK_PTR
&& bb != BASIC_BLOCK (bb->index))
{
error ("bb %d on wrong place", bb->index);
err = 1;
}
if (bb->prev_bb != last_bb_seen)
{
error ("prev_bb of %d should be %d, not %d",
bb->index, last_bb_seen->index, bb->prev_bb->index);
err = 1;
}
last_bb_seen = bb;
}
/* Now check the basic blocks (boundaries etc.) */
FOR_EACH_BB_REVERSE (bb)
{
int n_fallthru = 0;
edge e;
if (bb->count < 0)
{
error ("verify_flow_info: Wrong count of block %i %i",
bb->index, (int)bb->count);
err = 1;
}
if (bb->frequency < 0)
{
error ("verify_flow_info: Wrong frequency of block %i %i",
bb->index, bb->frequency);
err = 1;
}
for (e = bb->succ; e; e = e->succ_next)
{
if (last_visited [e->dest->index + 2] == bb)
{
error ("verify_flow_info: Duplicate edge %i->%i",
e->src->index, e->dest->index);
err = 1;
}
if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
{
error ("verify_flow_info: Wrong probability of edge %i->%i %i",
e->src->index, e->dest->index, e->probability);
err = 1;
}
if (e->count < 0)
{
error ("verify_flow_info: Wrong count of edge %i->%i %i",
e->src->index, e->dest->index, (int)e->count);
err = 1;
}
last_visited [e->dest->index + 2] = bb;
if (e->flags & EDGE_FALLTHRU)
n_fallthru++;
if (e->src != bb)
{
error ("verify_flow_info: Basic block %d succ edge is corrupted",
bb->index);
fprintf (stderr, "Predecessor: ");
dump_edge_info (stderr, e, 0);
fprintf (stderr, "\nSuccessor: ");
dump_edge_info (stderr, e, 1);
fprintf (stderr, "\n");
err = 1;
}
edge_checksum[e->dest->index + 2] += (size_t) e;
}
if (n_fallthru > 1)
{
error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
err = 1;
}
for (e = bb->pred; e; e = e->pred_next)
{
if (e->dest != bb)
{
error ("basic block %d pred edge is corrupted", bb->index);
fputs ("Predecessor: ", stderr);
dump_edge_info (stderr, e, 0);
fputs ("\nSuccessor: ", stderr);
dump_edge_info (stderr, e, 1);
fputc ('\n', stderr);
err = 1;
}
edge_checksum[e->dest->index + 2] -= (size_t) e;
}
}
/* Complete edge checksumming for ENTRY and EXIT. */
{
edge e;
for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
edge_checksum[e->dest->index + 2] += (size_t) e;
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
edge_checksum[e->dest->index + 2] -= (size_t) e;
}
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
if (edge_checksum[bb->index + 2])
{
error ("basic block %i edge lists are corrupted", bb->index);
err = 1;
}
num_bb_notes = 0;
last_bb_seen = ENTRY_BLOCK_PTR;
/* Clean up. */
free (last_visited);
free (edge_checksum);
if (cfg_hooks->verify_flow_info)
err |= cfg_hooks->verify_flow_info ();
if (err)
internal_error ("verify_flow_info failed");
timevar_pop (TV_CFG_VERIFY);
}
/* Print out one basic block. This function takes care of the purely
graph related information. The cfg hook for the active representation
should dump representation-specific information. */
void
dump_bb (basic_block bb, FILE *outf, int indent)
{
edge e;
char *s_indent;
s_indent = (char *) alloca ((size_t) indent + 1);
memset ((void *) s_indent, ' ', (size_t) indent);
s_indent[indent] = '\0';
fprintf (outf, ";;%s basic block %d, loop depth %d, count ",
s_indent, bb->index, bb->loop_depth);
fprintf (outf, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
putc ('\n', outf);
fprintf (outf, ";;%s prev block ", s_indent);
if (bb->prev_bb)
fprintf (outf, "%d, ", bb->prev_bb->index);
else
fprintf (outf, "(nil), ");
fprintf (outf, "next block ");
if (bb->next_bb)
fprintf (outf, "%d", bb->next_bb->index);
else
fprintf (outf, "(nil)");
putc ('\n', outf);
fprintf (outf, ";;%s pred: ", s_indent);
for (e = bb->pred; e; e = e->pred_next)
dump_edge_info (outf, e, 0);
putc ('\n', outf);
fprintf (outf, ";;%s succ: ", s_indent);
for (e = bb->succ; e; e = e->succ_next)
dump_edge_info (outf, e, 1);
putc ('\n', outf);
if (cfg_hooks->dump_bb)
cfg_hooks->dump_bb (bb, outf, indent);
}
/* Redirect edge E to the given basic block DEST and update underlying program
representation. Returns edge representing redirected branch (that may not
be equivalent to E in the case of duplicate edges being removed) or NULL
if edge is not easily redirectable for whatever reason. */
bool
redirect_edge_and_branch (edge e, basic_block dest)
{
bool ret;
if (!cfg_hooks->redirect_edge_and_branch)
internal_error ("%s does not support redirect_edge_and_branch.",
cfg_hooks->name);
ret = cfg_hooks->redirect_edge_and_branch (e, dest);
return ret;
}
/* Redirect the edge E to basic block DEST even if it requires creating
of a new basic block; then it returns the newly created basic block.
Aborts when redirection is impossible. */
basic_block
redirect_edge_and_branch_force (edge e, basic_block dest)
{
basic_block ret;
if (!cfg_hooks->redirect_edge_and_branch_force)
internal_error ("%s does not support redirect_edge_and_branch_force.",
cfg_hooks->name);
ret = cfg_hooks->redirect_edge_and_branch_force (e, dest);
return ret;
}
/* Splits basic block BB after the specified instruction I (but at least after
the labels). If I is NULL, splits just after labels. The newly created edge
is returned. The new basic block is created just after the old one. */
edge
split_block (basic_block bb, void *i)
{
basic_block new_bb;
if (!cfg_hooks->split_block)
internal_error ("%s does not support split_block.", cfg_hooks->name);
new_bb = cfg_hooks->split_block (bb, i);
if (!new_bb)
return NULL;
new_bb->count = bb->count;
new_bb->frequency = bb->frequency;
new_bb->loop_depth = bb->loop_depth;
if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
{
redirect_immediate_dominators (CDI_DOMINATORS, bb, new_bb);
set_immediate_dominator (CDI_DOMINATORS, new_bb, bb);
}
return make_edge (bb, new_bb, EDGE_FALLTHRU);
}
/* Splits block BB just after labels. The newly created edge is returned. */
edge
split_block_after_labels (basic_block bb)
{
return split_block (bb, NULL);
}
/* Moves block BB immediatelly after block AFTER. Returns false if the
movement was impossible. */
bool
move_block_after (basic_block bb, basic_block after)
{
bool ret;
if (!cfg_hooks->move_block_after)
internal_error ("%s does not support move_block_after.", cfg_hooks->name);
ret = cfg_hooks->move_block_after (bb, after);
return ret;
}
/* Deletes the basic block BB. */
void
delete_basic_block (basic_block bb)
{
if (!cfg_hooks->delete_basic_block)
internal_error ("%s does not support delete_basic_block.", cfg_hooks->name);
cfg_hooks->delete_basic_block (bb);
/* 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 (bb->pred != NULL)
remove_edge (bb->pred);
while (bb->succ != NULL)
remove_edge (bb->succ);
bb->pred = NULL;
bb->succ = NULL;
if (dom_computed[CDI_DOMINATORS])
delete_from_dominance_info (CDI_DOMINATORS, bb);
if (dom_computed[CDI_POST_DOMINATORS])
delete_from_dominance_info (CDI_POST_DOMINATORS, bb);
/* Remove the basic block from the array. */
expunge_block (bb);
}
/* Splits edge E and returns the newly created basic block. */
basic_block
split_edge (edge e)
{
basic_block ret;
gcov_type count = e->count;
int freq = EDGE_FREQUENCY (e);
if (!cfg_hooks->split_edge)
internal_error ("%s does not support split_edge.", cfg_hooks->name);
ret = cfg_hooks->split_edge (e);
ret->count = count;
ret->frequency = freq;
ret->succ->probability = REG_BR_PROB_BASE;
ret->succ->count = count;
if (dom_computed[CDI_DOMINATORS])
set_immediate_dominator (CDI_DOMINATORS, ret, ret->pred->src);
if (dom_computed[CDI_DOMINATORS] >= DOM_NO_FAST_QUERY)
set_immediate_dominator (CDI_DOMINATORS, ret->succ->dest,
recount_dominator (CDI_DOMINATORS,
ret->succ->dest));
return ret;
}
/* Creates a new basic block just after the basic block AFTER.
HEAD and END are the first and the last statement belonging
to the block. If both are NULL, an empty block is created. */
basic_block
create_basic_block (void *head, void *end, basic_block after)
{
basic_block ret;
if (!cfg_hooks->create_basic_block)
internal_error ("%s does not support create_basic_block.", cfg_hooks->name);
ret = cfg_hooks->create_basic_block (head, end, after);
if (dom_computed[CDI_DOMINATORS])
add_to_dominance_info (CDI_DOMINATORS, ret);
if (dom_computed[CDI_POST_DOMINATORS])
add_to_dominance_info (CDI_POST_DOMINATORS, ret);
return ret;
}
/* Creates an empty basic block just after basic block AFTER. */
basic_block
create_empty_bb (basic_block after)
{
return create_basic_block (NULL, NULL, after);
}
/* Checks whether we may merge blocks BB1 and BB2. */
bool
can_merge_blocks_p (basic_block bb1, basic_block bb2)
{
bool ret;
if (!cfg_hooks->can_merge_blocks_p)
internal_error ("%s does not support can_merge_blocks_p.", cfg_hooks->name);
ret = cfg_hooks->can_merge_blocks_p (bb1, bb2);
return ret;
}
/* Merges basic block B into basic block A. */
void
merge_blocks (basic_block a, basic_block b)
{
edge e;
if (!cfg_hooks->merge_blocks)
internal_error ("%s does not support merge_blocks.", cfg_hooks->name);
cfg_hooks->merge_blocks (a, b);
/* 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;
if (dom_computed[CDI_DOMINATORS])
redirect_immediate_dominators (CDI_DOMINATORS, b, a);
if (dom_computed[CDI_DOMINATORS])
delete_from_dominance_info (CDI_DOMINATORS, b);
if (dom_computed[CDI_POST_DOMINATORS])
delete_from_dominance_info (CDI_POST_DOMINATORS, b);
expunge_block (b);
}
/* Split BB into entry part and the rest (the rest is the newly created block).
Redirect those edges for that REDIRECT_EDGE_P returns true to the entry
part. Returns the edge connecting the entry part to the rest. */
edge
make_forwarder_block (basic_block bb, bool (*redirect_edge_p) (edge),
void (*new_bb_cbk) (basic_block))
{
edge e, next_e, fallthru;
basic_block dummy, jump;
if (!cfg_hooks->make_forwarder_block)
internal_error ("%s does not support make_forwarder_block.",
cfg_hooks->name);
fallthru = split_block_after_labels (bb);
dummy = fallthru->src;
bb = fallthru->dest;
/* Redirect back edges we want to keep. */
for (e = dummy->pred; e; e = next_e)
{
next_e = e->pred_next;
if (redirect_edge_p (e))
continue;
dummy->frequency -= EDGE_FREQUENCY (e);
dummy->count -= e->count;
if (dummy->frequency < 0)
dummy->frequency = 0;
if (dummy->count < 0)
dummy->count = 0;
jump = redirect_edge_and_branch_force (e, bb);
if (jump)
new_bb_cbk (jump);
}
if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
{
basic_block doms_to_fix[2];
doms_to_fix[0] = dummy;
doms_to_fix[1] = bb;
iterate_fix_dominators (CDI_DOMINATORS, doms_to_fix, 2);
}
cfg_hooks->make_forwarder_block (fallthru);
return fallthru;
}
void
tidy_fallthru_edge (edge e)
{
if (cfg_hooks->tidy_fallthru_edge)
cfg_hooks->tidy_fallthru_edge (e);
}
/* 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 (!cfg_hooks->tidy_fallthru_edge)
return;
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)
tidy_fallthru_edge (s);
}
}

View File

@ -24,10 +24,12 @@ Boston, MA 02111-1307, USA. */
struct cfg_hooks
{
/* Debugging. Do not use macros to hook these so they can be called from
debugger! */
int (*cfgh_verify_flow_info) (void);
void (*dump_bb) (basic_block, FILE *);
/* Name of the corresponding ir. */
const char *name;
/* Debugging. */
int (*verify_flow_info) (void);
void (*dump_bb) (basic_block, FILE *, int);
/* Basic CFG manipulation. */
@ -44,11 +46,15 @@ struct cfg_hooks
on abnormal edge. */
basic_block (*redirect_edge_and_branch_force) (edge, basic_block);
/* Remove given basic block and all edges possibly pointing into it. */
void (*delete_block) (basic_block);
/* Remove statements corresponding to a given basic block. */
void (*delete_basic_block) (basic_block);
/* Split basic block B after specified instruction I. */
edge (*split_block) (basic_block b, void * i);
/* Creates a new basic block just after basic block B by splitting
everything after specified instruction I. */
basic_block (*split_block) (basic_block b, void * i);
/* Move block B immediately after block A. */
bool (*move_block_after) (basic_block b, basic_block a);
/* Return true when blocks A and B can be merged into single basic block. */
bool (*can_merge_blocks_p) (basic_block a, basic_block b);
@ -58,23 +64,34 @@ struct cfg_hooks
/* Higher level functions representable by primitive operations above if
we didn't have some oddities in RTL and Tree representations. */
basic_block (*cfgh_split_edge) (edge);
basic_block (*split_edge) (edge);
void (*make_forwarder_block) (edge);
/* Tries to make the edge fallthru. */
void (*tidy_fallthru_edge) (edge);
};
#define redirect_edge_and_branch(e,b) cfg_hooks->redirect_edge_and_branch (e,b)
#define redirect_edge_and_branch_force(e,b) cfg_hooks->redirect_edge_and_branch_force (e,b)
#define split_block(e,i) cfg_hooks->split_block (e,i)
#define delete_block(b) cfg_hooks->delete_block (b)
#define split_edge(e) cfg_hooks->cfgh_split_edge (e)
#define create_basic_block(h,e,a) cfg_hooks->create_basic_block (h,e,a)
#define can_merge_blocks_p(a,b) cfg_hooks->can_merge_blocks_p (a,b)
#define merge_blocks(a,b) cfg_hooks->merge_blocks (a,b)
extern void verify_flow_info (void);
extern void dump_bb (basic_block, FILE *, int);
extern bool redirect_edge_and_branch (edge, basic_block);
extern basic_block redirect_edge_and_branch_force (edge, basic_block);
extern edge split_block (basic_block, void *);
extern edge split_block_after_labels (basic_block);
extern bool move_block_after (basic_block, basic_block);
extern void delete_basic_block (basic_block);
extern basic_block split_edge (edge);
extern basic_block create_basic_block (void *, void *, basic_block);
extern basic_block create_empty_bb (basic_block);
extern bool can_merge_blocks_p (basic_block, basic_block);
extern void merge_blocks (basic_block, basic_block);
extern edge make_forwarder_block (basic_block, bool (*)(edge),
void (*) (basic_block));
extern void tidy_fallthru_edge (edge);
extern void tidy_fallthru_edges (void);
/* Hooks containers. */
extern struct cfg_hooks rtl_cfg_hooks;
/* A pointer to one of the hooks containers. */
extern struct cfg_hooks *cfg_hooks;
extern struct cfg_hooks cfg_layout_rtl_cfg_hooks;
/* Declarations. */
extern void rtl_register_cfg_hooks (void);

View File

@ -1268,7 +1268,6 @@ copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs,
bb->rbi->duplicated = 1;
/* Add to loop. */
add_bb_to_loop (new_bb, bb->loop_father->copy);
add_to_dominance_info (CDI_DOMINATORS, new_bb);
/* Possibly set header. */
if (bb->loop_father->header == bb && bb->loop_father != base)
new_bb->loop_father->header = new_bb;

View File

@ -33,6 +33,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
considered to belong to inner loop with same header. */
#define HEAVY_EDGE_RATIO 8
#define HEADER_BLOCK(B) (* (int *) (B)->aux)
#define LATCH_EDGE(E) (*(int *) (E)->aux)
static void flow_loops_cfg_dump (const struct loops *, FILE *);
static void flow_loop_entry_edges_find (struct loop *);
static void flow_loop_exit_edges_find (struct loop *);
@ -42,10 +45,8 @@ static basic_block flow_loop_pre_header_find (basic_block);
static int flow_loop_level_compute (struct loop *);
static int flow_loops_level_compute (struct loops *);
static void establish_preds (struct loop *);
static basic_block make_forwarder_block (basic_block, int, int, edge, int);
static void canonicalize_loop_headers (void);
static bool glb_enum_p (basic_block, void *);
static void redirect_edge_with_latch_update (edge, basic_block);
/* Dump loop related CFG information. */
@ -547,78 +548,41 @@ flow_loop_scan (struct loop *loop, int flags)
return 1;
}
#define HEADER_BLOCK(B) (* (int *) (B)->aux)
#define LATCH_EDGE(E) (*(int *) (E)->aux)
/* A callback to update latch and header info for basic block JUMP created
by redirecting an edge. */
/* Redirect edge and update latch and header info. */
static void
redirect_edge_with_latch_update (edge e, basic_block to)
update_latch_info (basic_block jump)
{
basic_block jump;
jump = redirect_edge_and_branch_force (e, to);
if (jump)
{
alloc_aux_for_block (jump, sizeof (int));
HEADER_BLOCK (jump) = 0;
alloc_aux_for_edge (jump->pred, sizeof (int));
LATCH_EDGE (jump->succ) = LATCH_EDGE (e);
LATCH_EDGE (jump->pred) = 0;
}
alloc_aux_for_block (jump, sizeof (int));
HEADER_BLOCK (jump) = 0;
alloc_aux_for_edge (jump->pred, sizeof (int));
LATCH_EDGE (jump->pred) = 0;
}
/* Split BB into entry part and rest; if REDIRECT_LATCH, redirect edges
marked as latch into entry part, analogically for REDIRECT_NONLATCH.
In both of these cases, ignore edge EXCEPT. If CONN_LATCH, set edge
between created entry part and BB as latch one. Return created entry
part. */
/* A callback for make_forwarder block, to redirect all edges except for
MFB_KJ_EDGE to the entry part. E is the edge for that we should decide
whether to redirect it. */
static basic_block
make_forwarder_block (basic_block bb, int redirect_latch, int redirect_nonlatch, edge except, int conn_latch)
static edge mfb_kj_edge;
static bool
mfb_keep_just (edge e)
{
edge e, next_e, fallthru;
basic_block dummy;
rtx insn;
return e != mfb_kj_edge;
}
insn = PREV_INSN (first_insn_after_basic_block_note (bb));
/* A callback for make_forwarder block, to redirect the latch edges into an
entry part. E is the edge for that we should decide whether to redirect
it. */
/* For empty block split_block will return NULL. */
if (BB_END (bb) == insn)
emit_note_after (NOTE_INSN_DELETED, insn);
fallthru = split_block (bb, insn);
dummy = fallthru->src;
bb = fallthru->dest;
bb->aux = xmalloc (sizeof (int));
HEADER_BLOCK (dummy) = 0;
HEADER_BLOCK (bb) = 1;
/* Redirect back edges we want to keep. */
for (e = dummy->pred; e; e = next_e)
{
next_e = e->pred_next;
if (e == except
|| !((redirect_latch && LATCH_EDGE (e))
|| (redirect_nonlatch && !LATCH_EDGE (e))))
{
dummy->frequency -= EDGE_FREQUENCY (e);
dummy->count -= e->count;
if (dummy->frequency < 0)
dummy->frequency = 0;
if (dummy->count < 0)
dummy->count = 0;
redirect_edge_with_latch_update (e, bb);
}
}
alloc_aux_for_edge (fallthru, sizeof (int));
LATCH_EDGE (fallthru) = conn_latch;
return dummy;
static bool
mfb_keep_nonlatch (edge e)
{
return LATCH_EDGE (e);
}
/* Takes care of merging natural loops with shared headers. */
static void
canonicalize_loop_headers (void)
{
@ -675,19 +639,10 @@ canonicalize_loop_headers (void)
FOR_EACH_BB (header)
{
int num_latch;
int want_join_latch;
int max_freq, is_heavy;
edge heavy;
edge heavy, tmp_edge;
if (!HEADER_BLOCK (header))
continue;
num_latch = HEADER_BLOCK (header);
want_join_latch = (num_latch > 1);
if (!want_join_latch)
if (HEADER_BLOCK (header) <= 1)
continue;
/* Find a heavy edge. */
@ -713,13 +668,28 @@ canonicalize_loop_headers (void)
if (is_heavy)
{
basic_block new_header =
make_forwarder_block (header, true, true, heavy, 0);
if (num_latch > 2)
make_forwarder_block (new_header, true, false, NULL, 1);
/* Split out the heavy edge, and create inner loop for it. */
mfb_kj_edge = heavy;
tmp_edge = make_forwarder_block (header, mfb_keep_just,
update_latch_info);
alloc_aux_for_block (tmp_edge->dest, sizeof (int));
HEADER_BLOCK (tmp_edge->dest) = 1;
alloc_aux_for_edge (tmp_edge, sizeof (int));
LATCH_EDGE (tmp_edge) = 0;
HEADER_BLOCK (header)--;
}
if (HEADER_BLOCK (header) > 1)
{
/* Create a new latch block. */
tmp_edge = make_forwarder_block (header, mfb_keep_nonlatch,
update_latch_info);
alloc_aux_for_block (tmp_edge->dest, sizeof (int));
HEADER_BLOCK (tmp_edge->src) = 0;
HEADER_BLOCK (tmp_edge->dest) = 1;
alloc_aux_for_edge (tmp_edge, sizeof (int));
LATCH_EDGE (tmp_edge) = 1;
}
else
make_forwarder_block (header, true, false, NULL, 1);
}
free_aux_for_blocks ();

View File

@ -63,11 +63,6 @@ split_loop_bb (basic_block bb, rtx insn)
/* Add dest to loop. */
add_bb_to_loop (e->dest, e->src->loop_father);
/* Fix dominators. */
add_to_dominance_info (CDI_DOMINATORS, e->dest);
redirect_immediate_dominators (CDI_DOMINATORS, e->src, e->dest);
set_immediate_dominator (CDI_DOMINATORS, e->dest, e->src);
return e;
}
@ -88,8 +83,7 @@ remove_bbs (basic_block *bbs, int nbbs)
for (i = 0; i < nbbs; i++)
{
remove_bb_from_loops (bbs[i]);
delete_from_dominance_info (CDI_DOMINATORS, bbs[i]);
delete_block (bbs[i]);
delete_basic_block (bbs[i]);
}
}
@ -1070,19 +1064,45 @@ duplicate_loop_to_header_edge (struct loop *loop, edge e, struct loops *loops,
return true;
}
/* A callback for make_forwarder block, to redirect all edges except for
MFB_KJ_EDGE to the entry part. E is the edge for that we should decide
whether to redirect it. */
static edge mfb_kj_edge;
static bool
mfb_keep_just (edge e)
{
return e != mfb_kj_edge;
}
/* A callback for make_forwarder block, to update data structures for a basic
block JUMP created by redirecting an edge (only the latch edge is being
redirected). */
static void
mfb_update_loops (basic_block jump)
{
struct loop *loop = jump->succ->dest->loop_father;
if (dom_computed[CDI_DOMINATORS])
set_immediate_dominator (CDI_DOMINATORS, jump, jump->pred->src);
add_bb_to_loop (jump, loop);
loop->latch = jump;
}
/* Creates a pre-header for a LOOP. Returns newly created block. Unless
CP_SIMPLE_PREHEADERS is set in FLAGS, we only force LOOP to have single
entry; otherwise we also force preheader block to have only one successor.
The function also updates dominators stored in DOM. */
The function also updates dominators. */
static basic_block
create_preheader (struct loop *loop, int flags)
{
edge e, fallthru;
basic_block dummy;
basic_block jump, src = 0;
struct loop *cloop, *ploop;
int nentry = 0;
rtx insn;
bool irred = false;
cloop = loop->outer;
@ -1090,6 +1110,7 @@ create_preheader (struct loop *loop, int flags)
{
if (e->src == loop->latch)
continue;
irred |= (e->flags & EDGE_IRREDUCIBLE_LOOP) != 0;
nentry++;
}
if (!nentry)
@ -1102,17 +1123,9 @@ create_preheader (struct loop *loop, int flags)
return NULL;
}
insn = first_insn_after_basic_block_note (loop->header);
if (insn)
insn = PREV_INSN (insn);
else
insn = get_last_insn ();
if (insn == BB_END (loop->header))
{
/* Split_block would not split block after its end. */
emit_note_after (NOTE_INSN_DELETED, insn);
}
fallthru = split_block (loop->header, insn);
mfb_kj_edge = loop_latch_edge (loop);
fallthru = make_forwarder_block (loop->header, mfb_keep_just,
mfb_update_loops);
dummy = fallthru->src;
loop->header = fallthru->dest;
@ -1122,35 +1135,22 @@ create_preheader (struct loop *loop, int flags)
if (ploop->latch == dummy)
ploop->latch = fallthru->dest;
add_to_dominance_info (CDI_DOMINATORS, fallthru->dest);
/* Redirect edges. */
/* Reorganize blocks so that the preheader is not stuck in the middle of the
loop. */
for (e = dummy->pred; e; e = e->pred_next)
{
src = e->src;
if (src == loop->latch)
break;
}
if (!e)
abort ();
if (e->src != loop->latch)
break;
move_block_after (dummy, e->src);
dummy->frequency -= EDGE_FREQUENCY (e);
dummy->count -= e->count;
fallthru->count -= e->count;
jump = redirect_edge_and_branch_force (e, loop->header);
if (jump)
{
add_to_dominance_info (CDI_DOMINATORS, jump);
set_immediate_dominator (CDI_DOMINATORS, jump, src);
add_bb_to_loop (jump, loop);
loop->latch = jump;
}
/* Update structures. */
redirect_immediate_dominators (CDI_DOMINATORS, dummy, loop->header);
set_immediate_dominator (CDI_DOMINATORS, loop->header, dummy);
loop->header->loop_father = loop;
add_bb_to_loop (dummy, cloop);
if (irred)
{
dummy->flags |= BB_IRREDUCIBLE_LOOP;
dummy->succ->flags |= EDGE_IRREDUCIBLE_LOOP;
}
if (rtl_dump_file)
fprintf (rtl_dump_file, "Created preheader block for loop %i\n",
loop->num);
@ -1212,7 +1212,6 @@ loop_split_edge_with (edge e, rtx insns)
/* Create basic block for it. */
new_bb = split_edge (e);
add_to_dominance_info (CDI_DOMINATORS, new_bb);
add_bb_to_loop (new_bb, loop_c);
new_bb->flags = insns ? BB_SUPERBLOCK : 0;
@ -1226,10 +1225,6 @@ loop_split_edge_with (edge e, rtx insns)
if (insns)
emit_insn_after (insns, BB_END (new_bb));
set_immediate_dominator (CDI_DOMINATORS, new_bb, src);
set_immediate_dominator (CDI_DOMINATORS, dest,
recount_dominator (CDI_DOMINATORS, dest));
if (dest->loop_father->latch == src)
dest->loop_father->latch = new_bb;

View File

@ -76,18 +76,20 @@ static rtx last_loop_beg_note (rtx);
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);
/* Return true if NOTE is not one of the ones that must be kept paired,
so that we may simply delete it. */
@ -337,7 +339,7 @@ rtl_create_basic_block (void *headp, void *endp, basic_block after)
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++;
@ -407,19 +409,6 @@ rtl_delete_block (basic_block b)
/* 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);
}
/* Records the basic block struct in BLOCK_FOR_INSN for every insn. */
@ -470,28 +459,34 @@ update_bb_for_insn (basic_block bb)
}
}
/* 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;
/* There is no point splitting the block after its end. */
if (BB_END (bb) == insn)
return 0;
if (!insn)
{
insn = first_insn_after_basic_block_note (bb);
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. */
@ -500,8 +495,6 @@ rtl_split_block (basic_block bb, void *insnp)
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);
@ -528,34 +521,7 @@ rtl_split_block (basic_block bb, void *insnp)
#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
@ -625,10 +591,9 @@ rtl_merge_blocks (basic_block a, basic_block b)
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. */
@ -1159,10 +1124,16 @@ rtl_redirect_edge_and_branch_force (edge e, basic_block target)
/* 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
@ -1208,48 +1179,6 @@ tidy_fallthru_edge (edge e, basic_block b, basic_block c)
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);
}
}
/* Helper function for split_edge. Return true in case edge BB2 to BB1
is back edge of syntactic loop. */
@ -1285,6 +1214,15 @@ back_edge_of_syntactic_loop_p (basic_block bb1, basic_block bb2)
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.
@ -1347,8 +1285,6 @@ rtl_split_edge (edge edge_in)
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)
@ -1714,15 +1650,21 @@ commit_edge_insertions_watch_calls (void)
sbitmap_free (blocks);
}
/* 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;
fputs (";; Registers live at start:", outf);
s_indent = (char *) alloca ((size_t) indent + 1);
memset ((void *) s_indent, ' ', (size_t) indent);
s_indent[indent] = '\0';
fprintf (outf, ";;%s Registers live at start: ", s_indent);
dump_regset (bb->global_live_at_start, outf);
putc ('\n', outf);
@ -1730,7 +1672,7 @@ rtl_dump_bb (basic_block bb, FILE *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);
}
@ -1847,6 +1789,7 @@ update_br_prob_note (basic_block bb)
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)
{
@ -2412,16 +2355,17 @@ purge_all_dead_edges (int update_life_p)
}
/* 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;
}
@ -2511,7 +2455,8 @@ cfg_layout_redirect_edge_and_branch_force (edge e, basic_block dest)
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)
{
@ -2693,11 +2638,10 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
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)
{
@ -2707,19 +2651,22 @@ 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,
@ -2727,9 +2674,12 @@ struct cfg_hooks rtl_cfg_hooks = {
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
@ -2737,6 +2687,7 @@ struct cfg_hooks rtl_cfg_hooks = {
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,
@ -2744,7 +2695,10 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
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
};

View File

@ -517,7 +517,7 @@ verify_wide_reg (int regno, basic_block bb)
if (rtl_dump_file)
{
fprintf (rtl_dump_file, "Register %d died unexpectedly.\n", regno);
dump_bb (bb, rtl_dump_file);
dump_bb (bb, rtl_dump_file, 0);
}
abort ();
}
@ -541,7 +541,7 @@ verify_local_live_at_start (regset new_live_at_start, basic_block bb)
bb->index);
debug_bitmap_file (rtl_dump_file, new_live_at_start);
fputs ("Old:\n", rtl_dump_file);
dump_bb (bb, rtl_dump_file);
dump_bb (bb, rtl_dump_file, 0);
}
abort ();
}
@ -562,7 +562,7 @@ verify_local_live_at_start (regset new_live_at_start, basic_block bb)
{
fprintf (rtl_dump_file,
"Register %d died unexpectedly.\n", i);
dump_bb (bb, rtl_dump_file);
dump_bb (bb, rtl_dump_file, 0);
}
abort ();
}

View File

@ -2103,8 +2103,6 @@ merge_if_block (struct ce_if_block * ce_info)
{
bb = fallthru;
fallthru = block_fallthru (bb);
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
delete_from_dominance_info (CDI_POST_DOMINATORS, bb);
merge_blocks (combo_bb, bb);
num_true_changes++;
}
@ -2120,8 +2118,6 @@ merge_if_block (struct ce_if_block * ce_info)
if (combo_bb->global_live_at_end)
COPY_REG_SET (combo_bb->global_live_at_end,
then_bb->global_live_at_end);
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
delete_from_dominance_info (CDI_POST_DOMINATORS, then_bb);
merge_blocks (combo_bb, then_bb);
num_true_changes++;
}
@ -2131,8 +2127,6 @@ merge_if_block (struct ce_if_block * ce_info)
get their addresses taken. */
if (else_bb)
{
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
delete_from_dominance_info (CDI_POST_DOMINATORS, else_bb);
merge_blocks (combo_bb, else_bb);
num_true_changes++;
}
@ -2188,8 +2182,6 @@ merge_if_block (struct ce_if_block * ce_info)
COPY_REG_SET (combo_bb->global_live_at_end,
join_bb->global_live_at_end);
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
delete_from_dominance_info (CDI_POST_DOMINATORS, join_bb);
merge_blocks (combo_bb, join_bb);
num_true_changes++;
}
@ -2205,7 +2197,7 @@ merge_if_block (struct ce_if_block * ce_info)
/* Remove the jump and cruft from the end of the COMBO block. */
if (join_bb != EXIT_BLOCK_PTR)
tidy_fallthru_edge (combo_bb->succ, combo_bb, join_bb);
tidy_fallthru_edge (combo_bb->succ);
}
num_updated_if_blocks++;
@ -2643,11 +2635,7 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
/* Delete the trap block if possible. */
remove_edge (trap_bb == then_bb ? then_edge : else_edge);
if (trap_bb->pred == NULL)
{
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
delete_from_dominance_info (CDI_POST_DOMINATORS, trap_bb);
delete_block (trap_bb);
}
delete_basic_block (trap_bb);
/* If the non-trap block and the test are now adjacent, merge them.
Otherwise we must insert a direct branch. */
@ -2829,9 +2817,7 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
then_bb_index = then_bb->index;
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
delete_from_dominance_info (CDI_POST_DOMINATORS, then_bb);
delete_block (then_bb);
delete_basic_block (then_bb);
/* Make rest of code believe that the newly created block is the THEN_BB
block we removed. */
@ -2839,8 +2825,6 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
{
new_bb->index = then_bb_index;
BASIC_BLOCK (then_bb_index) = new_bb;
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
add_to_dominance_info (CDI_POST_DOMINATORS, new_bb);
}
/* We've possibly created jump to next insn, cleanup_cfg will solve that
later. */
@ -2909,9 +2893,7 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
then_bb->global_live_at_start,
else_bb->global_live_at_end, BITMAP_IOR);
if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
delete_from_dominance_info (CDI_POST_DOMINATORS, else_bb);
delete_block (else_bb);
delete_basic_block (else_bb);
num_true_changes++;
num_updated_if_blocks++;

View File

@ -381,7 +381,6 @@ unswitch_loop (struct loops *loops, struct loop *loop, basic_block unswitch_on)
switch_bb->succ->flags &= ~EDGE_IRREDUCIBLE_LOOP;
switch_bb->succ->succ_next->flags &= ~EDGE_IRREDUCIBLE_LOOP;
}
add_to_dominance_info (CDI_DOMINATORS, switch_bb);
unswitch_on->rbi->copy = unswitch_on_alt;
/* Loopify from the copy of LOOP body, constructing the new loop. */

View File

@ -45,6 +45,7 @@ DEFTIMEVAR (TV_CGRAPHOPT , "callgraph optimization")
DEFTIMEVAR (TV_CFG , "cfg construction")
/* Time spent by cleaning up CFG. */
DEFTIMEVAR (TV_CLEANUP_CFG , "cfg cleanup")
DEFTIMEVAR (TV_CFG_VERIFY , "CFG verifier")
DEFTIMEVAR (TV_DELETE_TRIVIALLY_DEAD , "trivially dead code")
/* Time spent by life analysis. */
DEFTIMEVAR (TV_LIFE , "life analysis")