mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-23 00:41:25 +08:00
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:
parent
79bdca32d4
commit
532aafaddb
@ -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.
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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 ();
|
||||
|
@ -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
|
||||
|
@ -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
272
gcc/cfg.c
@ -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);
|
||||
|
198
gcc/cfganal.c
198
gcc/cfganal.c
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
223
gcc/cfgrtl.c
223
gcc/cfgrtl.c
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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. */
|
||||
|
234
gcc/doc/cfg.texi
234
gcc/doc/cfg.texi
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user