diff options
author | abel <abel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-09-01 08:57:00 +0000 |
---|---|---|
committer | abel <abel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-09-01 08:57:00 +0000 |
commit | e1ab78748da58d43da7f08cc64b9de80577f470e (patch) | |
tree | 137062af2fefb2287271b69ca6f0c7e9e8e57e11 /gcc/sel-sched-dump.c | |
parent | 346e3a9c85f2878a54745f5065eb84eeeaed12f5 (diff) | |
download | gcc-e1ab78748da58d43da7f08cc64b9de80577f470e.tar.gz |
2008-08-31 Andrey Belevantsev <abel@ispras.ru>
Dmitry Melnik <dm@ispras.ru>
Dmitry Zhurikhin <zhur@ispras.ru>
Alexander Monakov <amonakov@ispras.ru>
Maxim Kuvyrkov <maxim@codesourcery.com>
* sel-sched.h, sel-sched-dump.h, sel-sched-ir.h, sel-sched.c,
sel-sched-dump.c, sel-sched-ir.c: New files.
* Makefile.in (OBJS-common): Add selective scheduling object
files.
(sel-sched.o, sel-sched-dump.o, sel-sched-ir.o): New entries.
(SEL_SCHED_IR_H, SEL_SCHED_DUMP_H): New entries.
(sched-vis.o): Add dependency on $(INSN_ATTR_H).
* cfghooks.h (get_cfg_hooks, set_cfg_hooks): New prototypes.
* cfghooks.c (get_cfg_hooks, set_cfg_hooks): New functions.
(make_forwarder_block): Update loop latch if we have redirected
the loop latch edge.
* cfgloop.c (get_loop_body_in_custom_order): New function.
* cfgloop.h (LOOPS_HAVE_FALLTHRU_PREHEADERS): New enum field.
(CP_FALLTHRU_PREHEADERS): Likewise.
(get_loop_body_in_custom_order): Declare.
* cfgloopmanip.c (has_preds_from_loop): New.
(create_preheader): Honor CP_FALLTHRU_PREHEADERS.
Assert that the preheader edge will be fall thru when it is set.
* common.opt (fsel-sched-bookkeeping, fsel-sched-pipelining,
fsel-sched-pipelining-outer-loops, fsel-sched-renaming,
fsel-sched-substitution, fselective-scheduling): New flags.
* cse.c (hash_rtx_cb): New.
(hash_rtx): Use it.
* dbgcnt.def (sel_sched_cnt, sel_sched_region_cnt,
sel_sched_insn_cnt): New counters.
* final.c (compute_alignments): Export. Free dominance info after loop_optimizer_finalize.
* genattr.c (main): Output maximal_insn_latency prototype.
* genautomata.c (output_default_latencies): New. Factor its code from ...
(output_internal_insn_latency_func): ... here.
(output_internal_maximal_insn_latency_func): New.
(output_maximal_insn_latency_func): New.
* hard-reg-set.h (UHOST_BITS_PER_WIDE_INT): Define unconditionally.
(struct hard_reg_set_iterator): New.
(hard_reg_set_iter_init, hard_reg_set_iter_set,
hard_reg_set_iter_next): New functions.
(EXECUTE_IF_SET_IN_HARD_REG_SET): New macro.
* lists.c (remove_free_INSN_LIST_node,
remove_free_EXPR_LIST_node): New functions.
* loop-init.c (loop_optimizer_init): When LOOPS_HAVE_FALLTHRU_PREHEADERS,
set CP_FALLTHRU_PREHEADERS when calling create_preheaders.
(loop_optimizer_finalize): Do not verify flow info after reload.
* recog.c (validate_replace_rtx_1): New parameter simplify.
Default it to true. Update all uses. Factor out simplifying
code to ...
(simplify_while_replacing): ... this new function.
(validate_replace_rtx_part,
validate_replace_rtx_part_nosimplify): New.
* recog.h (validate_replace_rtx_part,
validate_replace_rtx_part_nosimplify): Declare.
* rtl.c (rtx_equal_p_cb): New.
(rtx_equal_p): Use it.
* rtl.h (rtx_equal_p_cb, hash_rtx_cb): Declare.
(remove_free_INSN_LIST_NODE, remove_free_EXPR_LIST_node,
debug_bb_n_slim, debug_bb_slim, print_rtl_slim): Likewise.
* vecprim.h: Add a vector type for unsigned int.
* haifa-sched.c: Include vecprim.h and cfgloop.h.
(issue_rate, sched_verbose_param, note_list, dfa_state_size,
ready_try, cycle_issued_insns, spec_info): Make global.
(readyp): Initialize.
(dfa_lookahead): New global variable.
(old_max_uid, old_last_basic_block): Remove.
(h_i_d): Make it a vector.
(INSN_TICK, INTER_TICK, QUEUE_INDEX, INSN_COST): Make them work
through HID macro.
(after_recovery, adding_bb_to_current_region_p):
New variables to handle correct insertion of the recovery code.
(struct ready_list): Move declaration to sched-int.h.
(rgn_n_insns): Removed.
(rtx_vec_t): Move to sched-int.h.
(find_insn_reg_weight): Remove.
(find_insn_reg_weight1): Rename to find_insn_reg_weight.
(haifa_init_h_i_d, haifa_finish_h_i_d):
New functions to initialize / finalize haifa instruction data.
(extend_h_i_d, init_h_i_d): Rewrite.
(unlink_other_notes): Move logic to add_to_note_list. Handle
selective scheduler.
(ready_lastpos, ready_element, ready_sort, reemit_notes,
find_fallthru_edge): Make global, remove static prototypes.
(max_issue): Make global. Add privileged_n and state parameters. Use
them.
(extend_global, extend_all): Removed.
(init_before_recovery): Add new param. Fix the handling of the case
when we insert a recovery code before the EXIT which has a predecessor
with a fallthrough edge to it.
(create_recovery_block): Make global. Rename to
sched_create_recovery_block. Update.
(change_pattern): Rename to sched_change_pattern. Make global.
(speculate_insn): Rename to sched_speculate_insn. Make global.
Split haifa-specific functionality into ...
(haifa_change_pattern): New static function.
(sched_extend_bb): New static function.
(sched_init_bbs): New function.
(current_sched_info): Change type to struct haifa_sched_info.
(insn_cost): Adjust for selective scheduling.
(dep_cost_1): New function. Move logic from ...
(dep_cost): ... here.
(dep_cost): Use dep_cost_1.
(contributes_to_priority_p): Use sched_deps_info instead of
current_sched_info.
(priority): Adjust to work with selective scheduling. Process the
corner case when all dependencies don't contribute to priority.
(rank_for_schedule): Use ds_weak instead of dep_weak.
(advance_state): New function. Move logic from ...
(advance_one_cycle): ... here.
(add_to_note_list, concat_note_lists): New functions.
(rm_other_notes): Make static. Adjust for selective scheduling.
(remove_notes, restore_other_notes): New functions.
(move_insn): Add two arguments. Update assert. Don't call
reemit_notes.
(choose_ready): Remove lookahead variable, use dfa_lookahead.
Remove more_issue, max_points. Move the code to initialize
max_lookahead_tries to max_issue.
(schedule_block): Remove rgn_n_insns1 parameter. Don't allocate
ready. Adjust use of move_insn. Call restore_other_notes.
(luid): Remove.
(sched_init, sched_finish): Move Haifa-specific initialization/
finalization to ...
(haifa_sched_init, haifa_sched_finish): ... respectively.
New functions.
(setup_sched_dump): New function.
(haifa_init_only_bb): New static function.
(haifa_speculate_insn): New static function.
(try_ready): Use haifa_* instead of speculate_insn and
change_pattern.
(extend_ready, extend_all): Remove.
(sched_extend_ready_list, sched_finish_ready_list): New functions.
(create_check_block_twin, add_to_speculative_block): Use
haifa_insns_init instead of extend_global. Update to use new
initialization functions. Change parameter. Factor out code from
create_check_block_twin to ...
(sched_create_recovery_edges) ... this new function.
(add_block): Remove.
(sched_scan_info): New.
(extend_bb): Use sched_scan_info.
(init_bb, extend_insn, init_insn, init_insns_in_bb, sched_scan): New
static functions for walking through scheduling region.
(sched_luids): New vector variable to replace uid_to_luid.
(luids_extend_insn): New function.
(sched_max_luid): New variable.
(luids_init_insn): New function.
(sched_init_luids, sched_finish_luids): New functions.
(insn_luid): New debug function.
(sched_extend_target): New function.
(haifa_init_insn): New static function.
(sched_init_only_bb): New hook.
(sched_split_block): New hook.
(sched_split_block_1): New function.
(sched_create_empty_bb): New hook.
(sched_create_empty_bb_1): New function.
(common_sched_info, ready): New global variables.
(current_sched_info_var): Remove.
(move_block_after_check): Use common_sched_info.
(haifa_luid_for_non_insn): New static function.
(init_before_recovery): Use haifa_init_only_bb instead of
add_block.
(increase_insn_priority): New.
* modulo-sched.c: (issue_rate): Remove static declaration.
(sms_sched_info): Change type to haifa_sched_info.
(sms_sched_deps_info, sms_common_sched_info): New variables.
(setup_sched_infos): New.
(sms_schedule): Initialize them. Call haifa_sched_init/finish.
Do not call regstat_free_calls_crossed.
(sms_print_insn): Use const_rtx.
* params.def (PARAM_MAX_PIPELINE_REGION_BLOCKS,
PARAM_MAX_PIPELINE_REGION_INSNS, PARAM_SELSCHED_MAX_LOOKAHEAD,
PARAM_SELSCHED_MAX_SCHED_TIMES, PARAM_SELSCHED_INSNS_TO_RENAME,
PARAM_SCHED_MEM_TRUE_DEP_COST): New.
* sched-deps.c (sched_deps_info): New. Update all relevant uses of
current_sched_info to use it.
(enum reg_pending_barrier_mode): Move to sched-int.h.
(h_d_i_d): New variable. Initialize to NULL.
({true, output, anti, spec, forward}_dependency_cache): Initialize
to NULL.
(estimate_dep_weak): Remove static declaration.
(sched_has_condition_p): New function. Adjust users of
sched_get_condition to use it instead.
(conditions_mutex_p): Add arguments indicating which conditions are
reversed. Use them.
(sched_get_condition_with_rev): Rename from sched_get_condition. Add
argument to indicate whether returned condition is reversed. Do not
generate new rtx when condition should be reversed; indicate it by
setting new argument instead.
(add_dependence_list_and_free): Add deps parameter.
Update all users. Do not free dependence list when
deps context is readonly.
(add_insn_mem_dependence, flush_pending_lists): Adjust for readonly
contexts.
(remove_from_dependence_list, remove_from_both_dependence_lists): New.
(remove_from_deps): New. Use the above functions.
(cur_insn, can_start_lhs_rhs_p): New static variables.
(add_or_update_back_dep_1): Initialize present_dep_type.
(haifa_start_insn, haifa_finish_insn, haifa_note_reg_set,
haifa_note_reg_clobber, haifa_note_reg_use, haifa_note_mem_dep,
haifa_note_dep): New functions implementing dependence hooks for
the Haifa scheduler.
(note_reg_use, note_reg_set, note_reg_clobber, note_mem_dep,
note_dep): New functions.
(ds_to_dt, extend_deps_reg_info, maybe_extend_reg_info_p): New
functions.
(init_deps): Initialize last_reg_pending_barrier and deps->readonly.
(free_deps): Initialize deps->reg_last.
(sched_analyze_reg, sched_analyze_1, sched_analyze_2,
sched_analyze_insn): Update to use dependency hooks infrastructure
and readonly contexts.
(deps_analyze_insn): New function. Move part of logic from ...
(sched_analyze): ... here. Also move some logic to ...
(deps_start_bb): ... here. New function.
(add_forw_dep, delete_forw_dep): Guard use of INSN_DEP_COUNT with
sel_sched_p.
(sched_deps_init): New function. Move code from ...
(init_dependency_caches): ... here. Remove.
(init_deps_data_vector): New.
(sched_deps_finish): New function. Move code from ...
(free_dependency_caches): ... here. Remove.
(init_deps_global, finish_deps_global): Adjust for use with
selective scheduling.
(get_dep_weak): Move logic to ...
(get_dep_weak_1): New function.
(ds_merge): Move logic to ...
(ds_merge_1): New static function.
(ds_full_merge, ds_max_merge, ds_get_speculation_types): New functions.
(ds_get_max_dep_weak): New function.
* sched-ebb.c (sched_n_insns): Rename to sched_rgn_n_insns.
(n_insns): Rename to rgn_n_insns.
(debug_ebb_dependencies): New function.
(init_ready_list): Use it.
(begin_schedule_ready): Use sched_init_only_bb.
(ebb_print_insn): Indicate when an insn starts a new cycle.
(contributes_to_priority, compute_jump_reg_dependencies,
add_remove_insn, fix_recovery_cfg): Add ebb_ prefix to function names.
(add_block1): Remove to ebb_add_block.
(ebb_sched_deps_info, ebb_common_sched_info): New variables.
(schedule_ebb): Initialize them. Use remove_notes instead of
rm_other_notes. Use haifa_local_init/finish.
(schedule_ebbs): Use haifa_sched_init/finish.
* sched-int.h: Include vecprim.h, remove rtl.h.
(struct ready_list): Delete declaration.
(sched_verbose_param, enum sched_pass_id_t,
bb_vec_t, insn_vec_t, rtx_vec_t): New.
(struct sched_scan_info_def): New structure.
(sched_scan_info, sched_scan, sched_init_bbs,
sched_init_luids, sched_finish_luids, sched_extend_target,
haifa_init_h_i_d, haifa_finish_h_i_d): Declare.
(struct common_sched_info_def): New.
(common_sched_info, haifa_common_sched_info,
sched_emulate_haifa_p): Declare.
(sel_sched_p): New.
(sched_luids): Declare.
(INSN_LUID, LUID_BY_UID, SET_INSN_LUID): Declare.
(sched_max_luid, insn_luid): Declare.
(note_list, remove_notes, restore_other_notes, bb_note): Declare.
(sched_insns_init, sched_insns_finish, xrecalloc, reemit_notes,
print_insn, print_pattern, print_value, haifa_classify_insn,
sel_find_rgns, sel_mark_hard_insn, dfa_state_size, advance_state,
setup_sched_dump, sched_init, sched_finish,
sel_insn_is_speculation_check): Export.
(struct ready_list): Move from haifa-sched.c.
(ready_try, ready, max_issue): Export.
(ebb_compute_jump_reg_dependencies, find_fallthru_edge,
sched_init_only_bb, sched_split_block, sched_split_block_1,
sched_create_empty_bb, sched_create_empty_bb_1,
sched_create_recovery_block, sched_create_recovery_edges): Export.
(enum reg_pending_barrier_mode): Export.
(struct deps): New fields `last_reg_pending_barrier' and `readonly'.
(deps_t): New.
(struct sched_info): Rename to haifa_sched_info. Use const_rtx for
print_insn field. Move add_block and fix_recovery_cfg to
common_sched_info_def. Move compute_jump_reg_dependencies, use_cselib ...
(struct sched_deps_info_def): ... this new structure.
(sched_deps_info): Declare.
(struct spec_info_def): Remove weakness_cutoff, add
data_weakness_cutoff and control_weakness_cutoff.
(spec_info): Declare.
(struct _haifa_deps_insn_data): Split from haifa_insn_data. Add
dep_count field.
(struct haifa_insn_data): Rename to struct _haifa_insn_data.
(haifa_insn_data_def, haifa_insn_data_t): New typedefs.
(current_sched_info): Change type to struct haifa_sched_info.
(haifa_deps_insn_data_def, haifa_deps_insn_data_t): New typedefs.
(h_d_i_d): New variable.
(HDID): New accessor macro.
(h_i_d): Change type to VEC (haifa_insn_data_def, heap) *.
(HID): New accessor macro. Rewrite h_i_d accessor macros through HID
and HDID.
(IS_SPECULATION_CHECK_P): Update for selective scheduler.
(enum SCHED_FLAGS): Update for selective scheduler.
(enum SPEC_SCHED_FLAGS): New flag SEL_SCHED_SPEC_DONT_CHECK_CONTROL.
(init_dependency_caches, free_dependency_caches): Delete declarations.
(deps_analyze_insn, remove_from_deps, get_dep_weak_1,
estimate_dep_weak, ds_full_merge, ds_max_merge, ds_weak,
ds_get_speculation_types, ds_get_max_dep_weak, sched_deps_init,
sched_deps_finish, haifa_note_reg_set, haifa_note_reg_use,
haifa_note_reg_clobber, maybe_extend_reg_info_p, deps_start_bb,
ds_to_dt): Export.
(rm_other_notes): Delete declaration.
(schedule_block): Remove one argument.
(cycle_issued_insns, issue_rate, dfa_lookahead, ready_sort,
ready_element, ready_lastpos, sched_extend_ready_list,
sched_finish_ready_list, sched_change_pattern, sched_speculate_insn,
concat_note_lists): Export.
(struct region): Move from sched-rgn.h.
(nr_regions, rgn_table, rgn_bb_table, block_to_bb, containing_rgn,
RGN_NR_BLOCKS, RGN_BLOCKS, RGN_DONT_CALC_DEPS, RGN_HAS_REAL_EBB,
BLOCK_TO_BB, CONTAINING_RGN): Export.
(ebb_head, BB_TO_BLOCK, EBB_FIRST_BB, EBB_LAST_BB, INSN_BB): Likewise.
(current_nr_blocks, current_blocks, target_bb): Likewise.
(dep_cost_1, sched_is_disabled_for_current_region_p, sched_rgn_init,
sched_rgn_finish, rgn_setup_region, sched_rgn_compute_dependencies,
sched_rgn_local_init, extend_regions,
rgn_make_new_region_out_of_new_block, compute_priorities,
debug_rgn_dependencies, free_rgn_deps, contributes_to_priority,
extend_rgns, deps_join rgn_setup_common_sched_info,
rgn_setup_sched_infos, debug_regions, debug_region, dump_region_dot,
dump_region_dot_file, haifa_sched_init, haifa_sched_finish): Export.
(get_rgn_sched_max_insns_priority, sel_add_to_insn_priority,
increase_insn_priority): Likewise.
* sched-rgn.c: Include sel-sched.h.
(ref_counts): New static variable. Use it ...
(INSN_REF_COUNT): ... here. Rewrite and move closer to uses.
(FED_BY_SPEC_LOAD, IS_LOAD_INSN): Rewrite to use HID accessor macro.
(sched_is_disabled_for_current_region_p): Delete static declaration.
(struct region): Move to sched-int.h.
(nr_regions, rgn_table, rgn_bb_table, block_to_bb, containing_rgn,
ebb_head): Define and initialize.
(RGN_NR_BLOCKS, RGN_BLOCKS, RGN_DONT_CALC_DEPS, RGN_HAS_REAL_EBB,
BLOCK_TO_BB, CONTAINING_RGN, debug_regions, extend_regions,
BB_TO_BLOCK, EBB_FIRST_BB, EBB_LAST_BB): Move to
sched-int.h.
(find_single_block_region): Add new argument to indicate that EBB
regions should be constructed.
(debug_live): Delete declaration.
(current_nr_blocks, current_blocks, target_bb): Remove static qualifiers.
(compute_dom_prob_ps, check_live, update_live, set_spec_fed): Delete
declaration.
(init_regions): Delete declaration.
(debug_region, bb_in_region_p, dump_region_dot_file, dump_region_dot,
rgn_estimate_number_of_insns): New.
(too_large): Use estimate_number_of_insns.
(haifa_find_rgns): New. Move the code from ...
(find_rgns): ... here. Call either sel_find_rgns or haifa_find_rgns.
(free_trg_info): New.
(compute_trg_info): Allocate candidate tables here instead of ...
(init_ready_list): ... here.
(rgn_print_insn): Use const_rtx.
(contributes_to_priority, extend_regions): Delete static declaration.
(add_remove_insn, fix_recovery_cfg): Add rgn_ to function names.
(add_block1): Rename to rgn_add_block.
(debug_rgn_dependencies): Delete static qualifier.
(new_ready): Use sched_deps_info. Simplify.
(rgn_common_sched_info, rgn_const_sched_deps_info,
rgn_const_sel_sched_deps_info, rgn_sched_deps_info, rgn_sched_info): New.
(region_sched_info): Rename to rgn_const_sched_info.
(deps_join): New, extracted from ...
(propagate_deps): ... here.
(compute_block_dependences, debug_dependencies): Update for selective
scheduling.
(free_rgn_deps, compute_priorities): New functions.
(sched_rgn_init, sched_rgn_finish, rgn_setup_region,
sched_rgn_compute_dependencies): New functions.
(schedule_region): Use them.
(sched_rgn_local_init, sched_rgn_local_free, sched_rgn_local_finish,
rgn_setup_common_sched_info, rgn_setup_sched_infos):
New functions.
(schedule_insns): Call new functions that were split out.
(rgn_make_new_region_out_of_new_block): New.
(get_rgn_sched_max_insns_priority): New.
(rest_of_handle_sched, rest_of_handle_sched2): Call selective
scheduling when appropriate.
* sched-vis.c: Include insn-attr.h.
(print_value, print_pattern): Make global.
(print_rtl_slim, debug_bb_slim, debug_bb_n_slim): New functions.
* target-def.h (TARGET_SCHED_ADJUST_COST_2,
TARGET_SCHED_ALLOC_SCHED_CONTEXT, TARGET_SCHED_INIT_SCHED_CONTEXT,
TARGET_SCHED_SET_SCHED_CONTEXT, TARGET_SCHED_CLEAR_SCHED_CONTEXT,
TARGET_SCHED_FREE_SCHED_CONTEXT, TARGET_SCHED_GET_INSN_CHECKED_DS,
TARGET_SCHED_GET_INSN_SPEC_DS, TARGET_SCHED_SKIP_RTX_P): New target
hooks. Initialize them to 0.
(TARGET_SCHED_GEN_CHECK): Rename to TARGET_SCHED_GEN_SPEC_CHECK.
* target.h (struct gcc_target): Add them. Rename gen_check field to
gen_spec_check.
* flags.h (sel_sched_switch_set): Declare.
* opts.c (sel_sched_switch_set): New variable.
(decode_options): Unset flag_sel_sched_pipelining_outer_loops if
pipelining is disabled from command line.
(common_handle_option): Record whether selective scheduling is
requested from command line.
* doc/invoke.texi: Document new flags and parameters.
* doc/tm.texi: Document new target hooks.
* config/ia64/ia64.c (TARGET_SCHED_GEN_SPEC_CHECK): Define to ia64_gen_check.
(dfa_state_size): Do not declare locally.
* config/ia64/ia64.opt (msched-ar-data-spec): Default to 0.
* config/rs6000/rs6000.c (rs6000_init_sched_context,
rs6000_alloc_sched_context, rs6000_set_sched_context,
rs6000_free_sched_context): New functions.
(struct _rs6000_sched_context): New.
(rs6000_sched_reorder2): Do not modify INSN_PRIORITY for selective
scheduling.
(rs6000_sched_finish): Do not run for selective scheduling.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@139854 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/sel-sched-dump.c')
-rw-r--r-- | gcc/sel-sched-dump.c | 945 |
1 files changed, 945 insertions, 0 deletions
diff --git a/gcc/sel-sched-dump.c b/gcc/sel-sched-dump.c new file mode 100644 index 00000000000..7d56d3ba078 --- /dev/null +++ b/gcc/sel-sched-dump.c @@ -0,0 +1,945 @@ +/* Instruction scheduling pass. Log dumping infrastructure. + Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "function.h" +#include "flags.h" +#include "insn-config.h" +#include "insn-attr.h" +#include "params.h" +#include "output.h" +#include "basic-block.h" +#include "cselib.h" +#include "sel-sched-ir.h" +#include "sel-sched-dump.h" + + +/* These variables control high-level pretty printing. */ +static int sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS; +static int sel_debug_cfg_flags = SEL_DUMP_CFG_FLAGS; + +/* True when a cfg should be dumped. */ +static bool sel_dump_cfg_p; + +/* Variables that are used to build the cfg dump file name. */ +static const char * const sel_debug_cfg_root = "./"; +static const char * const sel_debug_cfg_root_postfix_default = ""; +static const char *sel_debug_cfg_root_postfix = ""; +static int sel_dump_cfg_fileno = -1; +static int sel_debug_cfg_fileno = -1; + +/* When this flag is on, we are dumping to the .dot file. + When it is off, we are dumping to log. + This is useful to differentiate formatting between log and .dot + files. */ +bool sched_dump_to_dot_p = false; + +/* Controls how insns from a fence list should be dumped. */ +static int dump_flist_insn_flags = (DUMP_INSN_UID | DUMP_INSN_BBN + | DUMP_INSN_SEQNO); + + +/* The variable used to hold the value of sched_dump when temporarily + switching dump output to the other source, e.g. the .dot file. */ +static FILE *saved_sched_dump = NULL; + +/* Switch sched_dump to TO. It must not be called twice. */ +static void +switch_dump (FILE *to) +{ + gcc_assert (saved_sched_dump == NULL); + + saved_sched_dump = sched_dump; + sched_dump = to; +} + +/* Restore previously switched dump. */ +static void +restore_dump (void) +{ + sched_dump = saved_sched_dump; + saved_sched_dump = NULL; +} + + +/* Functions for dumping instructions, av sets, and exprs. */ + +/* Default flags for dumping insns. */ +static int dump_insn_rtx_flags = DUMP_INSN_RTX_PATTERN; + +/* Default flags for dumping vinsns. */ +static int dump_vinsn_flags = (DUMP_VINSN_INSN_RTX | DUMP_VINSN_TYPE + | DUMP_VINSN_COUNT); + +/* Default flags for dumping expressions. */ +static int dump_expr_flags = DUMP_EXPR_ALL; + +/* Default flags for dumping insns when debugging. */ +static int debug_insn_rtx_flags = DUMP_INSN_RTX_ALL; + +/* Default flags for dumping vinsns when debugging. */ +static int debug_vinsn_flags = DUMP_VINSN_ALL; + +/* Default flags for dumping expressions when debugging. */ +static int debug_expr_flags = DUMP_EXPR_ALL; + +/* Controls how an insn from stream should be dumped when debugging. */ +static int debug_insn_flags = DUMP_INSN_ALL; + +/* Print an rtx X. */ +void +sel_print_rtl (rtx x) +{ + print_rtl_single (sched_dump, x); +} + +/* Dump insn INSN honoring FLAGS. */ +void +dump_insn_rtx_1 (rtx insn, int flags) +{ + int all; + + /* flags == -1 also means dumping all. */ + all = (flags & 1);; + if (all) + flags |= DUMP_INSN_RTX_ALL; + + sel_print ("("); + + if (flags & DUMP_INSN_RTX_UID) + sel_print ("%d;", INSN_UID (insn)); + + if (flags & DUMP_INSN_RTX_PATTERN) + { + char buf[2048]; + + print_insn (buf, insn, 0); + sel_print ("%s;", buf); + } + + if (flags & DUMP_INSN_RTX_BBN) + { + basic_block bb = BLOCK_FOR_INSN (insn); + + sel_print ("bb:%d;", bb != NULL ? bb->index : -1); + } + + sel_print (")"); +} + + +/* Dump INSN with default flags. */ +void +dump_insn_rtx (rtx insn) +{ + dump_insn_rtx_1 (insn, dump_insn_rtx_flags); +} + + +/* Dump INSN to stderr. */ +void +debug_insn_rtx (rtx insn) +{ + switch_dump (stderr); + dump_insn_rtx_1 (insn, debug_insn_rtx_flags); + sel_print ("\n"); + restore_dump (); +} + +/* Dump vinsn VI honoring flags. */ +void +dump_vinsn_1 (vinsn_t vi, int flags) +{ + int all; + + /* flags == -1 also means dumping all. */ + all = flags & 1; + if (all) + flags |= DUMP_VINSN_ALL; + + sel_print ("("); + + if (flags & DUMP_VINSN_INSN_RTX) + dump_insn_rtx_1 (VINSN_INSN_RTX (vi), dump_insn_rtx_flags | all); + + if (flags & DUMP_VINSN_TYPE) + sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi))); + + if (flags & DUMP_VINSN_COUNT) + sel_print ("count:%d;", VINSN_COUNT (vi)); + + if (flags & DUMP_VINSN_COST) + { + int cost = vi->cost; + + if (cost != -1) + sel_print ("cost:%d;", cost); + } + + sel_print (")"); +} + +/* Dump vinsn VI with default flags. */ +void +dump_vinsn (vinsn_t vi) +{ + dump_vinsn_1 (vi, dump_vinsn_flags); +} + +/* Dump vinsn VI to stderr. */ +void +debug_vinsn (vinsn_t vi) +{ + switch_dump (stderr); + dump_vinsn_1 (vi, debug_vinsn_flags); + sel_print ("\n"); + restore_dump (); +} + +/* Dump EXPR honoring flags. */ +void +dump_expr_1 (expr_t expr, int flags) +{ + int all; + + /* flags == -1 also means dumping all. */ + all = flags & 1; + if (all) + flags |= DUMP_EXPR_ALL; + + sel_print ("["); + + if (flags & DUMP_EXPR_VINSN) + dump_vinsn_1 (EXPR_VINSN (expr), dump_vinsn_flags | all); + + if (flags & DUMP_EXPR_SPEC) + { + int spec = EXPR_SPEC (expr); + + if (spec != 0) + sel_print ("spec:%d;", spec); + } + + if (flags & DUMP_EXPR_USEFULNESS) + { + int use = EXPR_USEFULNESS (expr); + + if (use != REG_BR_PROB_BASE) + sel_print ("use:%d;", use); + } + + if (flags & DUMP_EXPR_PRIORITY) + sel_print ("prio:%d;", EXPR_PRIORITY (expr)); + + if (flags & DUMP_EXPR_SCHED_TIMES) + { + int times = EXPR_SCHED_TIMES (expr); + + if (times != 0) + sel_print ("times:%d;", times); + } + + if (flags & DUMP_EXPR_SPEC_DONE_DS) + { + ds_t spec_done_ds = EXPR_SPEC_DONE_DS (expr); + + if (spec_done_ds != 0) + sel_print ("ds:%d;", spec_done_ds); + } + + if (flags & DUMP_EXPR_ORIG_BB) + { + int orig_bb = EXPR_ORIG_BB_INDEX (expr); + + if (orig_bb != 0) + sel_print ("orig_bb:%d;", orig_bb); + } + + if (EXPR_TARGET_AVAILABLE (expr) < 1) + sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr)); + sel_print ("]"); +} + +/* Dump expression EXPR with default flags. */ +void +dump_expr (expr_t expr) +{ + dump_expr_1 (expr, dump_expr_flags); +} + +/* Dump expression EXPR to stderr. */ +void +debug_expr (expr_t expr) +{ + switch_dump (stderr); + dump_expr_1 (expr, debug_expr_flags); + sel_print ("\n"); + restore_dump (); +} + +/* Dump insn I honoring FLAGS. */ +void +dump_insn_1 (insn_t i, int flags) +{ + int all; + + all = flags & 1; + if (all) + flags |= DUMP_INSN_ALL; + + if (!sched_dump_to_dot_p) + sel_print ("("); + + if (flags & DUMP_INSN_EXPR) + { + dump_expr_1 (INSN_EXPR (i), dump_expr_flags | all); + sel_print (";"); + } + else if (flags & DUMP_INSN_PATTERN) + { + dump_insn_rtx_1 (i, DUMP_INSN_RTX_PATTERN | all); + sel_print (";"); + } + else if (flags & DUMP_INSN_UID) + sel_print ("uid:%d;", INSN_UID (i)); + + if (flags & DUMP_INSN_SEQNO) + sel_print ("seqno:%d;", INSN_SEQNO (i)); + + if (flags & DUMP_INSN_SCHED_CYCLE) + { + int cycle = INSN_SCHED_CYCLE (i); + + if (cycle != 0) + sel_print ("cycle:%d;", cycle); + } + + if (!sched_dump_to_dot_p) + sel_print (")"); +} + +/* Dump insn I with default flags. */ +void +dump_insn (insn_t i) +{ + dump_insn_1 (i, DUMP_INSN_EXPR | DUMP_INSN_SCHED_CYCLE); +} + +/* Dump INSN to stderr. */ +void +debug_insn (insn_t insn) +{ + switch_dump (stderr); + dump_insn_1 (insn, debug_insn_flags); + sel_print ("\n"); + restore_dump (); +} + +/* Dumps av_set AV. */ +void +dump_av_set (av_set_t av) +{ + av_set_iterator i; + expr_t expr; + + if (!sched_dump_to_dot_p) + sel_print ("{"); + + FOR_EACH_EXPR (expr, i, av) + { + dump_expr (expr); + if (!sched_dump_to_dot_p) + sel_print (" "); + else + sel_print ("\n"); + } + + if (!sched_dump_to_dot_p) + sel_print ("}"); +} + +/* Dumps lvset LV. */ +void +dump_lv_set (regset lv) +{ + sel_print ("{"); + + /* This code was adapted from flow.c: dump_regset (). */ + if (lv == NULL) + sel_print ("nil"); + else + { + unsigned i; + reg_set_iterator rsi; + int count = 0; + + EXECUTE_IF_SET_IN_REG_SET (lv, 0, i, rsi) + { + sel_print (" %d", i); + if (i < FIRST_PSEUDO_REGISTER) + { + sel_print (" [%s]", reg_names[i]); + ++count; + } + + ++count; + + if (sched_dump_to_dot_p && count == 12) + { + count = 0; + sel_print ("\n"); + } + } + } + + sel_print ("}\n"); +} + +/* Dumps a list of instructions pointed to by P. */ +static void +dump_ilist (ilist_t p) +{ + while (p) + { + dump_insn (ILIST_INSN (p)); + p = ILIST_NEXT (p); + } +} + +/* Dumps a list of boundaries pointed to by BNDS. */ +void +dump_blist (blist_t bnds) +{ + for (; bnds; bnds = BLIST_NEXT (bnds)) + { + bnd_t bnd = BLIST_BND (bnds); + + sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd))); + dump_ilist (BND_PTR (bnd)); + sel_print ("] "); + } +} + +/* Dumps a list of fences pointed to by L. */ +void +dump_flist (flist_t l) +{ + while (l) + { + dump_insn_1 (FENCE_INSN (FLIST_FENCE (l)), dump_flist_insn_flags); + sel_print (" "); + l = FLIST_NEXT (l); + } +} + +/* Dumps an insn vector SUCCS. */ +void +dump_insn_vector (rtx_vec_t succs) +{ + int i; + rtx succ; + + for (i = 0; VEC_iterate (rtx, succs, i, succ); i++) + if (succ) + dump_insn (succ); + else + sel_print ("NULL "); +} + +/* Dumps a hard reg set SET to FILE using PREFIX. */ +static void +print_hard_reg_set (FILE *file, const char *prefix, HARD_REG_SET set) +{ + int i; + + fprintf (file, "%s{ ", prefix); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (TEST_HARD_REG_BIT (set, i)) + fprintf (file, "%d ", i); + } + fprintf (file, "}\n"); +} + +/* Dumps a hard reg set SET using PREFIX. */ +void +dump_hard_reg_set (const char *prefix, HARD_REG_SET set) +{ + print_hard_reg_set (sched_dump, prefix, set); +} + +/* Pretty print INSN. This is used as a hook. */ +const char * +sel_print_insn (const_rtx insn, int aligned ATTRIBUTE_UNUSED) +{ + static char buf[80]; + + /* '+' before insn means it is a new cycle start and it's not been + scheduled yet. '>' - has been scheduled. */ + if (s_i_d && INSN_LUID (insn) > 0) + if (GET_MODE (insn) == TImode) + sprintf (buf, "%s %4d", + INSN_SCHED_TIMES (insn) > 0 ? "> " : "< ", + INSN_UID (insn)); + else + sprintf (buf, "%s %4d", + INSN_SCHED_TIMES (insn) > 0 ? "! " : " ", + INSN_UID (insn)); + else + if (GET_MODE (insn) == TImode) + sprintf (buf, "+ %4d", INSN_UID (insn)); + else + sprintf (buf, " %4d", INSN_UID (insn)); + + return buf; +} + + +/* Functions for pretty printing of CFG. */ + +/* Replace all occurencies of STR1 to STR2 in BUF. + The BUF must be large enough to hold the result. */ +static void +replace_str_in_buf (char *buf, const char *str1, const char *str2) +{ + int buf_len = strlen (buf); + int str1_len = strlen (str1); + int str2_len = strlen (str2); + int diff = str2_len - str1_len; + + char *p = buf; + do + { + p = strstr (p, str1); + if (p) + { + char *p1 = p + str1_len; + /* Copy the rest of buf and '\0'. */ + int n = buf + buf_len - p1; + int i; + + /* Shift str by DIFF chars. */ + if (diff > 0) + for (i = n; i >= 0; i--) + p1[i + diff] = p1[i]; + else + for (i = 0; i <= n; i++) + p1[i + diff] = p1[i]; + + /* Copy str2. */ + for (i = 0; i < str2_len; i++) + p[i] = str2[i]; + + p += str2_len; + buf_len += diff; + } + + } + while (p); +} + +/* Replace characters in BUF that have special meaning in .dot file. */ +void +sel_prepare_string_for_dot_label (char *buf) +{ + static char specials_from[7][2] = { "<", ">", "{", "|", "}", "\"", + "\n" }; + static char specials_to[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}", + "\\\"", "\\l" }; + unsigned i; + + for (i = 0; i < 7; i++) + replace_str_in_buf (buf, specials_from[i], specials_to[i]); +} + +/* Dump INSN with FLAGS. */ +static void +sel_dump_cfg_insn (insn_t insn, int flags) +{ + int insn_flags = DUMP_INSN_UID | DUMP_INSN_PATTERN; + + if (sched_luids != NULL && INSN_LUID (insn) > 0) + { + if (flags & SEL_DUMP_CFG_INSN_SEQNO) + insn_flags |= DUMP_INSN_SEQNO | DUMP_INSN_SCHED_CYCLE | DUMP_INSN_EXPR; + } + + dump_insn_1 (insn, insn_flags); +} + +/* Dump E to the dot file F. */ +static void +sel_dump_cfg_edge (FILE *f, edge e) +{ + int w; + const char *color; + + if (e->flags & EDGE_FALLTHRU) + { + w = 10; + color = ", color = red"; + } + else if (e->src->next_bb == e->dest) + { + w = 3; + color = ", color = blue"; + } + else + { + w = 1; + color = ""; + } + + fprintf (f, "\tbb%d -> bb%d [weight = %d%s];\n", + e->src->index, e->dest->index, w, color); +} + + +/* Return true if BB has a predesessor from current region. + TODO: Either make this function to trace back through empty block + or just remove those empty blocks. */ +static bool +has_preds_in_current_region_p (basic_block bb) +{ + edge e; + edge_iterator ei; + + gcc_assert (!in_current_region_p (bb)); + + FOR_EACH_EDGE (e, ei, bb->preds) + if (in_current_region_p (e->src)) + return true; + + return false; +} + +/* Dump a cfg region to the dot file F honoring FLAGS. */ +static void +sel_dump_cfg_2 (FILE *f, int flags) +{ + basic_block bb; + + sched_dump_to_dot_p = true; + switch_dump (f); + + fprintf (f, "digraph G {\n" + "\tratio = 2.25;\n" + "\tnode [shape = record, fontsize = 9];\n"); + + if (flags & SEL_DUMP_CFG_FUNCTION_NAME) + fprintf (f, "function [label = \"%s\"];\n", current_function_name ()); + + FOR_EACH_BB (bb) + { + insn_t insn = BB_HEAD (bb); + insn_t next_tail = NEXT_INSN (BB_END (bb)); + edge e; + edge_iterator ei; + bool in_region_p = ((flags & SEL_DUMP_CFG_CURRENT_REGION) + && in_current_region_p (bb)); + bool full_p = (!(flags & SEL_DUMP_CFG_CURRENT_REGION) + || in_region_p); + bool some_p = full_p || has_preds_in_current_region_p (bb); + const char *color; + const char *style; + + if (!some_p) + continue; + + if ((flags & SEL_DUMP_CFG_CURRENT_REGION) + && in_current_region_p (bb) + && BLOCK_TO_BB (bb->index) == 0) + color = "color = green, "; + else + color = ""; + + if ((flags & SEL_DUMP_CFG_FENCES) + && in_region_p) + { + style = ""; + + if (!sel_bb_empty_p (bb)) + { + bool first_p = true; + insn_t tail = BB_END (bb); + insn_t cur_insn; + + cur_insn = bb_note (bb); + + do + { + fence_t fence; + + cur_insn = NEXT_INSN (cur_insn); + fence = flist_lookup (fences, cur_insn); + + if (fence != NULL) + { + if (!FENCE_SCHEDULED_P (fence)) + { + if (first_p) + color = "color = red, "; + else + color = "color = yellow, "; + } + else + color = "color = blue, "; + } + + first_p = false; + } + while (cur_insn != tail); + } + } + else if (!full_p) + style = "style = dashed, "; + else + style = ""; + + fprintf (f, "\tbb%d [%s%slabel = \"{Basic block %d", bb->index, + style, color, bb->index); + + if ((flags & SEL_DUMP_CFG_BB_LOOP) + && bb->loop_father != NULL) + fprintf (f, ", loop %d", bb->loop_father->num); + + if (full_p + && (flags & SEL_DUMP_CFG_BB_NOTES_LIST)) + { + insn_t notes = BB_NOTE_LIST (bb); + + if (notes != NULL_RTX) + { + fprintf (f, "|"); + + /* For simplicity, we dump notes from note_list in reversed order + to that what they will appear in the code. */ + while (notes != NULL_RTX) + { + sel_dump_cfg_insn (notes, flags); + fprintf (f, "\\l"); + + notes = PREV_INSN (notes); + } + } + } + + if (full_p + && (flags & SEL_DUMP_CFG_AV_SET) + && in_current_region_p (bb) + && !sel_bb_empty_p (bb)) + { + fprintf (f, "|"); + + if (BB_AV_SET_VALID_P (bb)) + dump_av_set (BB_AV_SET (bb)); + else if (BB_AV_LEVEL (bb) == -1) + fprintf (f, "AV_SET needs update"); + } + + if ((flags & SEL_DUMP_CFG_LV_SET) + && !sel_bb_empty_p (bb)) + { + fprintf (f, "|"); + + if (BB_LV_SET_VALID_P (bb)) + dump_lv_set (BB_LV_SET (bb)); + else + fprintf (f, "LV_SET needs update"); + } + + if (full_p + && (flags & SEL_DUMP_CFG_BB_INSNS)) + { + fprintf (f, "|"); + while (insn != next_tail) + { + sel_dump_cfg_insn (insn, flags); + fprintf (f, "\\l"); + + insn = NEXT_INSN (insn); + } + } + + fprintf (f, "}\"];\n"); + + FOR_EACH_EDGE (e, ei, bb->succs) + if (full_p || in_current_region_p (e->dest)) + sel_dump_cfg_edge (f, e); + } + + fprintf (f, "}"); + + restore_dump (); + sched_dump_to_dot_p = false; +} + +/* Dump a cfg region to the file specified by TAG honoring flags. + The file is created by the function. */ +static void +sel_dump_cfg_1 (const char *tag, int flags) +{ + char *buf; + int i; + FILE *f; + + ++sel_dump_cfg_fileno; + + if (!sel_dump_cfg_p) + return; + + i = 1 + snprintf (NULL, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root, + sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag); + buf = XNEWVEC (char, i); + snprintf (buf, i, "%s/%s%05d-%s.dot", sel_debug_cfg_root, + sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag); + + f = fopen (buf, "w"); + + if (f == NULL) + fprintf (stderr, "Can't create file: %s.\n", buf); + else + { + sel_dump_cfg_2 (f, flags); + + fclose (f); + } + + free (buf); +} + +/* Setup cfg dumping flags. Used for debugging. */ +void +setup_dump_cfg_params (void) +{ + sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS; + sel_dump_cfg_p = 0; + sel_debug_cfg_root_postfix = sel_debug_cfg_root_postfix_default; +} + +/* Debug a cfg region with FLAGS. */ +void +sel_debug_cfg_1 (int flags) +{ + bool t1 = sel_dump_cfg_p; + int t2 = sel_dump_cfg_fileno; + + sel_dump_cfg_p = true; + sel_dump_cfg_fileno = ++sel_debug_cfg_fileno; + + sel_dump_cfg_1 ("sel-debug-cfg", flags); + + sel_dump_cfg_fileno = t2; + sel_dump_cfg_p = t1; +} + +/* Dumps av_set AV to stderr. */ +void +debug_av_set (av_set_t av) +{ + switch_dump (stderr); + dump_av_set (av); + sel_print ("\n"); + restore_dump (); +} + +/* Dump LV to stderr. */ +void +debug_lv_set (regset lv) +{ + switch_dump (stderr); + dump_lv_set (lv); + sel_print ("\n"); + restore_dump (); +} + +/* Dump an instruction list P to stderr. */ +void +debug_ilist (ilist_t p) +{ + switch_dump (stderr); + dump_ilist (p); + sel_print ("\n"); + restore_dump (); +} + +/* Dump a boundary list BNDS to stderr. */ +void +debug_blist (blist_t bnds) +{ + switch_dump (stderr); + dump_blist (bnds); + sel_print ("\n"); + restore_dump (); +} + +/* Dump an insn vector SUCCS. */ +void +debug_insn_vector (rtx_vec_t succs) +{ + switch_dump (stderr); + dump_insn_vector (succs); + sel_print ("\n"); + restore_dump (); +} + +/* Dump a hard reg set SET to stderr. */ +void +debug_hard_reg_set (HARD_REG_SET set) +{ + switch_dump (stderr); + dump_hard_reg_set ("", set); + sel_print ("\n"); + restore_dump (); +} + +/* Debug a cfg region with default flags. */ +void +sel_debug_cfg (void) +{ + sel_debug_cfg_1 (sel_debug_cfg_flags); +} + +/* Print a current cselib value for X's address to stderr. */ +rtx +debug_mem_addr_value (rtx x) +{ + rtx t, addr; + + gcc_assert (MEM_P (x)); + t = shallow_copy_rtx (x); + if (cselib_lookup (XEXP (t, 0), Pmode, 0)) + XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0)); + + t = canon_rtx (t); + addr = get_addr (XEXP (t, 0)); + debug_rtx (t); + debug_rtx (addr); + return t; +} + + |