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
This commit is contained in:
Steven Bosscher 2012-07-08 10:06:14 +00:00
parent 79bdca32d4
commit 532aafaddb
38 changed files with 749 additions and 642 deletions

View File

@ -1,3 +1,101 @@
2012-07-08 Steven Bosscher <steven@gcc.gnu.org>
* 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.
2012-07-08 Steven Bosscher <steven@gcc.gnu.org>
* alias.h: Do not include coretypes.h in header files.

View File

@ -859,7 +859,7 @@ RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
$(FIXED_VALUE_H) alias.h $(HASHTAB_H)
FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
RTL_H = $(RTL_BASE_H) genrtl.h vecir.h
RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h vecir.h
RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
PARAMS_H = params.h params.def
@ -875,7 +875,7 @@ TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) cfghooks.h
GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \
vecir.h $(GGC_H) $(BASIC_BLOCK_H) tree-ssa-operands.h \
vecir.h $(GGC_H) $(BASIC_BLOCK_H) $(TREE_H) tree-ssa-operands.h \
tree-ssa-alias.h $(INTERNAL_FN_H)
TRANS_MEM_H = trans-mem.h
GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h
@ -886,7 +886,8 @@ ALIAS_H = alias.h
EMIT_RTL_H = emit-rtl.h
FLAGS_H = flags.h flag-types.h $(OPTIONS_H)
OPTIONS_H = options.h flag-types.h $(OPTIONS_H_EXTRA)
FUNCTION_H = function.h $(TREE_H) $(HASHTAB_H) vecprim.h $(TM_H) hard-reg-set.h
FUNCTION_H = function.h $(HASHTAB_H) vecprim.h $(TM_H) hard-reg-set.h \
$(VEC_H) vecir.h $(INPUT_H) $(MACHMODE_H)
EXPR_H = expr.h insn-config.h $(FUNCTION_H) $(RTL_H) $(FLAGS_H) $(TREE_H) $(MACHMODE_H) $(EMIT_RTL_H)
OPTABS_H = optabs.h insn-codes.h
REGS_H = regs.h $(MACHMODE_H) hard-reg-set.h
@ -911,7 +912,7 @@ GGC_INTERNAL_H = ggc-internal.h $(GGC_H)
TIMEVAR_H = timevar.h timevar.def
INSN_ATTR_H = insn-attr.h insn-attr-common.h $(INSN_ADDR_H)
INSN_ADDR_H = $(srcdir)/insn-addr.h vecprim.h
C_COMMON_H = c-family/c-common.h c-family/c-common.def \
C_COMMON_H = c-family/c-common.h c-family/c-common.def $(TREE_H) \
$(SPLAY_TREE_H) $(CPPLIB_H) $(GGC_H) $(DIAGNOSTIC_CORE_H)
C_PRAGMA_H = c-family/c-pragma.h $(CPPLIB_H)
C_TREE_H = c-tree.h $(C_COMMON_H) $(DIAGNOSTIC_H)
@ -2937,7 +2938,7 @@ cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h $(RECOG_H) \
$(EMIT_RTL_H) $(DIAGNOSTIC_CORE_H) $(FUNCTION_H) $(TREE_PASS_H) \
cselib.h gt-cselib.h $(GGC_H) $(TM_P_H) $(PARAMS_H) alloc-pool.h \
$(HASHTAB_H) $(TARGET_H) $(BITMAP_H)
$(HASHTAB_H) $(TARGET_H) $(BITMAP_H) $(TREE_H)
cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h $(FLAGS_H) insn-config.h $(RECOG_H) $(EXPR_H) toplev.h $(DIAGNOSTIC_CORE_H) \
$(FUNCTION_H) $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \
@ -3076,10 +3077,8 @@ auto-inc-dec.o : auto-inc-dec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(RTL_H) $(TM_P_H) hard-reg-set.h $(BASIC_BLOCK_H) insn-config.h \
$(REGS_H) $(FLAGS_H) $(FUNCTION_H) $(EXCEPT_H) $(DIAGNOSTIC_CORE_H) $(RECOG_H) \
$(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) $(TARGET_H)
cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \
$(REGS_H) hard-reg-set.h $(DIAGNOSTIC_CORE_H) $(FUNCTION_H) $(EXCEPT_H) $(GGC_H) \
$(TM_P_H) $(TIMEVAR_H) $(OBSTACK_H) $(TREE_H) alloc-pool.h \
$(HASHTAB_H) $(DF_H) $(CFGLOOP_H) $(TREE_FLOW_H) $(TREE_PASS_H)
cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(DIAGNOSTIC_CORE_H) $(GGC_H) \
$(OBSTACK_H) alloc-pool.h $(HASHTAB_H) $(CFGLOOP_H) $(BASIC_BLOCK_H)
cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TIMEVAR_H) toplev.h $(DIAGNOSTIC_CORE_H) $(CFGLOOP_H)
cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
@ -3095,10 +3094,8 @@ cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ERROR_H) \
insn-config.h $(EXPR_H) \
$(CFGLOOP_H) $(OBSTACK_H) $(TARGET_H) $(TREE_H) \
$(TREE_PASS_H) $(DF_H) $(GGC_H) $(COMMON_TARGET_H) gt-cfgrtl.h
cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(BASIC_BLOCK_H) hard-reg-set.h insn-config.h $(RECOG_H) $(TM_P_H) \
$(TIMEVAR_H) $(OBSTACK_H) $(DIAGNOSTIC_CORE_H) vecprim.h sbitmap.h \
$(BITMAP_H) $(CFGLOOP_H)
cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(BASIC_BLOCK_H) \
$(TIMEVAR_H) vecprim.h sbitmap.h $(BITMAP_H)
cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(FLAGS_H) $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h $(DIAGNOSTIC_CORE_H) \
$(FUNCTION_H) $(EXCEPT_H) $(TIMEVAR_H) $(TREE_H) $(EXPR_H) sbitmap.h
@ -3129,7 +3126,7 @@ cfgloopmanip.o : cfgloopmanip.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
loop-init.o : loop-init.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(GGC_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) \
coretypes.h $(TM_H) $(OBSTACK_H) $(TREE_PASS_H) $(TIMEVAR_H) $(FLAGS_H) \
$(DF_H)
$(REGS_H) $(DF_H)
loop-unswitch.o : loop-unswitch.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(PARAMS_H) \
$(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H)
@ -3212,7 +3209,7 @@ ira-costs.o: ira-costs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(REGS_H) addresses.h insn-config.h $(RECOG_H) $(DIAGNOSTIC_CORE_H) $(TARGET_H) \
$(PARAMS_H) $(IRA_INT_H) reload.h
ira-conflicts.o: ira-conflicts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
$(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(TREE_H) $(FLAGS_H) \
insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(PARAMS_H) \
$(DF_H) sparseset.h addresses.h $(IRA_INT_H)
ira-color.o: ira-color.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
@ -3263,7 +3260,7 @@ haifa-sched.o : haifa-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_
sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
$(FUNCTION_H) $(INSN_ATTR_H) $(DIAGNOSTIC_CORE_H) $(RECOG_H) $(EXCEPT_H) cselib.h \
ira.h $(PARAMS_H) $(TM_P_H) ira.h $(TARGET_H)
ira.h $(PARAMS_H) $(TM_P_H) ira.h $(TARGET_H) $(TREE_H)
sched-rgn.o : sched-rgn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
$(FUNCTION_H) $(INSN_ATTR_H) $(DIAGNOSTIC_CORE_H) $(RECOG_H) $(EXCEPT_H) $(PARAMS_H) \
@ -3275,7 +3272,7 @@ sched-ebb.o : sched-ebb.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(PARAMS_H) $(TARGET_H)
sched-vis.o : sched-vis.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(SCHED_INT_H) hard-reg-set.h $(BASIC_BLOCK_H) $(OBSTACK_H) \
$(TREE_PASS_H) $(INSN_ATTR_H)
$(TREE_PASS_H) $(INSN_ATTR_H) $(TREE_H)
sel-sched.o : sel-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_ERROR_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
$(FUNCTION_H) $(INSN_ATTR_H) $(RECOG_H) $(EXCEPT_H) $(PARAMS_H) \

View File

@ -448,10 +448,6 @@ basic_block split_edge_and_insert (edge, rtx);
extern void commit_one_edge_insertion (edge e);
extern void commit_edge_insertions (void);
extern void remove_fake_edges (void);
extern void remove_fake_exit_edges (void);
extern void add_noreturn_fake_exit_edges (void);
extern void connect_infinite_loops_to_exit (void);
extern edge unchecked_make_edge (basic_block, basic_block, int);
extern edge cached_make_edge (sbitmap, basic_block, basic_block, int);
extern edge make_edge (basic_block, basic_block, int);
@ -462,15 +458,7 @@ 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 int post_order_compute (int *, bool, bool);
extern int inverted_post_order_compute (int *);
extern int pre_and_rev_post_order_compute (int *, int *, bool);
extern int dfs_enumerate_from (basic_block, int,
bool (*)(const_basic_block, const void *),
basic_block *, int, const void *);
extern void compute_dominance_frontiers (struct bitmap_head_def *);
extern bitmap compute_idf (bitmap, struct bitmap_head_def *);
extern void dump_bb_info (basic_block, bool, bool, int, const char *, FILE *);
extern void dump_bb_info (basic_block, bool, bool, bool, const char *, FILE *);
extern void dump_edge_info (FILE *, edge, int);
extern void brief_dump_cfg (FILE *);
extern void clear_edges (void);
@ -501,9 +489,9 @@ typedef struct ce_if_block
} ce_if_block_t;
/* This structure maintains an edge list vector. */
/* FIXME: Make this a VEC(edge). */
struct edge_list
{
int num_blocks;
int num_edges;
edge *index_to_edge;
};
@ -734,13 +722,6 @@ ei_cond (edge_iterator ei, edge *p)
ei_cond ((ITER), &(EDGE)); \
ei_next (&(ITER)))
struct edge_list * create_edge_list (void);
void free_edge_list (struct edge_list *);
void print_edge_list (FILE *, struct edge_list *);
void verify_edge_list (FILE *, struct edge_list *);
int find_edge_index (struct edge_list *, basic_block, basic_block);
edge find_edge (basic_block, basic_block);
#define CLEANUP_EXPENSIVE 1 /* Do relatively expensive optimizations
except for edge forwarding */
#define CLEANUP_CROSSJUMP 2 /* Do crossjumping. */
@ -789,6 +770,7 @@ extern bool predictable_edge_p (edge);
extern void init_flow (struct function *);
extern void debug_bb (basic_block);
extern basic_block debug_bb_n (int);
extern void dump_flow_info (FILE *, int);
extern void expunge_block (basic_block);
extern void link_block (basic_block, basic_block);
extern void unlink_block (basic_block);
@ -804,11 +786,25 @@ extern void free_aux_for_edges (void);
/* In cfganal.c */
extern void find_unreachable_blocks (void);
extern bool forwarder_block_p (const_basic_block);
extern bool can_fallthru (basic_block, basic_block);
extern bool could_fall_through (basic_block, basic_block);
extern void flow_nodes_print (const char *, const_sbitmap, FILE *);
extern void flow_edge_list_print (const char *, const edge *, int, FILE *);
extern bool mark_dfs_back_edges (void);
struct edge_list * create_edge_list (void);
void free_edge_list (struct edge_list *);
void print_edge_list (FILE *, struct edge_list *);
void verify_edge_list (FILE *, struct edge_list *);
int find_edge_index (struct edge_list *, basic_block, basic_block);
edge find_edge (basic_block, basic_block);
extern void remove_fake_edges (void);
extern void remove_fake_exit_edges (void);
extern void add_noreturn_fake_exit_edges (void);
extern void connect_infinite_loops_to_exit (void);
extern int post_order_compute (int *, bool, bool);
extern int inverted_post_order_compute (int *);
extern int pre_and_rev_post_order_compute (int *, int *, bool);
extern int dfs_enumerate_from (basic_block, int,
bool (*)(const_basic_block, const void *),
basic_block *, int, const void *);
extern void compute_dominance_frontiers (struct bitmap_head_def *);
extern bitmap compute_idf (bitmap, struct bitmap_head_def *);
/* In cfgrtl.c */
extern rtx block_label (basic_block);
@ -817,6 +813,8 @@ extern bool purge_all_dead_edges (void);
extern bool purge_dead_edges (basic_block);
extern bool fixup_abnormal_edges (void);
extern basic_block force_nonfallthru_and_redirect (edge, basic_block, rtx);
extern bool forwarder_block_p (const_basic_block);
extern bool can_fallthru (basic_block, basic_block);
/* In cfgbuild.c. */
extern void find_many_sub_basic_blocks (sbitmap);
@ -833,8 +831,6 @@ extern int flow_find_head_matching_sequence (basic_block, basic_block,
extern bool delete_unreachable_blocks (void);
extern bool mark_dfs_back_edges (void);
extern void set_edge_can_fallthru_flag (void);
extern void update_br_prob_note (basic_block);
extern bool inside_basic_block_p (const_rtx);
extern bool control_flow_insn_p (const_rtx);

View File

@ -1384,6 +1384,41 @@ find_rarely_executed_basic_blocks_and_crossing_edges (void)
return crossing_edges;
}
/* Set the flag EDGE_CAN_FALLTHRU for edges that can be fallthru. */
static void
set_edge_can_fallthru_flag (void)
{
basic_block bb;
FOR_EACH_BB (bb)
{
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
{
e->flags &= ~EDGE_CAN_FALLTHRU;
/* The FALLTHRU edge is also CAN_FALLTHRU edge. */
if (e->flags & EDGE_FALLTHRU)
e->flags |= EDGE_CAN_FALLTHRU;
}
/* If the BB ends with an invertible condjump all (2) edges are
CAN_FALLTHRU edges. */
if (EDGE_COUNT (bb->succs) != 2)
continue;
if (!any_condjump_p (BB_END (bb)))
continue;
if (!invert_jump (BB_END (bb), JUMP_LABEL (BB_END (bb)), 0))
continue;
invert_jump (BB_END (bb), JUMP_LABEL (BB_END (bb)), 0);
EDGE_SUCC (bb, 0)->flags |= EDGE_CAN_FALLTHRU;
EDGE_SUCC (bb, 1)->flags |= EDGE_CAN_FALLTHRU;
}
}
/* If any destination of a crossing edge does not have a label, add label;
Convert any easy fall-through crossing edges to unconditional jumps. */
@ -1959,7 +1994,11 @@ reorder_basic_blocks (void)
relink_block_chain (/*stay_in_cfglayout_mode=*/true);
if (dump_file)
dump_flow_info (dump_file, dump_flags);
{
if (dump_flags & TDF_DETAILS)
dump_reg_info (dump_file);
dump_flow_info (dump_file, dump_flags);
}
if (flag_reorder_blocks_and_partition)
verify_hot_cold_block_grouping ();

