diff options
author | Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> | 2004-01-29 08:47:56 +0100 |
---|---|---|
committer | Zdenek Dvorak <rakdver@gcc.gnu.org> | 2004-01-29 07:47:56 +0000 |
commit | f470c378ac3e1ee9261034709851f4c6ef068fef (patch) | |
tree | 075d0d98ba746f488ac4ecf2ecf94a83992aacbc /gcc | |
parent | 3cea47884638a56ebe6a71d2ffd4a13e18a52598 (diff) | |
download | gcc-f470c378ac3e1ee9261034709851f4c6ef068fef.tar.gz |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 63 | ||||
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/basic-block.h | 8 | ||||
-rw-r--r-- | gcc/cfg.c | 173 | ||||
-rw-r--r-- | gcc/cfgcleanup.c | 12 | ||||
-rw-r--r-- | gcc/cfghooks.c | 536 | ||||
-rw-r--r-- | gcc/cfghooks.h | 57 | ||||
-rw-r--r-- | gcc/cfglayout.c | 1 | ||||
-rw-r--r-- | gcc/cfgloop.c | 128 | ||||
-rw-r--r-- | gcc/cfgloopmanip.c | 95 | ||||
-rw-r--r-- | gcc/cfgrtl.c | 208 | ||||
-rw-r--r-- | gcc/flow.c | 6 | ||||
-rw-r--r-- | gcc/ifcvt.c | 26 | ||||
-rw-r--r-- | gcc/loop-unswitch.c | 1 | ||||
-rw-r--r-- | gcc/timevar.def | 1 |
15 files changed, 824 insertions, 493 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index faa3c9a1376..39e5a4b5202 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 92916f0e2c6..946b4f75b18 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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) diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 10cc6351bd6..240edfd79df 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.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 diff --git a/gcc/cfg.c b/gcc/cfg.c index 80425853666..ff3f3679136 100644 --- a/gcc/cfg.c +++ b/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; } diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 52d58196d85..a886e832bb5 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -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; } } diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c index 525289c04f8..fd361c5fc85 100644 --- a/gcc/cfghooks.c +++ b/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); + } +} diff --git a/gcc/cfghooks.h b/gcc/cfghooks.h index 5ef3b1f5480..4c2d0bf37bb 100644 --- a/gcc/cfghooks.h +++ b/gcc/cfghooks.h @@ -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); + + /* 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); - /* Split basic block B after specified instruction I. */ - edge (*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); diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index 15ec0547451..bdee8675768 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -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; diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c index 69097c009a9..6fa8b17706a 100644 --- a/gcc/cfgloop.c +++ b/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) +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; - - 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); - } - } + return e != mfb_kj_edge; +} - alloc_aux_for_edge (fallthru, sizeof (int)); - LATCH_EDGE (fallthru) = conn_latch; +/* 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. */ - 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 (); diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c index 86af4a2536b..2c60659fec8 100644 --- a/gcc/cfgloopmanip.c +++ b/gcc/cfgloopmanip.c @@ -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); + + loop->header->loop_father = loop; + add_bb_to_loop (dummy, cloop); - dummy->frequency -= EDGE_FREQUENCY (e); - dummy->count -= e->count; - fallthru->count -= e->count; - jump = redirect_edge_and_branch_force (e, loop->header); - if (jump) + if (irred) { - add_to_dominance_info (CDI_DOMINATORS, jump); - set_immediate_dominator (CDI_DOMINATORS, jump, src); - add_bb_to_loop (jump, loop); - loop->latch = jump; + dummy->flags |= BB_IRREDUCIBLE_LOOP; + dummy->succ->flags |= EDGE_IRREDUCIBLE_LOOP; } - /* 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 (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; diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 70d06563ac6..01a5f3dbe66 100644 --- a/gcc/cfgrtl.c +++ b/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. */ @@ -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 }; diff --git a/gcc/flow.c b/gcc/flow.c index dbd82503609..76ffdacc194 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -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 (); } diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index ffcb0016298..7a790638091 100644 --- a/gcc/ifcvt.c +++ b/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++; diff --git a/gcc/loop-unswitch.c b/gcc/loop-unswitch.c index 4cfaa2f6255..aa39ae23816 100644 --- a/gcc/loop-unswitch.c +++ b/gcc/loop-unswitch.c @@ -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. */ diff --git a/gcc/timevar.def b/gcc/timevar.def index 6fab782c052..19dc0c468f0 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -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") |