aboutsummaryrefslogtreecommitdiff
path: root/gcc/cfgrtl.c
diff options
context:
space:
mode:
authorSteven Bosscher <steven@gcc.gnu.org>2012-07-08 10:06:14 +0000
committerSteven Bosscher <steven@gcc.gnu.org>2012-07-08 10:06:14 +0000
commit532aafaddbc0ec451f6301800ba4b0d3c7ddf8a9 (patch)
tree6449db5e8557f01213c64b681cc559f5835d3636 /gcc/cfgrtl.c
parent79bdca32d42fcd1a77fbb94826d22f020dca8829 (diff)
downloadgcc-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.c223
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)