View File

@ -1,3 +1,7 @@
2012-07-08 Steven Bosscher <steven@gcc.gnu.org>
* c-common.h: Include tree.h.
2012-07-02 Jason Merrill <jason@redhat.com>
PR c++/53524

View File

@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "splay-tree.h"
#include "cpplib.h"
#include "ggc.h"
#include "tree.h"
/* In order for the format checking to accept the C frontend
diagnostic framework extensions, you must include this file before

272
gcc/cfg.c
View File

@ -43,37 +43,22 @@ along with GCC; see the file COPYING3. If not see
verify_flow_info
- Dumping and debugging
print_rtl_with_bb, dump_bb, debug_bb, debug_bb_n
TODO: Document these "Available functionality" functions in the files
that implement them.
*/
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "flags.h"
#include "function.h"
#include "except.h"
#include "diagnostic-core.h"
#include "tm_p.h"
#include "obstack.h"
#include "timevar.h"
#include "tree-pass.h"
#include "ggc.h"
#include "hashtab.h"
#include "alloc-pool.h"
#include "basic-block.h"
#include "df.h"
#include "cfgloop.h"
#include "tree-flow.h"
#include "cfgloop.h" /* FIXME: For struct loop. */
/* The obstack on which the flow graph components are allocated. */
struct bitmap_obstack reg_obstack;
void debug_flow_info (void);
static void free_edge (edge);
#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
@ -98,10 +83,10 @@ init_flow (struct function *the_fun)
}
/* Helper function for remove_edge and clear_edges. Frees edge structure
without actually unlinking it from the pred/succ lists. */
without actually removing it from the pred/succ arrays. */
static void
free_edge (edge e ATTRIBUTE_UNUSED)
free_edge (edge e)
{
n_edges--;
ggc_free (e);
@ -363,9 +348,6 @@ remove_edge_raw (edge e)
disconnect_src (e);
disconnect_dest (e);
/* This is probably not needed, but it doesn't hurt. */
redirect_edge_var_map_clear (e);
free_edge (e);
}
@ -386,31 +368,6 @@ redirect_edge_succ (edge e, basic_block new_succ)
execute_on_growing_pred (e);
}
/* Like previous but avoid possible duplicate edge. */
edge
redirect_edge_succ_nodup (edge e, basic_block new_succ)
{
edge s;
s = find_edge (e->src, new_succ);
if (s && s != e)
{
s->flags |= e->flags;
s->probability += e->probability;
if (s->probability > REG_BR_PROB_BASE)
s->probability = REG_BR_PROB_BASE;
s->count += e->count;
redirect_edge_var_map_dup (s, e);
remove_edge (e);
e = s;
}
else
redirect_edge_succ (e, new_succ);
return e;
}
/* Redirect an edge's predecessor from one block to another. */
void
@ -485,222 +442,15 @@ check_bb_profile (basic_block bb, FILE * file)
}
}
/* Write information about registers and basic blocks into FILE.
This is part of making a debugging dump. */
void
dump_regset (regset r, FILE *outf)
{
unsigned i;
reg_set_iterator rsi;
if (r == NULL)
{
fputs (" (nil)", outf);
return;
}
EXECUTE_IF_SET_IN_REG_SET (r, 0, i, rsi)
{
fprintf (outf, " %d", i);
if (i < FIRST_PSEUDO_REGISTER)
fprintf (outf, " [%s]",
reg_names[i]);
}
}
/* Print a human-readable representation of R on the standard error
stream. This function is designed to be used from within the
debugger. */
DEBUG_FUNCTION void
debug_regset (regset r)
{
dump_regset (r, stderr);
putc ('\n', stderr);
}
/* 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. FLAGS is the dump flags of interest; TDF_DETAILS emit
global register liveness information. PREFIX is put in front of every
line. The output is emitted to FILE. */
void
dump_bb_info (basic_block bb, bool header, bool footer, int flags,
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);
/* Both maybe_hot_bb_p & probably_never_executed_bb_p functions
crash without cfun. */
if (cfun && maybe_hot_bb_p (bb))
fputs (", maybe hot", file);
if (cfun && 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 ((flags & TDF_DETAILS)
&& (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 ((flags & TDF_DETAILS)
&& (bb->flags & BB_RTL)
&& df)
{
putc ('\n', file);
df_dump_bottom (bb, file);
}
}
putc ('\n', file);
}
/* Dump the register info to FILE. */
void
dump_reg_info (FILE *file)
{
unsigned int i, max = max_reg_num ();
if (reload_completed)
return;
if (reg_info_p_size < max)
max = reg_info_p_size;
fprintf (file, "%d registers.\n", max);
for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
{
enum reg_class rclass, altclass;
if (regstat_n_sets_and_refs)
fprintf (file, "\nRegister %d used %d times across %d insns",
i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
else if (df)
fprintf (file, "\nRegister %d used %d times across %d insns",
i, DF_REG_USE_COUNT (i) + DF_REG_DEF_COUNT (i), REG_LIVE_LENGTH (i));
if (REG_BASIC_BLOCK (i) >= NUM_FIXED_BLOCKS)
fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
if (regstat_n_sets_and_refs)
fprintf (file, "; set %d time%s", REG_N_SETS (i),
(REG_N_SETS (i) == 1) ? "" : "s");
else if (df)
fprintf (file, "; set %d time%s", DF_REG_DEF_COUNT (i),
(DF_REG_DEF_COUNT (i) == 1) ? "" : "s");
if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i]))
fputs ("; user var", file);
if (REG_N_DEATHS (i) != 1)
fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
if (REG_N_CALLS_CROSSED (i) == 1)
fputs ("; crosses 1 call", file);
else if (REG_N_CALLS_CROSSED (i))
fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
if (REG_FREQ_CALLS_CROSSED (i))
fprintf (file, "; crosses call with %d frequency", REG_FREQ_CALLS_CROSSED (i));
if (regno_reg_rtx[i] != NULL
&& PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
rclass = reg_preferred_class (i);
altclass = reg_alternate_class (i);
if (rclass != GENERAL_REGS || altclass != ALL_REGS)
{
if (altclass == ALL_REGS || rclass == ALL_REGS)
fprintf (file, "; pref %s", reg_class_names[(int) rclass]);
else if (altclass == NO_REGS)
fprintf (file, "; %s or none", reg_class_names[(int) rclass]);
else
fprintf (file, "; pref %s, else %s",
reg_class_names[(int) rclass],
reg_class_names[(int) altclass]);
}
if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i]))
fputs ("; pointer", file);
fputs (".\n", file);
}
}
void
dump_flow_info (FILE *file, int flags)
{
basic_block bb;
/* There are no pseudo registers after reload. Don't dump them. */
if (reg_info_p_size && (flags & TDF_DETAILS) != 0)
dump_reg_info (file);
fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
FOR_ALL_BB (bb)
{
dump_bb_info (bb, true, true, flags, "", file);
check_bb_profile (bb, file);
}
putc ('\n', file);
}
DEBUG_FUNCTION void
debug_flow_info (void)
{
dump_flow_info (stderr, TDF_DETAILS);
}
void
dump_edge_info (FILE *file, edge e, int do_succ)
{
basic_block side = (do_succ ? e->dest : e->src);
/* both ENTRY_BLOCK_PTR & EXIT_BLOCK_PTR depend upon cfun. */
if (cfun && side == ENTRY_BLOCK_PTR)
/* ENTRY_BLOCK_PTR/EXIT_BLOCK_PTR depend on cfun.
Compare against ENTRY_BLOCK/EXIT_BLOCK to avoid that dependency. */
if (side->index == ENTRY_BLOCK)
fputs (" ENTRY", file);
else if (cfun && side == EXIT_BLOCK_PTR)
else if (side->index == EXIT_BLOCK)
fputs (" EXIT", file);
else
fprintf (file, " %d", side->index);

View File

@ -1,7 +1,5 @@
/* Control flow graph analysis code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2010
Free Software Foundation, Inc.
Copyright (C) 1987-2012 Free Software Foundation, Inc.
This file is part of GCC.
@ -20,24 +18,16 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* This file contains various simple utilities to analyze the CFG. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "obstack.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "insn-config.h"
#include "recog.h"
#include "diagnostic-core.h"
#include "tm_p.h"
#include "vec.h"
#include "vecprim.h"
#include "bitmap.h"
#include "sbitmap.h"
#include "timevar.h"
#include "cfgloop.h"
/* Store the data structures necessary for depth-first search. */
struct depth_first_search_dsS {
@ -59,106 +49,6 @@ static void flow_dfs_compute_reverse_add_bb (depth_first_search_ds,
static basic_block flow_dfs_compute_reverse_execute (depth_first_search_ds,
basic_block);
static void flow_dfs_compute_reverse_finish (depth_first_search_ds);
static bool flow_active_insn_p (const_rtx);
/* 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. */
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. */
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. */
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;
}
/* Mark the back edges in DFS traversal.
Return nonzero if a loop (natural or otherwise) is present.
@ -252,41 +142,6 @@ mark_dfs_back_edges (void)
return found;
}
/* Set the flag EDGE_CAN_FALLTHRU for edges that can be fallthru. */
void
set_edge_can_fallthru_flag (void)
{
basic_block bb;
FOR_EACH_BB (bb)
{
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
{
e->flags &= ~EDGE_CAN_FALLTHRU;
/* The FALLTHRU edge is also CAN_FALLTHRU edge. */
if (e->flags & EDGE_FALLTHRU)
e->flags |= EDGE_CAN_FALLTHRU;
}
/* If the BB ends with an invertible condjump all (2) edges are
CAN_FALLTHRU edges. */
if (EDGE_COUNT (bb->succs) != 2)
continue;
if (!any_condjump_p (BB_END (bb)))
continue;
if (!invert_jump (BB_END (bb), JUMP_LABEL (BB_END (bb)), 0))
continue;
invert_jump (BB_END (bb), JUMP_LABEL (BB_END (bb)), 0);
EDGE_SUCC (bb, 0)->flags |= EDGE_CAN_FALLTHRU;
EDGE_SUCC (bb, 1)->flags |= EDGE_CAN_FALLTHRU;
}
}
/* Find unreachable blocks. An unreachable block will have 0 in
the reachable bit in block->flags. A nonzero value indicates the
block is reachable. */
@ -357,23 +212,18 @@ create_edge_list (void)
struct edge_list *elist;
edge e;
int num_edges;
int block_count;
basic_block bb;
edge_iterator ei;
block_count = n_basic_blocks; /* Include the entry and exit blocks. */
num_edges = 0;
/* Determine the number of edges in the flow graph by counting successor
edges on each basic block. */
num_edges = 0;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
num_edges += EDGE_COUNT (bb->succs);
}
elist = XNEW (struct edge_list);
elist->num_blocks = block_count;
elist->num_edges = num_edges;
elist->index_to_edge = XNEWVEC (edge, num_edges);
@ -407,7 +257,7 @@ print_edge_list (FILE *f, struct edge_list *elist)
int x;
fprintf (f, "Compressed edge list, %d BBs + entry & exit, and %d edges\n",
elist->num_blocks, elist->num_edges);
n_basic_blocks, elist->num_edges);
for (x = 0; x < elist->num_edges; x++)
{
@ -459,7 +309,7 @@ verify_edge_list (FILE *f, struct edge_list *elist)
}
/* We've verified that all the edges are in the list, now lets make sure
there are no spurious edges in the list. */
there are no spurious edges in the list. This is an expensive check! */
FOR_BB_BETWEEN (p, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
FOR_BB_BETWEEN (s, ENTRY_BLOCK_PTR->next_bb, NULL, next_bb)
@ -531,42 +381,6 @@ find_edge_index (struct edge_list *edge_list, basic_block pred, basic_block succ
return (EDGE_INDEX_NO_EDGE);
}
/* Dump the list of basic blocks in the bitmap NODES. */
void
flow_nodes_print (const char *str, const_sbitmap nodes, FILE *file)
{
unsigned int node = 0;
sbitmap_iterator sbi;
if (! nodes)
return;
fprintf (file, "%s { ", str);
EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, node, sbi)
fprintf (file, "%d ", node);
fputs ("}\n", file);
}
/* Dump the list of edges in the array EDGE_LIST. */
void
flow_edge_list_print (const char *str, const edge *edge_list, int num_edges, FILE *file)
{
int i;
if (! edge_list)
return;
fprintf (file, "%s { ", str);
for (i = 0; i < num_edges; i++)
fprintf (file, "%d->%d ", edge_list[i]->src->index,
edge_list[i]->dest->index);
fputs ("}\n", file);
}
/* This routine will remove any fake predecessor edges for a basic block.
When the edge is removed, it is also removed from whatever successor
@ -843,7 +657,7 @@ inverted_post_order_compute (int *post_order)
sbitmap_zero (visited);
/* Put all blocks that have no successor into the initial work list. */
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
FOR_ALL_BB (bb)
if (EDGE_COUNT (bb->succs) == 0)
{
/* Push the initial edge on to the stack. */

View File

@ -2797,7 +2797,7 @@ delete_unreachable_blocks (void)
have dominators information, walking blocks backward gets us a
better chance of retaining most debug information than
otherwise. */
if (MAY_HAVE_DEBUG_STMTS && current_ir_type () == IR_GIMPLE
if (MAY_HAVE_DEBUG_INSNS && current_ir_type () == IR_GIMPLE
&& dom_info_available_p (CDI_DOMINATORS))
{
for (b = EXIT_BLOCK_PTR->prev_bb; b != ENTRY_BLOCK_PTR; b = prev_bb)

View File

@ -377,9 +377,40 @@ remove_edge (edge e)
if (current_loops != NULL)
rescan_loop_exit (e, false, true);
/* This is probably not needed, but it doesn't hurt. */
/* FIXME: This should be called via a remove_edge hook. */
if (current_ir_type () == IR_GIMPLE)
redirect_edge_var_map_clear (e);
remove_edge_raw (e);
}
/* Like redirect_edge_succ but avoid possible duplicate edge. */
edge
redirect_edge_succ_nodup (edge e, basic_block new_succ)
{
edge s;
s = find_edge (e->src, new_succ);
if (s && s != e)
{
s->flags |= e->flags;
s->probability += e->probability;
if (s->probability > REG_BR_PROB_BASE)
s->probability = REG_BR_PROB_BASE;
s->count += e->count;
/* FIXME: This should be called via a hook and only for IR_GIMPLE. */
redirect_edge_var_map_dup (s, e);
remove_edge (e);
e = s;
}
else
redirect_edge_succ (e, new_succ);
return e;
}
/* 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. */

View File

@ -516,6 +516,107 @@ update_bb_for_insn (basic_block bb)
update_bb_for_insn_chain (BB_HEAD (bb), BB_END (bb), 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
@ -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)

View File

@ -1,3 +1,7 @@
2012-07-08 Steven Bosscher <steven@gcc.gnu.org>
* decl.c (cp_finish_decl): Add FIXME at add_local_decl call site.
2012-07-06 Jason Merrill <jason@redhat.com>
PR c++/53862

View File

@ -6190,7 +6190,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
/* Normally local_decls is populated during GIMPLE lowering,
but [cd]tors are never actually compiled directly. We need
to put statics on the list so we can deal with the label
address extension. */
address extension. FIXME. */
add_local_decl (cfun, decl);
}

View File

@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "rtl.h"
#include "tree.h"/* FIXME: For hashing DEBUG_EXPR & friends. */
#include "tm_p.h"
#include "regs.h"
#include "hard-reg-set.h"

View File

@ -403,6 +403,9 @@ static void df_clear_bb_info (struct dataflow *, unsigned int);
static void df_set_clean_cfg (void);
#endif
/* The obstack on which regsets are allocated. */
struct bitmap_obstack reg_obstack;
/* An obstack for bitmap not related to specific dataflow problems.
This obstack should e.g. be used for bitmaps with a short life time
such as temporary bitmaps. */
@ -1860,6 +1863,40 @@ df_reg_used (rtx insn, rtx reg)
Debugging and printing functions.
----------------------------------------------------------------------------*/
/* Write information about registers and basic blocks into FILE.
This is part of making a debugging dump. */
void
dump_regset (regset r, FILE *outf)
{
unsigned i;
reg_set_iterator rsi;
if (r == NULL)
{
fputs (" (nil)", outf);
return;
}
EXECUTE_IF_SET_IN_REG_SET (r, 0, i, rsi)
{
fprintf (outf, " %d", i);
if (i < FIRST_PSEUDO_REGISTER)
fprintf (outf, " [%s]",
reg_names[i]);
}
}
/* Print a human-readable representation of R on the standard error
stream. This function is designed to be used from within the
debugger. */
extern void debug_regset (regset);
DEBUG_FUNCTION void
debug_regset (regset r)
{
dump_regset (r, stderr);
putc ('\n', stderr);
}
/* Write information about registers and basic blocks into FILE.
This is part of making a debugging dump. */

View File

@ -1,6 +1,5 @@
@c -*-texinfo-*-
@c Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008 Free Software
@c Foundation, Inc.
@c Copyright (C) 2001-2012 Free Software Foundation, Inc.
@c This is part of the GCC manual.
@c For copying conditions, see the file gcc.texi.
@ -14,7 +13,7 @@
@findex basic-block.h
A control flow graph (CFG) is a data structure built on top of the
intermediate code representation (the RTL or @code{tree} instruction
intermediate code representation (the RTL or @code{GIMPLE} instruction
stream) abstracting the control flow behavior of a function that is
being compiled. The CFG is a directed graph where the vertices
represent basic blocks and edges represent possible transfer of
@ -22,6 +21,20 @@ control flow from one basic block to another. The data structures
used to represent the control flow graph are defined in
@file{basic-block.h}.
In GCC, the representation of control flow is maintained throughout
the compilation process, from constructing the CFG early in
@code{pass_build_cfg} to @code{pass_free_cfg} (see @file{passes.c}).
The CFG takes various different modes and may undergo extensive
manipulations, but the graph is always valid between its construction
and its release. This way, transfer of information such as data flow,
a measured profile, or the loop tree, can be propagated through the
passes pipeline, and even from @code{GIMPLE} to @code{RTL}.
Often the CFG may be better viewed as integral part of instruction
chain, than structure built on the top of it. Updating the compiler's
intermediate representation for instructions can not be easily done
without proper maintenance of the CFG simultaneously.
@menu
* Basic Blocks:: The definition and representation of basic blocks.
* Edges:: Types of edges and their representation.
@ -40,16 +53,10 @@ A basic block is a straight-line sequence of code with only one entry
point and only one exit. In GCC, basic blocks are represented using
the @code{basic_block} data type.
@findex next_bb, prev_bb, FOR_EACH_BB
Two pointer members of the @code{basic_block} structure are the
pointers @code{next_bb} and @code{prev_bb}. These are used to keep
doubly linked chain of basic blocks in the same order as the
underlying instruction stream. The chain of basic blocks is updated
transparently by the provided API for manipulating the CFG@. The macro
@code{FOR_EACH_BB} can be used to visit all the basic blocks in
lexicographical order. Dominator traversals are also possible using
@code{walk_dominator_tree}. Given two basic blocks A and B, block A
dominates block B if A is @emph{always} executed before B@.
@findex ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR
Special basic blocks represent possible entry and exit points of a
function. These blocks are called @code{ENTRY_BLOCK_PTR} and
@code{EXIT_BLOCK_PTR}. These blocks do not contain any code.
@findex BASIC_BLOCK
The @code{BASIC_BLOCK} array contains all basic blocks in an
@ -61,39 +68,61 @@ The total number of basic blocks in the function is
the total number of basic blocks may vary during the compilation
process, as passes reorder, create, duplicate, and destroy basic
blocks. The index for any block should never be greater than
@code{last_basic_block}.
@code{last_basic_block}. The indices 0 and 1 are special codes
reserved for @code{ENTRY_BLOCK} and @code{EXIT_BLOCK}, the
indices of @code{ENTRY_BLOCK_PTR} and @code{EXIT_BLOCK_PTR}.
@findex ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR
Special basic blocks represent possible entry and exit points of a
function. These blocks are called @code{ENTRY_BLOCK_PTR} and
@code{EXIT_BLOCK_PTR}. These blocks do not contain any code, and are
not elements of the @code{BASIC_BLOCK} array. Therefore they have
been assigned unique, negative index numbers.
@findex next_bb, prev_bb, FOR_EACH_BB, FOR_ALL_BB
Two pointer members of the @code{basic_block} structure are the
pointers @code{next_bb} and @code{prev_bb}. These are used to keep
doubly linked chain of basic blocks in the same order as the
underlying instruction stream. The chain of basic blocks is updated
transparently by the provided API for manipulating the CFG@. The macro
@code{FOR_EACH_BB} can be used to visit all the basic blocks in
lexicographical order, except @code{ENTRY_BLOCK} and @code{EXIT_BLOCK}.
The macro @code{FOR_ALL_BB} also visits all basic blocks in
lexicographical order, including @code{ENTRY_BLOCK} and @code{EXIT_BLOCK}.
@findex post_order_compute, inverted_post_order_compute, walk_dominator_tree
The functions @code{post_order_compute} and @code{inverted_post_order_compute}
can be used to compute topological orders of the CFG. The orders are
stored as vectors of basic block indices. The @code{BASIC_BLOCK} array
can be used to iterate each basic block by index.
Dominator traversals are also possible using
@code{walk_dominator_tree}. Given two basic blocks A and B, block A
dominates block B if A is @emph{always} executed before B@.
Each @code{basic_block} also contains pointers to the first
instruction (the @dfn{head}) and the last instruction (the @dfn{tail})
or @dfn{end} of the instruction stream contained in a basic block. In
fact, since the @code{basic_block} data type is used to represent
blocks in both major intermediate representations of GCC (@code{tree}
blocks in both major intermediate representations of GCC (@code{GIMPLE}
and RTL), there are pointers to the head and end of a basic block for
both representations.
both representations, stored in intermediate representation specific
data in the @code{il} field of @code{struct basic_block_def}.
@findex NOTE_INSN_BASIC_BLOCK, CODE_LABEL, notes
For RTL, these pointers are @code{rtx head, end}. In the RTL function
representation, the head pointer always points either to a
@code{NOTE_INSN_BASIC_BLOCK} or to a @code{CODE_LABEL}, if present.
@findex CODE_LABEL
@findex NOTE_INSN_BASIC_BLOCK
For RTL, these pointers are @code{BB_HEAD} and @code{BB_END}.
@cindex insn notes, notes
@findex NOTE_INSN_BASIC_BLOCK
In the RTL representation of a function, the instruction stream
contains not only the ``real'' instructions, but also @dfn{notes}.
contains not only the ``real'' instructions, but also @dfn{notes}
or @dfn{insn notes} (to distinguish them from @dfn{reg notes}).
Any function that moves or duplicates the basic blocks needs
to take care of updating of these notes. Many of these notes expect
that the instruction stream consists of linear regions, making such
updates difficult. The @code{NOTE_INSN_BASIC_BLOCK} note is the only
kind of note that may appear in the instruction stream contained in a
basic block. The instruction stream of a basic block always follows a
@code{NOTE_INSN_BASIC_BLOCK}, but zero or more @code{CODE_LABEL}
nodes can precede the block note. A basic block ends by control flow
instruction or last instruction before following @code{CODE_LABEL} or
@code{NOTE_INSN_BASIC_BLOCK}. A @code{CODE_LABEL} cannot appear in
that the instruction stream consists of linear regions, so updating
can sometimes be tedious. All types of insn notes are defined
in @file{insn-notes.def}.
In the RTL function representation, the instructions contained in a
basic block always follow a @code{NOTE_INSN_BASIC_BLOCK}, but zero
or more @code{CODE_LABEL} nodes can precede the block note.
A basic block ends with a control flow instruction or with the last
instruction before the next @code{CODE_LABEL} or
@code{NOTE_INSN_BASIC_BLOCK}.
By definition, a @code{CODE_LABEL} cannot appear in the middle of
the instruction stream of a basic block.
@findex can_fallthru
@ -110,27 +139,34 @@ Before any edge is made @dfn{fall-thru}, the existence of such
construct in the way needs to be checked by calling
@code{can_fallthru} function.
@cindex block statement iterators
For the @code{tree} representation, the head and end of the basic block
are being pointed to by the @code{stmt_list} field, but this special
@code{tree} should never be referenced directly. Instead, at the tree
level abstract containers and iterators are used to access statements
and expressions in basic blocks. These iterators are called
@dfn{block statement iterators} (BSIs). Grep for @code{^bsi}
in the various @file{tree-*} files.
The following snippet will pretty-print all the statements of the
program in the GIMPLE representation.
@cindex GIMPLE statement iterators
For the @code{GIMPLE} representation, the PHI nodes and statements
contained in a basic block are in a @code{gimple_seq} pointed to by
the basic block intermediate language specific pointers.
Abstract containers and iterators are used to access the PHI nodes
and statements in a basic blocks. These iterators are called
@dfn{GIMPLE statement iterators} (GSIs). Grep for @code{^gsi}
in the various @file{gimple-*} and @file{tree-*} files.
The following snippet will pretty-print all PHI nodes the statements
of the current function in the GIMPLE representation.
@smallexample
basic_block bb;
FOR_EACH_BB (bb)
@{
block_stmt_iterator si;
gimple_stmt_iterator si;
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
@{
tree stmt = bsi_stmt (si);
print_generic_stmt (stderr, stmt, 0);
@}
for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
@{
gimple phi = gsi_stmt (si);
print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
@}
for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
@{
gimple stmt = gsi_stmt (si);
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
@}
@}
@end smallexample
@ -144,7 +180,7 @@ Edges represent possible control flow transfers from the end of some
basic block A to the head of another basic block B@. We say that A is
a predecessor of B, and B is a successor of A@. Edges are represented
in GCC with the @code{edge} data type. Each @code{edge} acts as a
link between two basic blocks: the @code{src} member of an edge
link between two basic blocks: The @code{src} member of an edge
points to the predecessor basic block of the @code{dest} basic block.
The members @code{preds} and @code{succs} of the @code{basic_block} data
type point to type-safe vectors of edges to the predecessors and
@ -245,7 +281,7 @@ is needed. Note that this may require creation of a new basic block.
Exception handling edges represent possible control transfers from a
trapping instruction to an exception handler. The definition of
``trapping'' varies. In C++, only function calls can throw, but for
Java, exceptions like division by zero or segmentation fault are
Java and Ada, exceptions like division by zero or segmentation fault are
defined and thus each instruction possibly throwing this kind of
exception needs to be handled as control flow instruction. Exception
edges have the @code{EDGE_ABNORMAL} and @code{EDGE_EH} flags set.
@ -260,7 +296,7 @@ anyway. The edges can be eliminated via @code{purge_dead_edges} call.
In the RTL representation, the destination of an exception edge is
specified by @code{REG_EH_REGION} note attached to the insn.
In case of a trapping call the @code{EDGE_ABNORMAL_CALL} flag is set
too. In the @code{tree} representation, this extra flag is not set.
too. In the @code{GIMPLE} representation, this extra flag is not set.
@findex may_trap_p, tree_could_trap_p
In the RTL representation, the predicate @code{may_trap_p} may be used
@ -320,9 +356,11 @@ y:
goto *x;
@end smallexample
@findex pass_duplicate_computed_gotos
However, the classic problem with this transformation is that it has a
runtime cost in there resulting code: An extra jump. Therefore, the
computed jumps are un-factored in the later passes of the compiler.
computed jumps are un-factored in the later passes of the compiler
(in the pass called @code{pass_duplicate_computed_gotos}).
Be aware of that when you work on passes in that area. There have
been numerous examples already where the compile time for code with
unfactored computed jumps caused some serious headaches.
@ -343,7 +381,7 @@ edge from the call to the label is created with the
@findex LABEL_ALTERNATE_NAME
By definition, execution of function starts at basic block 0, so there
is always an edge from the @code{ENTRY_BLOCK_PTR} to basic block 0.
There is no @code{tree} representation for alternate entry points at
There is no @code{GIMPLE} representation for alternate entry points at
this moment. In RTL, alternate entry points are specified by
@code{CODE_LABEL} with @code{LABEL_ALTERNATE_NAME} defined. This
feature is currently used for multiple entry point prologues and is
@ -372,7 +410,7 @@ speed. In such cases it is useful to know information about how often
some given block will be executed. That is the purpose for
maintaining profile within the flow graph.
GCC can handle profile information obtained through @dfn{profile
feedback}, but it can also estimate branch probabilities based on
feedback}, but it can also estimate branch probabilities based on
statics and heuristics.
@cindex profile feedback
@ -425,7 +463,7 @@ Each edge also contains a branch probability field: an integer in the
range from 0 to @code{REG_BR_PROB_BASE}. It represents probability of
passing control from the end of the @code{src} basic block to the
@code{dest} basic block, i.e.@: the probability that control will flow
along this edge. The @code{EDGE_FREQUENCY} macro is available to
along this edge. The @code{EDGE_FREQUENCY} macro is available to
compute how frequently a given edge is taken. There is a @code{count}
field for each edge as well, representing same information as for a
basic block.
@ -482,76 +520,63 @@ manipulation routines when necessary. These hooks are defined in
manipulations, including block splitting and merging, edge redirection
and creating and deleting basic blocks. These hooks should provide
everything you need to maintain and manipulate the CFG in both the RTL
and @code{tree} representation.
and @code{GIMPLE} representation.
At the moment, the basic block boundaries are maintained transparently
when modifying instructions, so there rarely is a need to move them
manually (such as in case someone wants to output instruction outside
basic block explicitly).
Often the CFG may be better viewed as integral part of instruction
chain, than structure built on the top of it. However, in principle
the control flow graph for the @code{tree} representation is
@emph{not} an integral part of the representation, in that a function
tree may be expanded without first building a flow graph for the
@code{tree} representation at all. This happens when compiling
without any @code{tree} optimization enabled. When the @code{tree}
optimizations are enabled and the instruction stream is rewritten in
SSA form, the CFG is very tightly coupled with the instruction stream.
In particular, statement insertion and removal has to be done with
care. In fact, the whole @code{tree} representation can not be easily
used or maintained without proper maintenance of the CFG
simultaneously.
@findex BLOCK_FOR_INSN, bb_for_stmt
@findex BLOCK_FOR_INSN, gimple_bb
In the RTL representation, each instruction has a
@code{BLOCK_FOR_INSN} value that represents pointer to the basic block
that contains the instruction. In the @code{tree} representation, the
function @code{bb_for_stmt} returns a pointer to the basic block
that contains the instruction. In the @code{GIMPLE} representation, the
function @code{gimple_bb} returns a pointer to the basic block
containing the queried statement.
@cindex block statement iterators
When changes need to be applied to a function in its @code{tree}
representation, @dfn{block statement iterators} should be used. These
@cindex GIMPLE statement iterators
When changes need to be applied to a function in its @code{GIMPLE}
representation, @dfn{GIMPLE statement iterators} should be used. These
iterators provide an integrated abstraction of the flow graph and the
instruction stream. Block statement iterators are constructed using
the @code{block_stmt_iterator} data structure and several modifier are
the @code{gimple_stmt_iterator} data structure and several modifier are
available, including the following:
@ftable @code
@item bsi_start
This function initializes a @code{block_stmt_iterator} that points to
@item gsi_start
This function initializes a @code{gimple_stmt_iterator} that points to
the first non-empty statement in a basic block.
@item bsi_last
This function initializes a @code{block_stmt_iterator} that points to
@item gsi_last
This function initializes a @code{gimple_stmt_iterator} that points to
the last statement in a basic block.
@item bsi_end_p
This predicate is @code{true} if a @code{block_stmt_iterator}
@item gsi_end_p
This predicate is @code{true} if a @code{gimple_stmt_iterator}
represents the end of a basic block.
@item bsi_next
This function takes a @code{block_stmt_iterator} and makes it point to
@item gsi_next
This function takes a @code{gimple_stmt_iterator} and makes it point to
its successor.
@item bsi_prev
This function takes a @code{block_stmt_iterator} and makes it point to
@item gsi_prev
This function takes a @code{gimple_stmt_iterator} and makes it point to
its predecessor.
@item bsi_insert_after
This function inserts a statement after the @code{block_stmt_iterator}
@item gsi_insert_after
This function inserts a statement after the @code{gimple_stmt_iterator}
passed in. The final parameter determines whether the statement
iterator is updated to point to the newly inserted statement, or left
pointing to the original statement.
@item bsi_insert_before
This function inserts a statement before the @code{block_stmt_iterator}
@item gsi_insert_before
This function inserts a statement before the @code{gimple_stmt_iterator}
passed in. The final parameter determines whether the statement
iterator is updated to point to the newly inserted statement, or left
pointing to the original statement.
@item bsi_remove
This function removes the @code{block_stmt_iterator} passed in and
@item gsi_remove
This function removes the @code{gimple_stmt_iterator} passed in and
rechains the remaining statements in a basic block, if any.
@end ftable
@ -591,8 +616,8 @@ target of a jump or branch instruction.
@findex insert_insn_on_edge
@findex commit_edge_insertions
@findex bsi_insert_on_edge
@findex bsi_commit_edge_inserts
@findex gsi_insert_on_edge
@findex gsi_commit_edge_inserts
@cindex edge splitting
For a global optimizer, a common operation is to split edges in the
flow graph and insert instructions on them. In the RTL
@ -602,20 +627,17 @@ representation, this can be easily done using the
call that will take care of moving the inserted instructions off the
edge into the instruction stream contained in a basic block. This
includes the creation of new basic blocks where needed. In the
@code{tree} representation, the equivalent functions are
@code{bsi_insert_on_edge} which inserts a block statement
iterator on an edge, and @code{bsi_commit_edge_inserts} which flushes
@code{GIMPLE} representation, the equivalent functions are
@code{gsi_insert_on_edge} which inserts a block statement
iterator on an edge, and @code{gsi_commit_edge_inserts} which flushes
the instruction to actual instruction stream.
While debugging the optimization pass, a @code{verify_flow_info}
@findex verify_flow_info
@cindex CFG verification
While debugging the optimization pass, the @code{verify_flow_info}
function may be useful to find bugs in the control flow graph updating
code.
Note that at present, the representation of control flow in the
@code{tree} representation is discarded before expanding to RTL@.
Long term the CFG should be maintained and ``expanded'' to the
RTL representation along with the function @code{tree} itself.
@node Liveness information
@section Liveness information

View File

@ -716,6 +716,7 @@ compute_alignments (void)
if (dump_file)
{
dump_reg_info (dump_file);
dump_flow_info (dump_file, TDF_DETAILS);
flow_loops_dump (dump_file, NULL, 1);
}

View File

@ -6738,13 +6738,20 @@ reposition_prologue_and_epilogue_notes (void)
#endif /* HAVE_prologue or HAVE_epilogue */
}
/* Returns the name of function FN. */
const char *
function_name (struct function *fn)
{
if (fn == NULL)
return "(nofn)";
return lang_hooks.decl_printable_name (fn->decl, 2);
}
/* Returns the name of the current function. */
const char *
current_function_name (void)
{
if (cfun == NULL)
return "<none>";
return lang_hooks.decl_printable_name (cfun->decl, 2);
return function_name (cfun);
}

View File

@ -22,11 +22,14 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_FUNCTION_H
#define GCC_FUNCTION_H
#include "tree.h"
#include "hashtab.h"
#include "vec.h"
#include "vecprim.h"
#include "tm.h" /* For CUMULATIVE_ARGS. */
#include "hard-reg-set.h"
#include "vecir.h"
#include "machmode.h"
#include "tm.h" /* For CUMULATIVE_ARGS. */
#include "hard-reg-set.h" /* For HARD_REG_SET in struct rtl_data. */
#include "input.h" /* For location_t. */
/* Stack of pending (incomplete) sequences saved by `start_sequence'.
Each element describes one pending sequence.
@ -760,6 +763,7 @@ extern void clobber_return_register (void);
extern rtx get_arg_pointer_save_area (void);
/* Returns the name of the current function. */
extern const char *function_name (struct function *);
extern const char *current_function_name (void);
extern void do_warn_unused_parameter (tree);

View File

@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "vecir.h"
#include "ggc.h"
#include "basic-block.h"
#include "tree.h"
#include "tree-ssa-operands.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"

View File

@ -4454,7 +4454,10 @@ rest_of_handle_if_conversion (void)
if (flag_if_conversion)
{
if (dump_file)
dump_flow_info (dump_file, dump_flags);
{
dump_reg_info (dump_file);
dump_flow_info (dump_file, dump_flags);
}
cleanup_cfg (CLEANUP_EXPENSIVE);
if_convert ();
}

View File

@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "regs.h"
#include "rtl.h"
#include "tree.h" /* For DECL_ARTIFICIAL and friends. */
#include "tm_p.h"
#include "target.h"
#include "flags.h"

View File

@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_LANG_HOOKS_H
#define GCC_LANG_HOOKS_H
/* This file should be #include-d after tree.h. */
/* FIXME: This file should be #include-d after tree.h (for enum tree_code). */
struct diagnostic_info;

View File

@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "obstack.h"
#include "basic-block.h"
#include "cfgloop.h"
@ -204,7 +204,10 @@ rtl_loop_init (void)
gcc_assert (current_ir_type () == IR_RTL_CFGLAYOUT);
if (dump_file)
dump_flow_info (dump_file, dump_flags);
{
dump_reg_info (dump_file);
dump_flow_info (dump_file, dump_flags);
}
loop_optimizer_init (LOOPS_NORMAL);
return 0;
@ -242,7 +245,10 @@ rtl_loop_done (void)
cleanup_cfg (0);
if (dump_file)
dump_flow_info (dump_file, dump_flags);
{
dump_reg_info (dump_file);
dump_flow_info (dump_file, dump_flags);
}
return 0;
}

