mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-17 09:13:49 +08:00
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:
parent
3cea478846
commit
f470c378ac
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
173
gcc/cfg.c
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
536
gcc/cfghooks.c
536
gcc/cfghooks.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
122
gcc/cfgloop.c
122
gcc/cfgloop.c
@ -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)
|
||||
{
|
||||
basic_block jump;
|
||||
|
||||
jump = redirect_edge_and_branch_force (e, to);
|
||||
if (jump)
|
||||
update_latch_info (basic_block 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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 the latch edges into an
|
||||
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 bool
|
||||
mfb_keep_nonlatch (edge e)
|
||||
{
|
||||
edge e, next_e, fallthru;
|
||||
basic_block dummy;
|
||||
rtx insn;
|
||||
|
||||
insn = PREV_INSN (first_insn_after_basic_block_note (bb));
|
||||
|
||||
/* 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;
|
||||
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 ();
|
||||
|
@ -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)
|
||||
if (e->src != loop->latch)
|
||||
break;
|
||||
}
|
||||
if (!e)
|
||||
abort ();
|
||||
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;
|
||||
|
||||
|
206
gcc/cfgrtl.c
206
gcc/cfgrtl.c
@ -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. */
|
||||
@ -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
|
||||
};
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
26
gcc/ifcvt.c
26
gcc/ifcvt.c
@ -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++;
|
||||
|
@ -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. */
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user