diff options
author | Steven Bosscher <steven@gcc.gnu.org> | 2012-07-08 10:06:14 +0000 |
---|---|---|
committer | Steven Bosscher <steven@gcc.gnu.org> | 2012-07-08 10:06:14 +0000 |
commit | 532aafaddbc0ec451f6301800ba4b0d3c7ddf8a9 (patch) | |
tree | 6449db5e8557f01213c64b681cc559f5835d3636 /gcc/cfgrtl.c | |
parent | 79bdca32d42fcd1a77fbb94826d22f020dca8829 (diff) | |
download | gcc-532aafaddbc0ec451f6301800ba4b0d3c7ddf8a9.zip gcc-532aafaddbc0ec451f6301800ba4b0d3c7ddf8a9.tar.gz gcc-532aafaddbc0ec451f6301800ba4b0d3c7ddf8a9.tar.bz2 |
basic-block.h: Re-group most prototypes per file.
gcc/
* basic-block.h: Re-group most prototypes per file.
(struct edge_list): Remove num_blocks field.
(dump_bb_info): Adjust prototypes.
(dump_reg_info): Move prototype to regs.h.
* function.h: Do not include tree.h.
Include vec.h, vecir.h, input.h and machmode.h to compensate.
(function_name): New prototype.
* gimple.h: Include tree.h to compensate for basic-block.h change.
* langhooks.h: Note that tree.h is only necessary for enum tree_code.
* regs.h (dump_reg_info): Prototype here.
* regset.h: Adjust file reference in comment.
(debug_regset): Remove prototype.
* rtl.h: Include flags.h for flag_var_tracking_assignments.
(MAY_HAVE_DEBUG_INSNS): Define as flag_var_tracking_assignments
instead of no-longer-available tree.h's MAY_HAVE_DEBUG_STMTS.
(dump_reg_info, dump_flow_info): Remove prototypes.
* bb-reorder.c (set_edge_can_fallthru_flag): Move from cfganal.c
to here, the only user. Make static.
(reorder_basic_blocks): Call dump_reg_info before dump_flow_info.
* cfg.c: Do not include tm.h, tree.h, rtl.h, hard-reg-set.h, regs.h,
flags.h, function.h, except.h, diagnostic-core.h, tm_p.h, timevar.h,
tree-pass.h, cfgloop.h, and tree-flow.h.
Include basic-block.h, the first header I'd expect to be included.
(reg_obstack): Move to df-core.c.
(free_edge): Remove bogus ATTRIBUTE_UNUSED.
(remove_edge_raw): Do not call tree-ssa's redirect_edge_var_map_clear.
(redirect_edge_succ_nodup): Move to cfghooks.c.
(dump_regset, debug_regset): Move to df-core.c.
(dump_bb_info): Move to cfgrtl.c.
(dump_reg_info): Move to regstat.c.
(dump_flow_info): Move to cfgrtl.c.
(debug_flow_info): Likewise.
(dump_edge_info): Do not look at cfun, a CFG without cfun is nonsense.
* cfganal.c: Do not include tm.h, rtl.h, obstack.h, hard-reg-set.h,
insn-config.h, recog.h, diagnostic-core.h, tm_p.h, and cfgloop.h.
(flow_active_insn_p, forwarder_block_p, can_fallthru,
could_fall_through): Move to cfgrtl.c.
(set_edge_can_fallthru_flag): Moved to bb-reorder.c.
(create_edge_list): Do not set edge_list's removed num_blocks.
(print_edge_list): Look at n_basic_blocks instead of num_blocks.
(flow_nodes_print): Remove.
(flow_edge_list_print): Remove.
(inverted_post_order_compute): Use FOR_ALL_BB.
*cfgrtl.c (dump_flow_info): Moved from cfg.c.
Do not call dump_reg_info.
(debug_flow_info): Moved from cfg.c
(dump_bb_info): Moved from cfg.c. Take 'verbose' argument
to avoid looking at TDF_* flags from tree-pass.h.
(flow_active_insn_p, forwarder_block_p, can_fallthru,
could_fall_through): Moved from cfganal.c.
(print_rtl_with_bb): Adjust dump_bb_info calls.
* cfghooks.c (redirect_edge_succ_nodup): Moved from cfg.c.
(remove_edge): Call redirect_edge_var_map_clear if IR_GIMPLE.
(cfgcleanup.c): Look at MAY_HAVE_DEBUG_INSNS, not MAY_HAVE_DEBUG_STMTS.
* cselib.c: Include tree.h with a FIXME.
* df-core.c (reg_obstack): Moved from cfg.c.
(dump_regset): Likewise.
(debug_regset): Likewise. Make a DEBUG_FUNCTION.
* final.c (compute_alignments): Call dump_reg_info before
dump_flow_info.
* function.c (function_name): New function.
(current_function_name): Use it.
* ifcvt.c (rest_of_handle_if_conversion): Call dump_reg_info before
dump_flow_info.
* ira-conflicts.c: Include tree.h with a note.
* regstat.c (dump_reg_info): Moved here from cfg.c.
* loop-init.c: Include regs.h instead of hard-reg-set.h.
(rtl_loop_init): Call dump_reg_info before dump_flow_info.
(rtl_loop_done): Likewise.
* mcf.c: Include tree.h before langhooks.h.
* predict.c (maybe_hot_count_p): Assert we have cfun.
(probably_never_executed_bb_p): Likewise.
* profile.c (compute_branch_probabilities): Use gimple_dump_cfg
instead of dump_flow_info.
* sched-deps.c: Include tree.h with a FIXME.
(call_may_noreturn_p): Add FIXME note why this function has to
look at function decls instead of function decl flags.
* sched-vis.c: Include tree.h with a FIXME.
(print_rtl_slim): Adjust dump_bb_info uses.
* statistics.c (statistics_fini_pass_2): Use current_function_name
to avoid including tree.h.
(statistics_counter_event): Use function_name for the same reason.
(statistics_histogram_event): Likewise.
* tracer.c (tracer): Remove bogus gcc_assert. Use brief_dump_cfg
instead of dump_flow_info.
* var-tracking.c (variable_tracking_main_1): Call dump_reg_info
before dump_flow_info.
* doc/cfg.texi: Update CFG documentation.
* Makefile.in (RTL_H): Depend on FLAGS_H.
(GIMPLE_H): Depend on TREE_H.
(FUNCTION_H): Depend on VEC_H, vecir.h, INPUT_H and MACHMODE_H,
but no longer on TREE_H.
(C_COMMON_H): Depend on TREE_H.
(cselib.o, cse.o, cfganal.o, loop-init.o, ira-conflicts.o,
sched-deps.o, sched-vis.o): Fixup dependencies.
c-family/
* c-common.h: Include tree.h.
cp/
* decl.c (cp_finish_decl): Add FIXME at add_local_decl call site.
From-SVN: r189359
Diffstat (limited to 'gcc/cfgrtl.c')
-rw-r--r-- | gcc/cfgrtl.c | 223 |
1 files changed, 220 insertions, 3 deletions
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 69cf86d..5959751 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -517,6 +517,107 @@ update_bb_for_insn (basic_block bb) } +/* Like active_insn_p, except keep the return value clobber around + even after reload. */ + +static bool +flow_active_insn_p (const_rtx insn) +{ + if (active_insn_p (insn)) + return true; + + /* A clobber of the function return value exists for buggy + programs that fail to return a value. Its effect is to + keep the return value from being live across the entire + function. If we allow it to be skipped, we introduce the + possibility for register lifetime confusion. */ + if (GET_CODE (PATTERN (insn)) == CLOBBER + && REG_P (XEXP (PATTERN (insn), 0)) + && REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0))) + return true; + + return false; +} + +/* Return true if the block has no effect and only forwards control flow to + its single destination. */ +/* FIXME: Make this a cfg hook. */ + +bool +forwarder_block_p (const_basic_block bb) +{ + rtx insn; + + if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR + || !single_succ_p (bb)) + return false; + + /* Protect loop latches, headers and preheaders. */ + if (current_loops) + { + basic_block dest; + if (bb->loop_father->header == bb) + return false; + dest = EDGE_SUCC (bb, 0)->dest; + if (dest->loop_father->header == dest) + return false; + } + + for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = NEXT_INSN (insn)) + if (INSN_P (insn) && flow_active_insn_p (insn)) + return false; + + return (!INSN_P (insn) + || (JUMP_P (insn) && simplejump_p (insn)) + || !flow_active_insn_p (insn)); +} + +/* Return nonzero if we can reach target from src by falling through. */ +/* FIXME: Make this a cfg hook. */ + +bool +can_fallthru (basic_block src, basic_block target) +{ + rtx insn = BB_END (src); + rtx insn2; + edge e; + edge_iterator ei; + + if (target == EXIT_BLOCK_PTR) + return true; + if (src->next_bb != target) + return 0; + FOR_EACH_EDGE (e, ei, src->succs) + if (e->dest == EXIT_BLOCK_PTR + && e->flags & EDGE_FALLTHRU) + return 0; + + insn2 = BB_HEAD (target); + if (insn2 && !active_insn_p (insn2)) + insn2 = next_active_insn (insn2); + + /* ??? Later we may add code to move jump tables offline. */ + return next_active_insn (insn) == insn2; +} + +/* Return nonzero if we could reach target from src by falling through, + if the target was made adjacent. If we already have a fall-through + edge to the exit block, we can't do that. */ +static bool +could_fall_through (basic_block src, basic_block target) +{ + edge e; + edge_iterator ei; + + if (target == EXIT_BLOCK_PTR) + return true; + FOR_EACH_EDGE (e, ei, src->succs) + if (e->dest == EXIT_BLOCK_PTR + && e->flags & EDGE_FALLTHRU) + return 0; + return true; +} + /* Return the NOTE_INSN_BASIC_BLOCK of BB. */ rtx bb_note (basic_block bb) @@ -1811,10 +1912,11 @@ print_rtl_with_bb (FILE *outf, const_rtx rtx_first) for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx)) { int did_output; + bool verbose = ((dump_flags & TDF_DETAILS) != 0); bb = start[INSN_UID (tmp_rtx)]; if (bb != NULL) - dump_bb_info (bb, true, false, dump_flags, ";; ", outf); + dump_bb_info (bb, true, false, verbose, ";; ", outf); if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB && !NOTE_P (tmp_rtx) @@ -1827,7 +1929,7 @@ print_rtl_with_bb (FILE *outf, const_rtx rtx_first) bb = end[INSN_UID (tmp_rtx)]; if (bb != NULL) - dump_bb_info (bb, false, true, dump_flags, ";; ", outf); + dump_bb_info (bb, false, true, verbose, ";; ", outf); if (did_output) putc ('\n', outf); } @@ -1846,6 +1948,115 @@ print_rtl_with_bb (FILE *outf, const_rtx rtx_first) } } +/* Emit basic block information for BB. HEADER is true if the user wants + the generic information and the predecessors, FOOTER is true if they want + the successors. If VERBOSE is true, emit global register liveness + information. PREFIX is put in front of every line. The output is emitted + to FILE. This function should only be called by RTL CFG users. */ +/* FIXME: Dumping of the basic block shared info (index, prev, next, etc.) + is done here and also in dump_bb_header (but to a pretty-printer buffer). + This should be re-factored to give similar dumps for RTL and GIMPLE. */ + +void +dump_bb_info (basic_block bb, bool header, bool footer, bool verbose, + const char *prefix, FILE *file) +{ + edge e; + edge_iterator ei; + + if (header) + { + fprintf (file, "\n%sBasic block %d ", prefix, bb->index); + if (bb->prev_bb) + fprintf (file, ", prev %d", bb->prev_bb->index); + if (bb->next_bb) + fprintf (file, ", next %d", bb->next_bb->index); + fprintf (file, ", loop_depth %d, count ", bb->loop_depth); + fprintf (file, HOST_WIDEST_INT_PRINT_DEC, bb->count); + fprintf (file, ", freq %i", bb->frequency); + if (maybe_hot_bb_p (bb)) + fputs (", maybe hot", file); + if (probably_never_executed_bb_p (bb)) + fputs (", probably never executed", file); + if (bb->flags) + { + static const char * const bits[] = { + "new", "reachable", "irr_loop", "superblock", "disable_sched", + "hot_partition", "cold_partition", "duplicated", + "non_local_goto_target", "rtl", "forwarder", "nonthreadable", + "modified" + }; + unsigned int flags; + + fputs (", flags:", file); + for (flags = bb->flags; flags ; flags &= flags - 1) + { + unsigned i = ctz_hwi (flags); + if (i < ARRAY_SIZE (bits)) + fprintf (file, " %s", bits[i]); + else + fprintf (file, " <%d>", i); + } + } + fputs (".\n", file); + + fprintf (file, "%sPredecessors: ", prefix); + FOR_EACH_EDGE (e, ei, bb->preds) + dump_edge_info (file, e, 0); + + if (verbose + && (bb->flags & BB_RTL) + && df) + { + putc ('\n', file); + df_dump_top (bb, file); + } + } + + if (footer) + { + fprintf (file, "\n%sSuccessors: ", prefix); + FOR_EACH_EDGE (e, ei, bb->succs) + dump_edge_info (file, e, 1); + + if (verbose + && (bb->flags & BB_RTL) + && df) + { + putc ('\n', file); + df_dump_bottom (bb, file); + } + } + + putc ('\n', file); +} + + +void +dump_flow_info (FILE *file, int flags) +{ + basic_block bb; + bool verbose = ((flags & TDF_DETAILS) != 0); + + fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges); + FOR_ALL_BB (bb) + { + dump_bb_info (bb, true, true, verbose, "", file); + check_bb_profile (bb, file); + } + + putc ('\n', file); +} + +void debug_flow_info (void); +DEBUG_FUNCTION void +debug_flow_info (void) +{ + dump_flow_info (stderr, TDF_DETAILS); +} + +/* Update the branch probability of BB if a REG_BR_PROB is present. */ + void update_br_prob_note (basic_block bb) { @@ -2893,7 +3104,13 @@ struct rtl_opt_pass pass_outof_cfg_layout_mode = some transformations while in cfglayout mode. The required sequence of the basic blocks is in a linked list along the bb->aux field. This functions re-links the basic block prev_bb and next_bb pointers - accordingly, and it compacts and renumbers the blocks. */ + accordingly, and it compacts and renumbers the blocks. + + FIXME: This currently works only for RTL, but the only RTL-specific + bits are the STAY_IN_CFGLAYOUT_MODE bits. The tracer pass was moved + to GIMPLE a long time ago, but it doesn't relink the basic block + chain. It could do that (to give better initial RTL) if this function + is made IR-agnostic (and moved to cfganal.c or cfg.c while at it). */ void relink_block_chain (bool stay_in_cfglayout_mode) |