View File

@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tm.h"
#include "basic-block.h"
#include "tree.h" /* FIXME: Only for langhooks.h. */
#include "langhooks.h"
#include "tree.h"
#include "gcov-io.h"

View File

@ -150,6 +150,8 @@ maybe_hot_count_p (gcov_type count)
bool
maybe_hot_bb_p (const_basic_block bb)
{
/* Make sure CFUN exists, for dump_bb_info. */
gcc_assert (cfun);
if (profile_status == PROFILE_READ)
return maybe_hot_count_p (bb->count);
return maybe_hot_frequency_p (bb->frequency);
@ -201,6 +203,8 @@ maybe_hot_edge_p (edge e)
bool
probably_never_executed_bb_p (const_basic_block bb)
{
/* Make sure CFUN exists, for dump_bb_info. */
gcc_assert (cfun);
if (profile_info && flag_branch_probabilities)
return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
if ((!profile_info || !flag_branch_probabilities)

View File

@ -640,7 +640,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
if (dump_file)
{
int overlap = compute_frequency_overlap ();
dump_flow_info (dump_file, dump_flags);
gimple_dump_cfg (dump_file, dump_flags);
fprintf (dump_file, "Static profile overlap: %d.%d%%\n",
overlap / (OVERLAP_BASE / 100),
overlap % (OVERLAP_BASE / 100));

View File

@ -936,7 +936,7 @@ reginfo_init (void)
if (df)
df_compute_regs_ever_live (true);
/* This prevents dump_flow_info from losing if called
/* This prevents dump_reg_info from losing if called
before reginfo is run. */
reg_pref = NULL;
/* No more global register variables may be declared. */

View File

@ -92,7 +92,7 @@ REG_N_SETS (int regno)
#define INC_REG_N_SETS(N,V) (regstat_n_sets_and_refs[N].sets += V)
/* Functions defined in reg-stat.c. */
/* Functions defined in regstat.c. */
extern void regstat_init_n_sets_and_refs (void);
extern void regstat_free_n_sets_and_refs (void);
extern void regstat_compute_ri (void);
@ -100,7 +100,7 @@ extern void regstat_free_ri (void);
extern bitmap regstat_get_setjmp_crosses (void);
extern void regstat_compute_calls_crossed (void);
extern void regstat_free_calls_crossed (void);
extern void dump_reg_info (FILE *);
/* Register information indexed by register number. This structure is
initialized by calling regstat_compute_ri and is destroyed by

View File

@ -121,8 +121,7 @@ extern regset fixed_reg_set_regset;
/* An obstack for regsets. */
extern bitmap_obstack reg_obstack;
/* In cfg.c */
/* In df-core.c (which should use regset consistently instead of bitmap...) */
extern void dump_regset (regset, FILE *);
extern void debug_regset (regset);
#endif /* GCC_REGSET_H */

View File

@ -544,3 +544,69 @@ regstat_free_calls_crossed (void)
reg_info_p = NULL;
}
/* Dump the register info to FILE. */
void
dump_reg_info (FILE *file)
{
unsigned int i, max = max_reg_num ();
if (reload_completed)
return;
if (reg_info_p_size < max)
max = reg_info_p_size;
fprintf (file, "%d registers.\n", max);
for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
{
enum reg_class rclass, altclass;
if (regstat_n_sets_and_refs)
fprintf (file, "\nRegister %d used %d times across %d insns",
i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
else if (df)
fprintf (file, "\nRegister %d used %d times across %d insns",
i, DF_REG_USE_COUNT (i) + DF_REG_DEF_COUNT (i), REG_LIVE_LENGTH (i));
if (REG_BASIC_BLOCK (i) >= NUM_FIXED_BLOCKS)
fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
if (regstat_n_sets_and_refs)
fprintf (file, "; set %d time%s", REG_N_SETS (i),
(REG_N_SETS (i) == 1) ? "" : "s");
else if (df)
fprintf (file, "; set %d time%s", DF_REG_DEF_COUNT (i),
(DF_REG_DEF_COUNT (i) == 1) ? "" : "s");
if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i]))
fputs ("; user var", file);
if (REG_N_DEATHS (i) != 1)
fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
if (REG_N_CALLS_CROSSED (i) == 1)
fputs ("; crosses 1 call", file);
else if (REG_N_CALLS_CROSSED (i))
fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
if (REG_FREQ_CALLS_CROSSED (i))
fprintf (file, "; crosses call with %d frequency", REG_FREQ_CALLS_CROSSED (i));
if (regno_reg_rtx[i] != NULL
&& PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
rclass = reg_preferred_class (i);
altclass = reg_alternate_class (i);
if (rclass != GENERAL_REGS || altclass != ALL_REGS)
{
if (altclass == ALL_REGS || rclass == ALL_REGS)
fprintf (file, "; pref %s", reg_class_names[(int) rclass]);
else if (altclass == NO_REGS)
fprintf (file, "; %s or none", reg_class_names[(int) rclass]);
else
fprintf (file, "; pref %s, else %s",
reg_class_names[(int) rclass],
reg_class_names[(int) altclass]);
}
if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i]))
fputs ("; pointer", file);
fputs (".\n", file);
}
}

View File

@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "fixed-value.h"
#include "alias.h"
#include "hashtab.h"
#include "flags.h"
#undef FFS /* Some systems predefine this symbol; don't let it interfere. */
#undef FLOAT /* Likewise. */
@ -423,7 +424,7 @@ struct GTY((variable_size)) rtvec_def {
#define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
/* Nonzero if DEBUG_INSN_P may possibly hold. */
#define MAY_HAVE_DEBUG_INSNS MAY_HAVE_DEBUG_STMTS
#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
/* Predicate yielding nonzero iff X is a real insn. */
#define INSN_P(X) \
@ -2512,10 +2513,6 @@ extern int fixup_args_size_notes (rtx, rtx, int);
extern void print_rtl_with_bb (FILE *, const_rtx);
extern rtx duplicate_insn_chain (rtx, rtx);
/* In cfg.c. */
extern void dump_reg_info (FILE *);
extern void dump_flow_info (FILE *, int);
/* In expmed.c */
extern void init_expmed (void);
extern void expand_inc (rtx, rtx);

View File

@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "diagnostic-core.h"
#include "rtl.h"
#include "tree.h" /* FIXME: Used by call_may_noreturn_p. */
#include "tm_p.h"
#include "hard-reg-set.h"
#include "regs.h"
@ -3374,6 +3375,8 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
/* Return TRUE if INSN might not always return normally (e.g. call exit,
longjmp, loop forever, ...). */
/* FIXME: Why can't this function just use flags_from_decl_or_type and
test for ECF_NORETURN? */
static bool
call_may_noreturn_p (rtx insn)
{

View File

@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "tree.h" /* FIXME: To dump INSN_VAR_LOCATION_DECL. */
#include "obstack.h"
#include "hard-reg-set.h"
#include "basic-block.h"
@ -806,13 +807,15 @@ print_rtl_slim (FILE *f, rtx first, rtx last, int count, int flags)
(insn != NULL) && (insn != tail) && (count != 0);
insn = NEXT_INSN (insn))
{
bool verbose = ((flags & TDF_DETAILS) != 0);
if ((flags & TDF_BLOCKS)
&& (INSN_P (insn) || NOTE_P (insn))
&& BLOCK_FOR_INSN (insn)
&& !current_bb)
{
current_bb = BLOCK_FOR_INSN (insn);
dump_bb_info (current_bb, true, false, flags, ";; ", f);
dump_bb_info (current_bb, true, false, verbose, ";; ", f);
}
dump_insn_slim (f, insn);
@ -821,7 +824,7 @@ print_rtl_slim (FILE *f, rtx first, rtx last, int count, int flags)
&& current_bb
&& insn == BB_END (current_bb))
{
dump_bb_info (current_bb, false, true, flags, ";; ", f);
dump_bb_info (current_bb, false, true, verbose, ";; ", f);
current_bb = NULL;
}
if (count > 0)

View File

@ -142,7 +142,7 @@ statistics_fini_pass_2 (void **slot, void *data ATTRIBUTE_UNUSED)
current_pass->static_pass_number,
current_pass->name,
counter->id, counter->val,
cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
current_function_name (),
count);
else
fprintf (statistics_dump_file,
@ -150,7 +150,7 @@ statistics_fini_pass_2 (void **slot, void *data ATTRIBUTE_UNUSED)
current_pass->static_pass_number,
current_pass->name,
counter->id,
cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
current_function_name (),
count);
counter->prev_dumped_count = counter->count;
return 1;
@ -312,7 +312,7 @@ statistics_counter_event (struct function *fn, const char *id, int incr)
current_pass->static_pass_number,
current_pass->name,
id,
fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)",
function_name (fn),
incr);
}
@ -342,5 +342,5 @@ statistics_histogram_event (struct function *fn, const char *id, int val)
current_pass->static_pass_number,
current_pass->name,
id, val,
fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)");
function_name (fn));
}

View File

@ -370,14 +370,12 @@ tracer (void)
{
bool changed;
gcc_assert (current_ir_type () == IR_GIMPLE);
if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1)
return 0;
mark_dfs_back_edges ();
if (dump_file)
dump_flow_info (dump_file, dump_flags);
brief_dump_cfg (dump_file);
/* Trace formation is done on the fly inside tail_duplicate */
changed = tail_duplicate ();
@ -385,7 +383,7 @@ tracer (void)
free_dominance_info (CDI_DOMINATORS);
if (dump_file)
dump_flow_info (dump_file, dump_flags);
brief_dump_cfg (dump_file);
return changed ? TODO_cleanup_cfg : 0;
}

View File

@ -3833,6 +3833,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
/* Set input_location here so we get the right instantiation context
if we call instantiate_decl from inlinable_function_p. */
/* FIXME: instantiate_decl isn't called by inlinable_function_p. */
saved_location = input_location;
input_location = gimple_location (stmt);

View File

@ -10041,6 +10041,7 @@ variable_tracking_main_1 (void)
if (dump_file && (dump_flags & TDF_DETAILS))
{
dump_dataflow_sets ();
dump_reg_info (dump_file);
dump_flow_info (dump_file, dump_flags);
}