invoke.texi (-fsched-pressure): Document it.

2009-09-02  Vladimir Makarov  <vmakarov@redhat.com>

	* doc/invoke.texi (-fsched-pressure): Document it.
	(-fsched-reg-pressure-heuristic): Remove it.
	
	* reload.c (ira.h): Include.
	(find_reloads): Add choosing reload on number of small spilled
	classes.
	
	* haifa-sched.c (ira.h): Include.
	(sched_pressure_p, sched_regno_cover_class, curr_reg_pressure,
	saved_reg_pressure, curr_reg_live, saved_reg_live,
	region_ref_regs): New variables.
	(sched_init_region_reg_pressure_info, mark_regno_birth_or_death,
	initiate_reg_pressure_info, setup_ref_regs,
	initiate_bb_reg_pressure_info, save_reg_pressure,
	restore_reg_pressure, dying_use_p, print_curr_reg_pressure): New
	functions.
	(setup_insn_reg_pressure_info): New function.
	(rank_for_schedule): Add pressure checking and insn issue time.
	Remove comparison of insn reg weights.
	(ready_sort): Set insn reg pressure info.
	(update_register_pressure, setup_insn_max_reg_pressure,
	update_reg_and_insn_max_reg_pressure,
	sched_setup_bb_reg_pressure_info): New functions.
	(schedule_insn): Add code for printing and updating reg pressure
	info.
	(find_set_reg_weight, find_insn_reg_weight): Remove.
	(ok_for_early_queue_removal): Do nothing if pressure_only_p.
	(debug_ready_list): Print reg pressure info.
	(schedule_block): Ditto.  Check insn issue time.
	(sched_init): Set up sched_pressure_p.  Allocate and set up some
	reg pressure related info.
	(sched_finish): Free some reg pressure related info.
	(fix_tick_ready): Make insn always ready if pressure_p.
	(init_h_i_d): Don't call find_insn_reg_weight.
	(haifa_finish_h_i_d): Free insn reg pressure info.
	
	* ira-int.h (ira_hard_regno_cover_class, ira_reg_class_nregs,
	ira_memory_move_cost, ira_class_hard_regs,
	ira_class_hard_regs_num, ira_no_alloc_regs,
	ira_available_class_regs, ira_reg_class_cover_size,
	ira_reg_class_cover, ira_class_translate): Move to ira.h.

	* ira-lives.c (single_reg_class): Check mode to find how many
	registers are necessary for operand.
	(ira_implicitly_set_insn_hard_regs): New.

	* common.opt (fsched-pressure): New options.
	(fsched-reg-pressure-heuristic): Remove.

	* ira.c (setup_eliminable_regset): Rename to
	ira_setup_eliminable_regset.  Make it external.
	(expand_reg_info): Pass cover class to setup_reg_classes.
	(ira): Call resize_reg_info instead of allocate_reg_info.

	* sched-deps.c: Include ira.h.
	(implicit_reg_pending_clobbers, implicit_reg_pending_uses): New.
	(create_insn_reg_use, create_insn_reg_set, setup_insn_reg_uses,
	reg_pressure_info, insn_use_p, mark_insn_pseudo_birth,
	mark_insn_hard_regno_birth, mark_insn_reg_birth,
	mark_pseudo_death, mark_hard_regno_death, mark_reg_death,
	mark_insn_reg_store, mark_insn_reg_clobber,
	setup_insn_reg_pressure_info): New.
	(sched_analyze_1): Update implicit_reg_pending_uses.
	(sched_analyze_insn): Find implicit sets, uses, clobbers of regs.
	Use them to create dependencies.  Set insn reg uses and pressure
	info.  Process reg_pending_uses in one place.
	(free_deps): Free implicit sets.
	(remove_from_deps): Remove implicit sets if necessary.  Check
	implicit sets when clearing reg_last_in_use.
	(init_deps_global): Clear implicit_reg_pending_clobbers and
	implicit_reg_pending_uses.
	
	* ira.h (ira_hard_regno_cover_class, ira_reg_class_nregs,
	ira_memory_move_cost, ira_class_hard_regs,
	ira_class_hard_regs_num, ira_no_alloc_regs,
	ira_available_class_regs, ira_reg_class_cover_size,
	ira_reg_class_cover, ira_class_translate): Move from ira-int.h.
	(ira_setup_eliminable_regset, ira_set_pseudo_classes,
	ira_implicitly_set_insn_hard_regs): New prototypes.
	
	* ira-costs.c (pseudo_classes_defined_p, allocno_p,
	cost_elements_num): New variables.
	(allocno_costs, total_costs): Rename to costs and
	total_allocno_costs.
	(COSTS_OF_ALLOCNO): Rename to COSTS.
	(allocno_pref): Rename to pref.
	(allocno_pref_buffer): Rename to pref_buffer.
	(common_classes): Rename to regno_cover_class.
	(COST_INDEX): New.
	(record_reg_classes): Set allocno attributes only if allocno_p.
	(record_address_regs): Ditto.  Use COST_INDEX instead of
	ALLOCNO_NUM.
	(scan_one_insn): Use COST_INDEX and COSTS instead of ALLOCNO_NUM
	and COSTS_OF_ALLOCNO.
	(print_costs): Rename to print_allocno_costs.
	(print_pseudo_costs): New.
	(process_bb_node_for_costs): Split into 2 functions with new
	function process_bb_for_costs.  Pass BB to process_bb_for_costs.
	(find_allocno_class_costs): Rename to find_costs_and_classes.  Add
	new parameter dump_file.  Use cost_elements_num instead of
	ira_allocnos_num.  Make one iteration if preferred classes were
	already calculated for scheduler.  Make 2 versions of code
	depending on allocno_p.
	(setup_allocno_cover_class_and_costs): Check allocno_p.  Use
	regno_cover_class and COSTS instead of common_classes and
	COSTS_OF_ALLOCNO.
	(init_costs, finish_costs): New.
	(ira_costs): Set up allocno_p and cost_elements_num.  Call
	init_costs and finish_costs.
	(ira_set_pseudo_classes): New.

	* rtl.h (allocate_reg_info): Remove.
	(resize_reg_info): Change return type.
	(reg_cover_class): New.
	(setup_reg_classes): Add new parameter.
	
	* sched-int.h (struct deps_reg): New member implicit_sets.
	(sched_pressure_p, sched_regno_cover_class): New external
	definitions.
	(INCREASE_BITS): New macro.
	(struct reg_pressure_data, struct reg_use_data): New.
	(struct _haifa_insn_data): Remove reg_weight.  Add members
	reg_pressure, reg_use_list, reg_set_list, and
	reg_pressure_excess_cost_change.
	(struct deps): New member implicit_sets.
	(pressure_p): New variable.
	(COVER_CLASS_BITS, INCREASE_BITS): New macros.
	(struct reg_pressure_data, struct reg_use_data): New.
	(INSN_REG_WEIGHT): Remove.
	(INSN_REG_PRESSURE, INSN_MAX_REG_PRESSURE, INSN_REG_USE_LIST,
	INSN_REG_SET_LIST, INSN_REG_PRESSURE_EXCESS_COST_CHANGE): New
	macros.
	(sched_init_region_reg_pressure_info,
	sched_setup_bb_reg_pressure_info): New prototypes.
	
        * reginfo.c (struct reg_pref): New member coverclass.
	(reg_cover_class): New function.
	(reginfo_init, pass_reginfo_init): Move after free_reg_info.
	(reg_info_size): New variable.
	(allocate_reg_info): Make static.  Setup reg_info_size.
	(resize_reg_info): Use reg_info_size.  Return flag of resizing.
	(setup_reg_classes): Add a new parameter.  Setup cover class too.

	* Makefile.in (reload.o, haifa-sched.o, sched-deps.o): Add ira.h to the
	dependencies.

	* sched-rgn.c (deps_join): Set up implicit_sets.
	(schedule_region): Set up region and basic blocks pressure
	relative info.
	
	* passes.c (init_optimization_passes): Move
	pass_subregs_of_mode_init before pass_sched.

From-SVN: r151348
This commit is contained in:
Vladimir Makarov 2009-09-02 18:54:25 +00:00 committed by Vladimir Makarov
parent f8563a3ba7
commit ce18efcb54
17 changed files with 1825 additions and 531 deletions

View File

@ -1,3 +1,158 @@
2009-09-02 Vladimir Makarov <vmakarov@redhat.com>
* doc/invoke.texi (-fsched-pressure): Document it.
(-fsched-reg-pressure-heuristic): Remove it.
* reload.c (ira.h): Include.
(find_reloads): Add choosing reload on number of small spilled
classes.
* haifa-sched.c (ira.h): Include.
(sched_pressure_p, sched_regno_cover_class, curr_reg_pressure,
saved_reg_pressure, curr_reg_live, saved_reg_live,
region_ref_regs): New variables.
(sched_init_region_reg_pressure_info, mark_regno_birth_or_death,
initiate_reg_pressure_info, setup_ref_regs,
initiate_bb_reg_pressure_info, save_reg_pressure,
restore_reg_pressure, dying_use_p, print_curr_reg_pressure): New
functions.
(setup_insn_reg_pressure_info): New function.
(rank_for_schedule): Add pressure checking and insn issue time.
Remove comparison of insn reg weights.
(ready_sort): Set insn reg pressure info.
(update_register_pressure, setup_insn_max_reg_pressure,
update_reg_and_insn_max_reg_pressure,
sched_setup_bb_reg_pressure_info): New functions.
(schedule_insn): Add code for printing and updating reg pressure
info.
(find_set_reg_weight, find_insn_reg_weight): Remove.
(ok_for_early_queue_removal): Do nothing if pressure_only_p.
(debug_ready_list): Print reg pressure info.
(schedule_block): Ditto. Check insn issue time.
(sched_init): Set up sched_pressure_p. Allocate and set up some
reg pressure related info.
(sched_finish): Free some reg pressure related info.
(fix_tick_ready): Make insn always ready if pressure_p.
(init_h_i_d): Don't call find_insn_reg_weight.
(haifa_finish_h_i_d): Free insn reg pressure info.
* ira-int.h (ira_hard_regno_cover_class, ira_reg_class_nregs,
ira_memory_move_cost, ira_class_hard_regs,
ira_class_hard_regs_num, ira_no_alloc_regs,
ira_available_class_regs, ira_reg_class_cover_size,
ira_reg_class_cover, ira_class_translate): Move to ira.h.
* ira-lives.c (single_reg_class): Check mode to find how many
registers are necessary for operand.
(ira_implicitly_set_insn_hard_regs): New.
* common.opt (fsched-pressure): New options.
(fsched-reg-pressure-heuristic): Remove.
* ira.c (setup_eliminable_regset): Rename to
ira_setup_eliminable_regset. Make it external.
(expand_reg_info): Pass cover class to setup_reg_classes.
(ira): Call resize_reg_info instead of allocate_reg_info.
* sched-deps.c: Include ira.h.
(implicit_reg_pending_clobbers, implicit_reg_pending_uses): New.
(create_insn_reg_use, create_insn_reg_set, setup_insn_reg_uses,
reg_pressure_info, insn_use_p, mark_insn_pseudo_birth,
mark_insn_hard_regno_birth, mark_insn_reg_birth,
mark_pseudo_death, mark_hard_regno_death, mark_reg_death,
mark_insn_reg_store, mark_insn_reg_clobber,
setup_insn_reg_pressure_info): New.
(sched_analyze_1): Update implicit_reg_pending_uses.
(sched_analyze_insn): Find implicit sets, uses, clobbers of regs.
Use them to create dependencies. Set insn reg uses and pressure
info. Process reg_pending_uses in one place.
(free_deps): Free implicit sets.
(remove_from_deps): Remove implicit sets if necessary. Check
implicit sets when clearing reg_last_in_use.
(init_deps_global): Clear implicit_reg_pending_clobbers and
implicit_reg_pending_uses.
* ira.h (ira_hard_regno_cover_class, ira_reg_class_nregs,
ira_memory_move_cost, ira_class_hard_regs,
ira_class_hard_regs_num, ira_no_alloc_regs,
ira_available_class_regs, ira_reg_class_cover_size,
ira_reg_class_cover, ira_class_translate): Move from ira-int.h.
(ira_setup_eliminable_regset, ira_set_pseudo_classes,
ira_implicitly_set_insn_hard_regs): New prototypes.
* ira-costs.c (pseudo_classes_defined_p, allocno_p,
cost_elements_num): New variables.
(allocno_costs, total_costs): Rename to costs and
total_allocno_costs.
(COSTS_OF_ALLOCNO): Rename to COSTS.
(allocno_pref): Rename to pref.
(allocno_pref_buffer): Rename to pref_buffer.
(common_classes): Rename to regno_cover_class.
(COST_INDEX): New.
(record_reg_classes): Set allocno attributes only if allocno_p.
(record_address_regs): Ditto. Use COST_INDEX instead of
ALLOCNO_NUM.
(scan_one_insn): Use COST_INDEX and COSTS instead of ALLOCNO_NUM
and COSTS_OF_ALLOCNO.
(print_costs): Rename to print_allocno_costs.
(print_pseudo_costs): New.
(process_bb_node_for_costs): Split into 2 functions with new
function process_bb_for_costs. Pass BB to process_bb_for_costs.
(find_allocno_class_costs): Rename to find_costs_and_classes. Add
new parameter dump_file. Use cost_elements_num instead of
ira_allocnos_num. Make one iteration if preferred classes were
already calculated for scheduler. Make 2 versions of code
depending on allocno_p.
(setup_allocno_cover_class_and_costs): Check allocno_p. Use
regno_cover_class and COSTS instead of common_classes and
COSTS_OF_ALLOCNO.
(init_costs, finish_costs): New.
(ira_costs): Set up allocno_p and cost_elements_num. Call
init_costs and finish_costs.
(ira_set_pseudo_classes): New.
* rtl.h (allocate_reg_info): Remove.
(resize_reg_info): Change return type.
(reg_cover_class): New.
(setup_reg_classes): Add new parameter.
* sched-int.h (struct deps_reg): New member implicit_sets.
(sched_pressure_p, sched_regno_cover_class): New external
definitions.
(INCREASE_BITS): New macro.
(struct reg_pressure_data, struct reg_use_data): New.
(struct _haifa_insn_data): Remove reg_weight. Add members
reg_pressure, reg_use_list, reg_set_list, and
reg_pressure_excess_cost_change.
(struct deps): New member implicit_sets.
(pressure_p): New variable.
(COVER_CLASS_BITS, INCREASE_BITS): New macros.
(struct reg_pressure_data, struct reg_use_data): New.
(INSN_REG_WEIGHT): Remove.
(INSN_REG_PRESSURE, INSN_MAX_REG_PRESSURE, INSN_REG_USE_LIST,
INSN_REG_SET_LIST, INSN_REG_PRESSURE_EXCESS_COST_CHANGE): New
macros.
(sched_init_region_reg_pressure_info,
sched_setup_bb_reg_pressure_info): New prototypes.
* reginfo.c (struct reg_pref): New member coverclass.
(reg_cover_class): New function.
(reginfo_init, pass_reginfo_init): Move after free_reg_info.
(reg_info_size): New variable.
(allocate_reg_info): Make static. Setup reg_info_size.
(resize_reg_info): Use reg_info_size. Return flag of resizing.
(setup_reg_classes): Add a new parameter. Setup cover class too.
* Makefile.in (reload.o, haifa-sched.o, sched-deps.o): Add ira.h to the
dependencies.
* sched-rgn.c (deps_join): Set up implicit_sets.
(schedule_region): Set up region and basic blocks pressure
relative info.
* passes.c (init_optimization_passes): Move
pass_subregs_of_mode_init before pass_sched.
2009-09-02 Martin Jambor <mjambor@suse.cz>
* tree-sra.c (struct access): New field grp_hint.

View File

@ -3030,7 +3030,7 @@ vec.o : vec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h vec.h $(GGC_H) \
reload.o : reload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(FLAGS_H) output.h $(EXPR_H) $(OPTABS_H) reload.h $(RECOG_H) \
hard-reg-set.h insn-config.h $(REGS_H) $(FUNCTION_H) real.h $(TOPLEV_H) \
addresses.h $(TM_P_H) $(PARAMS_H) $(TARGET_H) $(REAL_H) $(DF_H)
addresses.h $(TM_P_H) $(PARAMS_H) $(TARGET_H) $(REAL_H) $(DF_H) ira.h
reload1.o : reload1.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \
$(BASIC_BLOCK_H) $(RECOG_H) output.h $(FUNCTION_H) $(TOPLEV_H) $(TM_P_H) \
@ -3126,11 +3126,11 @@ modulo-sched.o : modulo-sched.c $(DDG_H) $(CONFIG_H) $(CONFIG_H) $(SYSTEM_H) \
haifa-sched.o : haifa-sched.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) $(TOPLEV_H) $(RECOG_H) $(EXCEPT_H) $(TM_P_H) $(TARGET_H) output.h \
$(PARAMS_H) $(DBGCNT_H)
$(PARAMS_H) $(DBGCNT_H) ira.h
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) $(TOPLEV_H) $(RECOG_H) $(EXCEPT_H) cselib.h \
$(PARAMS_H) $(TM_P_H)
ira.h $(PARAMS_H) $(TM_P_H) ira.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) $(TOPLEV_H) $(RECOG_H) $(EXCEPT_H) $(PARAMS_H) \

View File

@ -982,6 +982,10 @@ fsched-interblock
Common Report Var(flag_schedule_interblock) Init(1) Optimization
Enable scheduling across basic blocks
fsched-pressure
Common Report Var(flag_sched_pressure) Init(0) Optimization
Enable register pressure sensitive insn scheduling
fsched-spec
Common Report Var(flag_schedule_speculative) Init(1) Optimization
Allow speculative motion of non-loads
@ -1071,10 +1075,6 @@ fsched-spec-insn-heuristic
Common Report Var(flag_sched_spec_insn_heuristic) Init(1) Optimization
Enable the speculative instruction heuristic in the scheduler
fsched-reg-pressure-heuristic
Common Report Var(flag_sched_reg_pressure_heuristic) Init(1) Optimization
Enable the register pressure heuristic in the scheduler
fsched-rank-heuristic
Common Report Var(flag_sched_rank_heuristic) Init(1) Optimization
Enable the rank heuristic in the scheduler

View File

@ -365,12 +365,12 @@ Objective-C and Objective-C++ Dialects}.
-freorder-blocks-and-partition -freorder-functions @gol
-frerun-cse-after-loop -freschedule-modulo-scheduled-loops @gol
-frounding-math -fsched2-use-superblocks @gol
-fsched2-use-traces -fsched-spec-load -fsched-spec-load-dangerous @gol
-fsched2-use-traces -fsched-pressure @gol
-fsched-spec-load -fsched-spec-load-dangerous @gol
-fsched-stalled-insns-dep[=@var{n}] -fsched-stalled-insns[=@var{n}] @gol
-fsched-group-heuristic -fsched-critical-path-heuristic @gol
-fsched-spec-insn-heuristic -fsched-reg-pressure-heuristic @gol
-fsched-rank-heuristic -fsched-last-insn-heuristic @gol
-fsched-dep-count-heuristic @gol
-fsched-spec-insn-heuristic -fsched-rank-heuristic @gol
-fsched-last-insn-heuristic -fsched-dep-count-heuristic @gol
-fschedule-insns -fschedule-insns2 -fsection-anchors @gol
-fselective-scheduling -fselective-scheduling2 @gol
-fsel-sched-pipelining -fsel-sched-pipelining-outer-loops @gol
@ -6226,6 +6226,16 @@ Don't allow speculative motion of non-load instructions. This is normally
enabled by default when scheduling before register allocation, i.e.@:
with @option{-fschedule-insns} or at @option{-O2} or higher.
@item -fsched-pressure
@opindex fsched-pressure
Enable register pressure sensitive insn scheduling before the register
allocation. This only makes sense when scheduling before register
allocation is enabled, i.e.@: with @option{-fschedule-insns} or at
@option{-O2} or higher. Usage of this option can improve the
generated code and decrease its size by preventing register pressure
increase above the number of available hard registers and as a
consequence register spills in the register allocation.
@item -fsched-spec-load
@opindex fsched-spec-load
Allow speculative motion of some load instructions. This only makes
@ -6294,13 +6304,6 @@ This is enabled by default when scheduling is enabled, i.e.@:
with @option{-fschedule-insns} or @option{-fschedule-insns2}
or at @option{-O2} or higher.
@item -fsched-reg-pressure-heuristic
@opindex fsched-reg-pressure-heuristic
Enable the register pressure heuristic in the scheduler. This heuristic
favors the instruction with smaller contribution to register pressure.
This only makes sense when scheduling before register allocation, i.e.@:
with @option{-fschedule-insns} or at @option{-O2} or higher.
@item -fsched-rank-heuristic
@opindex fsched-rank-heuristic
Enable the rank heuristic in the scheduler. This heuristic favors

View File

@ -147,6 +147,7 @@ along with GCC; see the file COPYING3. If not see
#include "vecprim.h"
#include "dbgcnt.h"
#include "cfgloop.h"
#include "ira.h"
#ifdef INSN_SCHEDULING
@ -507,8 +508,6 @@ static int rank_for_schedule (const void *, const void *);
static void swap_sort (rtx *, int);
static void queue_insn (rtx, int);
static int schedule_insn (rtx);
static int find_set_reg_weight (const_rtx);
static void find_insn_reg_weight (const_rtx);
static void adjust_priority (rtx);
static void advance_one_cycle (void);
static void extend_h_i_d (void);
@ -588,6 +587,210 @@ schedule_insns (void)
}
#else
/* Do register pressure sensitive insn scheduling if the flag is set
up. */
bool sched_pressure_p;
/* Map regno -> its cover class. The map defined only when
SCHED_PRESSURE_P is true. */
enum reg_class *sched_regno_cover_class;
/* The current register pressure. Only elements corresponding cover
classes are defined. */
static int curr_reg_pressure[N_REG_CLASSES];
/* Saved value of the previous array. */
static int saved_reg_pressure[N_REG_CLASSES];
/* Register living at given scheduling point. */
static bitmap curr_reg_live;
/* Saved value of the previous array. */
static bitmap saved_reg_live;
/* Registers mentioned in the current region. */
static bitmap region_ref_regs;
/* Initiate register pressure relative info for scheduling the current
region. Currently it is only clearing register mentioned in the
current region. */
void
sched_init_region_reg_pressure_info (void)
{
bitmap_clear (region_ref_regs);
}
/* Update current register pressure related info after birth (if
BIRTH_P) or death of register REGNO. */
static void
mark_regno_birth_or_death (int regno, bool birth_p)
{
enum reg_class cover_class;
cover_class = sched_regno_cover_class[regno];
if (regno >= FIRST_PSEUDO_REGISTER)
{
if (cover_class != NO_REGS)
{
if (birth_p)
{
bitmap_set_bit (curr_reg_live, regno);
curr_reg_pressure[cover_class]
+= ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)];
}
else
{
bitmap_clear_bit (curr_reg_live, regno);
curr_reg_pressure[cover_class]
-= ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)];
}
}
}
else if (cover_class != NO_REGS
&& ! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
{
if (birth_p)
{
bitmap_set_bit (curr_reg_live, regno);
curr_reg_pressure[cover_class]++;
}
else
{
bitmap_clear_bit (curr_reg_live, regno);
curr_reg_pressure[cover_class]--;
}
}
}
/* Initiate current register pressure related info from living
registers given by LIVE. */
static void
initiate_reg_pressure_info (bitmap live)
{
int i;
unsigned int j;
bitmap_iterator bi;
for (i = 0; i < ira_reg_class_cover_size; i++)
curr_reg_pressure[ira_reg_class_cover[i]] = 0;
bitmap_clear (curr_reg_live);
EXECUTE_IF_SET_IN_BITMAP (live, 0, j, bi)
if (current_nr_blocks == 1 || bitmap_bit_p (region_ref_regs, j))
mark_regno_birth_or_death (j, true);
}
/* Mark registers in X as mentioned in the current region. */
static void
setup_ref_regs (rtx x)
{
int i, j, regno;
const RTX_CODE code = GET_CODE (x);
const char *fmt;
if (REG_P (x))
{
regno = REGNO (x);
if (regno >= FIRST_PSEUDO_REGISTER)
bitmap_set_bit (region_ref_regs, REGNO (x));
else
for (i = hard_regno_nregs[regno][GET_MODE (x)] - 1; i >= 0; i--)
bitmap_set_bit (region_ref_regs, regno + i);
return;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
setup_ref_regs (XEXP (x, i));
else if (fmt[i] == 'E')
{
for (j = 0; j < XVECLEN (x, i); j++)
setup_ref_regs (XVECEXP (x, i, j));
}
}
/* Initiate current register pressure related info at the start of
basic block BB. */
static void
initiate_bb_reg_pressure_info (basic_block bb)
{
unsigned int i;
rtx insn;
if (current_nr_blocks > 1)
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
setup_ref_regs (PATTERN (insn));
initiate_reg_pressure_info (df_get_live_in (bb));
#ifdef EH_RETURN_DATA_REGNO
if (bb_has_eh_pred (bb))
for (i = 0; ; ++i)
{
unsigned int regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
if (! bitmap_bit_p (df_get_live_in (bb), regno))
mark_regno_birth_or_death (regno, true);
}
#endif
}
/* Save current register pressure related info. */
static void
save_reg_pressure (void)
{
int i;
for (i = 0; i < ira_reg_class_cover_size; i++)
saved_reg_pressure[ira_reg_class_cover[i]]
= curr_reg_pressure[ira_reg_class_cover[i]];
bitmap_copy (saved_reg_live, curr_reg_live);
}
/* Restore saved register pressure related info. */
static void
restore_reg_pressure (void)
{
int i;
for (i = 0; i < ira_reg_class_cover_size; i++)
curr_reg_pressure[ira_reg_class_cover[i]]
= saved_reg_pressure[ira_reg_class_cover[i]];
bitmap_copy (curr_reg_live, saved_reg_live);
}
/* Return TRUE if the register is dying after its USE. */
static bool
dying_use_p (struct reg_use_data *use)
{
struct reg_use_data *next;
for (next = use->next_regno_use; next != use; next = next->next_regno_use)
if (QUEUE_INDEX (next->insn) != QUEUE_SCHEDULED)
return false;
return true;
}
/* Print info about the current register pressure and its excess for
each cover class. */
static void
print_curr_reg_pressure (void)
{
int i;
enum reg_class cl;
fprintf (sched_dump, ";;\t");
for (i = 0; i < ira_reg_class_cover_size; i++)
{
cl = ira_reg_class_cover[i];
gcc_assert (curr_reg_pressure[cl] >= 0);
fprintf (sched_dump, " %s:%d(%d)", reg_class_names[cl],
curr_reg_pressure[cl],
curr_reg_pressure[cl] - ira_available_class_regs[cl]);
}
fprintf (sched_dump, "\n");
}
/* Pointer to the last instruction scheduled. Used by rank_for_schedule,
so that insns independent of the last scheduled insn will be preferred
over dependent instructions. */
@ -657,7 +860,8 @@ dep_cost_1 (dep_t link, dw_t dw)
/* A USE insn should never require the value used to be computed.
This allows the computation of a function's result and parameter
values to overlap the return and call. */
values to overlap the return and call. We don't care about the
the dependence cost when only decreasing register pressure. */
if (recog_memoized (used) < 0)
{
cost = 0;
@ -686,10 +890,8 @@ dep_cost_1 (dep_t link, dw_t dw)
if (targetm.sched.adjust_cost_2)
{
cost = targetm.sched.adjust_cost_2 (used, (int) dep_type, insn, cost,
dw);
}
cost = targetm.sched.adjust_cost_2 (used, (int) dep_type, insn, cost,
dw);
else if (targetm.sched.adjust_cost != NULL)
{
/* This variable is used for backward compatibility with the
@ -906,6 +1108,53 @@ do { if ((N_READY) == 2) \
qsort (READY, N_READY, sizeof (rtx), rank_for_schedule); } \
while (0)
/* Setup info about the current register pressure impact of scheduling
INSN at the current scheduling point. */
static void
setup_insn_reg_pressure_info (rtx insn)
{
int i, change, before, after, hard_regno;
int excess_cost_change;
enum machine_mode mode;
enum reg_class cl;
struct reg_pressure_data *pressure_info;
int *max_reg_pressure;
struct reg_use_data *use;
static int death[N_REG_CLASSES];
excess_cost_change = 0;
for (i = 0; i < ira_reg_class_cover_size; i++)
death[ira_reg_class_cover[i]] = 0;
for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
if (dying_use_p (use))
{
cl = sched_regno_cover_class[use->regno];
if (use->regno < FIRST_PSEUDO_REGISTER)
death[cl]++;
else
death[cl] += ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (use->regno)];
}
pressure_info = INSN_REG_PRESSURE (insn);
max_reg_pressure = INSN_MAX_REG_PRESSURE (insn);
gcc_assert (pressure_info != NULL && max_reg_pressure != NULL);
for (i = 0; i < ira_reg_class_cover_size; i++)
{
cl = ira_reg_class_cover[i];
gcc_assert (curr_reg_pressure[cl] >= 0);
change = (int) pressure_info[i].set_increase - death[cl];
before = MAX (0, max_reg_pressure[i] - ira_available_class_regs[cl]);
after = MAX (0, max_reg_pressure[i] + change
- ira_available_class_regs[cl]);
hard_regno = ira_class_hard_regs[cl][0];
gcc_assert (hard_regno >= 0);
mode = reg_raw_mode[hard_regno];
excess_cost_change += ((after - before)
* (ira_memory_move_cost[mode][cl][0]
+ ira_memory_move_cost[mode][cl][1]));
}
INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insn) = excess_cost_change;
}
/* Returns a positive value if x is preferred; returns a negative value if
y is preferred. Should never return 0, since that will make the sort
unstable. */
@ -917,7 +1166,7 @@ rank_for_schedule (const void *x, const void *y)
rtx tmp2 = *(const rtx *) x;
rtx last;
int tmp_class, tmp2_class;
int val, priority_val, weight_val, info_val;
int val, priority_val, info_val;
if (MAY_HAVE_DEBUG_INSNS)
{
@ -936,12 +1185,38 @@ rank_for_schedule (const void *x, const void *y)
/* Make sure that priority of TMP and TMP2 are initialized. */
gcc_assert (INSN_PRIORITY_KNOWN (tmp) && INSN_PRIORITY_KNOWN (tmp2));
if (sched_pressure_p)
{
int diff;
/* Prefer insn whose scheduling results in the smallest register
pressure excess. */
if ((diff = (INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp)
+ (INSN_TICK (tmp) > clock_var
? INSN_TICK (tmp) - clock_var : 0)
- INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp2)
- (INSN_TICK (tmp2) > clock_var
? INSN_TICK (tmp2) - clock_var : 0))) != 0)
return diff;
}
if (sched_pressure_p
&& (INSN_TICK (tmp2) > clock_var || INSN_TICK (tmp) > clock_var))
{
if (INSN_TICK (tmp) <= clock_var)
return -1;
else if (INSN_TICK (tmp2) <= clock_var)
return 1;
else
return INSN_TICK (tmp) - INSN_TICK (tmp2);
}
/* Prefer insn with higher priority. */
priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp);
if (flag_sched_critical_path_heuristic && priority_val)
return priority_val;
/* Prefer speculative insn with greater dependencies weakness. */
if (flag_sched_spec_insn_heuristic && spec_info)
{
@ -966,11 +1241,6 @@ rank_for_schedule (const void *x, const void *y)
return dw;
}
/* Prefer an insn with smaller contribution to registers-pressure. */
if (flag_sched_reg_pressure_heuristic && !reload_completed &&
(weight_val = INSN_REG_WEIGHT (tmp) - INSN_REG_WEIGHT (tmp2)))
return weight_val;
info_val = (*current_sched_info->rank) (tmp, tmp2);
if(flag_sched_rank_heuristic && info_val)
return info_val;
@ -1222,7 +1492,14 @@ ready_remove_insn (rtx insn)
void
ready_sort (struct ready_list *ready)
{
int i;
rtx *first = ready_lastpos (ready);
if (sched_pressure_p)
{
for (i = 0; i < ready->n_ready; i++)
setup_insn_reg_pressure_info (first[i]);
}
SCHED_SORT (first, ready->n_ready);
}
@ -1278,6 +1555,93 @@ advance_one_cycle (void)
/* Clock at which the previous instruction was issued. */
static int last_clock_var;
/* Update register pressure after scheduling INSN. */
static void
update_register_pressure (rtx insn)
{
struct reg_use_data *use;
struct reg_set_data *set;
for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
if (dying_use_p (use) && bitmap_bit_p (curr_reg_live, use->regno))
mark_regno_birth_or_death (use->regno, false);
for (set = INSN_REG_SET_LIST (insn); set != NULL; set = set->next_insn_set)
mark_regno_birth_or_death (set->regno, true);
}
/* Set up or update (if UPDATE_P) max register pressure (see its
meaning in sched-int.h::_haifa_insn_data) for all current BB insns
after insn AFTER. */
static void
setup_insn_max_reg_pressure (rtx after, bool update_p)
{
int i, p;
bool eq_p;
rtx insn;
static int max_reg_pressure[N_REG_CLASSES];
save_reg_pressure ();
for (i = 0; i < ira_reg_class_cover_size; i++)
max_reg_pressure[ira_reg_class_cover[i]]
= curr_reg_pressure[ira_reg_class_cover[i]];
for (insn = NEXT_INSN (after);
insn != NULL_RTX && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (after);
insn = NEXT_INSN (insn))
if (NONDEBUG_INSN_P (insn))
{
eq_p = true;
for (i = 0; i < ira_reg_class_cover_size; i++)
{
p = max_reg_pressure[ira_reg_class_cover[i]];
if (INSN_MAX_REG_PRESSURE (insn)[i] != p)
{
eq_p = false;
INSN_MAX_REG_PRESSURE (insn)[i]
= max_reg_pressure[ira_reg_class_cover[i]];
}
}
if (update_p && eq_p)
break;
update_register_pressure (insn);
for (i = 0; i < ira_reg_class_cover_size; i++)
if (max_reg_pressure[ira_reg_class_cover[i]]
< curr_reg_pressure[ira_reg_class_cover[i]])
max_reg_pressure[ira_reg_class_cover[i]]
= curr_reg_pressure[ira_reg_class_cover[i]];
}
restore_reg_pressure ();
}
/* Update the current register pressure after scheduling INSN. Update
also max register pressure for unscheduled insns of the current
BB. */
static void
update_reg_and_insn_max_reg_pressure (rtx insn)
{
int i;
int before[N_REG_CLASSES];
for (i = 0; i < ira_reg_class_cover_size; i++)
before[i] = curr_reg_pressure[ira_reg_class_cover[i]];
update_register_pressure (insn);
for (i = 0; i < ira_reg_class_cover_size; i++)
if (curr_reg_pressure[ira_reg_class_cover[i]] != before[i])
break;
if (i < ira_reg_class_cover_size)
setup_insn_max_reg_pressure (insn, true);
}
/* Set up register pressure at the beginning of basic block BB whose
insns starting after insn AFTER. Set up also max register pressure
for all insns of the basic block. */
void
sched_setup_bb_reg_pressure_info (basic_block bb, rtx after)
{
gcc_assert (sched_pressure_p);
initiate_bb_reg_pressure_info (bb);
setup_insn_max_reg_pressure (after, false);
}
/* INSN is the "currently executing insn". Launch each insn which was
waiting on INSN. READY is the ready list which contains the insns
that are ready to fire. CLOCK is the current cycle. The function
@ -1289,10 +1653,12 @@ schedule_insn (rtx insn)
{
sd_iterator_def sd_it;
dep_t dep;
int i;
int advance = 0;
if (sched_verbose >= 1)
{
struct reg_pressure_data *pressure_info;
char buf[2048];
print_insn (buf, insn, 0);
@ -1303,9 +1669,21 @@ schedule_insn (rtx insn)
fprintf (sched_dump, "nothing");
else
print_reservation (sched_dump, insn);
pressure_info = INSN_REG_PRESSURE (insn);
if (pressure_info != NULL)
{
fputc (':', sched_dump);
for (i = 0; i < ira_reg_class_cover_size; i++)
fprintf (sched_dump, "%s%+d(%d)",
reg_class_names[ira_reg_class_cover[i]],
pressure_info[i].set_increase, pressure_info[i].change);
}
fputc ('\n', sched_dump);
}
if (sched_pressure_p)
update_reg_and_insn_max_reg_pressure (insn);
/* Scheduling instruction should have all its dependencies resolved and
should have been removed from the ready list. */
gcc_assert (sd_lists_empty_p (insn, SD_LIST_BACK));
@ -1614,66 +1992,6 @@ restore_other_notes (rtx head, basic_block head_bb)
return head;
}
/* Functions for computation of registers live/usage info. */
/* This function looks for a new register being defined.
If the destination register is already used by the source,
a new register is not needed. */
static int
find_set_reg_weight (const_rtx x)
{
if (GET_CODE (x) == CLOBBER
&& register_operand (SET_DEST (x), VOIDmode))
return 1;
if (GET_CODE (x) == SET
&& register_operand (SET_DEST (x), VOIDmode))
{
if (REG_P (SET_DEST (x)))
{
if (!reg_mentioned_p (SET_DEST (x), SET_SRC (x)))
return 1;
else
return 0;
}
return 1;
}
return 0;
}
/* Calculate INSN_REG_WEIGHT for INSN. */
static void
find_insn_reg_weight (const_rtx insn)
{
int reg_weight = 0;
rtx x;
/* Handle register life information. */
if (! INSN_P (insn))
return;
/* Increment weight for each register born here. */
x = PATTERN (insn);
reg_weight += find_set_reg_weight (x);
if (GET_CODE (x) == PARALLEL)
{
int j;
for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
{
x = XVECEXP (PATTERN (insn), 0, j);
reg_weight += find_set_reg_weight (x);
}
}
/* Decrement weight for each register that dies here. */
for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
{
if (REG_NOTE_KIND (x) == REG_DEAD
|| REG_NOTE_KIND (x) == REG_UNUSED)
reg_weight--;
}
INSN_REG_WEIGHT (insn) = reg_weight;
}
/* Move insns that became ready to fire from queue to ready list. */
static void
@ -1943,7 +2261,18 @@ debug_ready_list (struct ready_list *ready)
p = ready_lastpos (ready);
for (i = 0; i < ready->n_ready; i++)
fprintf (sched_dump, " %s", (*current_sched_info->print_insn) (p[i], 0));
{
fprintf (sched_dump, " %s:%d",
(*current_sched_info->print_insn) (p[i], 0),
INSN_LUID (p[i]));
if (sched_pressure_p)
fprintf (sched_dump, "(cost=%d",
INSN_REG_PRESSURE_EXCESS_COST_CHANGE (p[i]));
if (INSN_TICK (p[i]) > clock_var)
fprintf (sched_dump, ":delay=%d", INSN_TICK (p[i]) - clock_var);
if (sched_pressure_p)
fprintf (sched_dump, ")");
}
fprintf (sched_dump, "\n");
}
@ -2666,6 +2995,8 @@ schedule_block (basic_block *target_bb)
fprintf (sched_dump, ";;\tReady list (t = %3d): ",
clock_var);
debug_ready_list (&ready);
if (sched_pressure_p)
print_curr_reg_pressure ();
}
if (ready.n_ready == 0
@ -2708,6 +3039,13 @@ schedule_block (basic_block *target_bb)
else
insn = ready_remove_first (&ready);
if (sched_pressure_p && INSN_TICK (insn) > clock_var)
{
ready_add (&ready, insn, true);
advance = 1;
break;
}
if (targetm.sched.dfa_new_cycle
&& targetm.sched.dfa_new_cycle (sched_dump, sched_verbose,
insn, last_clock_var,
@ -2745,6 +3083,8 @@ schedule_block (basic_block *target_bb)
fatal error for unrecognizable insns. */
cost = 0;
}
else if (sched_pressure_p)
cost = 0;
else
{
cost = state_transition (temp_state, insn);
@ -2826,7 +3166,6 @@ schedule_block (basic_block *target_bb)
else if (GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER)
can_issue_more--;
advance = schedule_insn (insn);
/* After issuing an asm insn we should start a new cycle. */
@ -3033,6 +3372,11 @@ sched_init (void)
flag_schedule_speculative_load = 0;
#endif
sched_pressure_p = (flag_sched_pressure && ! reload_completed
&& common_sched_info->sched_pass_id == SCHED_RGN_PASS);
if (sched_pressure_p)
ira_setup_eliminable_regset ();
/* Initialize SPEC_INFO. */
if (targetm.sched.set_sched_flags)
{
@ -3108,6 +3452,23 @@ sched_init (void)
targetm.sched.md_init_global (sched_dump, sched_verbose,
get_max_uid () + 1);
if (sched_pressure_p)
{
int i, max_regno = max_reg_num ();
ira_set_pseudo_classes (sched_verbose ? sched_dump : NULL);
sched_regno_cover_class
= (enum reg_class *) xmalloc (max_regno * sizeof (enum reg_class));
for (i = 0; i < max_regno; i++)
sched_regno_cover_class[i]
= (i < FIRST_PSEUDO_REGISTER
? ira_class_translate[REGNO_REG_CLASS (i)]
: reg_cover_class (i));
curr_reg_live = BITMAP_ALLOC (NULL);
saved_reg_live = BITMAP_ALLOC (NULL);
region_ref_regs = BITMAP_ALLOC (NULL);
}
curr_state = xmalloc (dfa_state_size);
}
@ -3205,6 +3566,13 @@ void
sched_finish (void)
{
haifa_finish_h_i_d ();
if (sched_pressure_p)
{
free (sched_regno_cover_class);
BITMAP_FREE (region_ref_regs);
BITMAP_FREE (saved_reg_live);
BITMAP_FREE (curr_reg_live);
}
free (curr_state);
if (targetm.sched.md_finish_global)
@ -3514,7 +3882,7 @@ fix_tick_ready (rtx next)
INSN_TICK (next) = tick;
delay = tick - clock_var;
if (delay <= 0)
if (delay <= 0 || sched_pressure_p)
delay = QUEUE_READY;
change_queue_index (next, delay);
@ -5091,7 +5459,6 @@ init_h_i_d (rtx insn)
if (INSN_LUID (insn) > 0)
{
INSN_COST (insn) = -1;
find_insn_reg_weight (insn);
QUEUE_INDEX (insn) = QUEUE_NOWHERE;
INSN_TICK (insn) = INVALID_TICK;
INTER_TICK (insn) = INVALID_TICK;
@ -5118,6 +5485,20 @@ haifa_init_h_i_d (bb_vec_t bbs, basic_block bb, insn_vec_t insns, rtx insn)
void
haifa_finish_h_i_d (void)
{
int i;
haifa_insn_data_t data;
struct reg_use_data *use, *next;
for (i = 0; VEC_iterate (haifa_insn_data_def, h_i_d, i, data); i++)
{
if (data->reg_pressure != NULL)
free (data->reg_pressure);
for (use = data->reg_use_list; use != NULL; use = next)
{
next = use->next_insn_use;
free (use);
}
}
VEC_free (haifa_insn_data_def, heap, h_i_d);
}

View File

@ -1,4 +1,4 @@
/* IRA hard register and memory cost calculation for allocnos.
/* IRA hard register and memory cost calculation for allocnos or pseudos.
Copyright (C) 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
@ -38,18 +38,25 @@ along with GCC; see the file COPYING3. If not see
#include "params.h"
#include "ira-int.h"
/* The file contains code is similar to one in regclass but the code
works on the allocno basis. */
/* The flags is set up every time when we calculate pseudo register
classes through function ira_set_pseudo_classes. */
static bool pseudo_classes_defined_p = false;
/* TRUE if we work with allocnos. Otherwise we work with pseudos. */
static bool allocno_p;
/* Number of elements in arrays `in_inc_dec' and `costs'. */
static int cost_elements_num;
#ifdef FORBIDDEN_INC_DEC_CLASSES
/* Indexed by n, is TRUE if allocno with number N is used in an
auto-inc or auto-dec context. */
/* Indexed by n, is TRUE if allocno or pseudo with number N is used in
an auto-inc or auto-dec context. */
static bool *in_inc_dec;
#endif
/* The `costs' struct records the cost of using hard registers of each
class considered for the calculation and of using memory for each
allocno. */
allocno or pseudo. */
struct costs
{
int mem_cost;
@ -74,8 +81,11 @@ static struct costs *temp_costs;
static struct costs *op_costs[MAX_RECOG_OPERANDS];
static struct costs *this_op_costs[MAX_RECOG_OPERANDS];
/* Original and accumulated costs of each class for each allocno. */
static struct costs *allocno_costs, *total_costs;
/* Costs of each class for each allocno or pseudo. */
static struct costs *costs;
/* Accumulated costs of each class for each allocno. */
static struct costs *total_allocno_costs;
/* Classes used for cost calculation. They may be different on
different iterations of the cost calculations or in different
@ -92,21 +102,26 @@ static int cost_class_nums[N_REG_CLASSES];
/* It is the current size of struct costs. */
static int struct_costs_size;
/* Return pointer to structure containing costs of allocno with given
NUM in array ARR. */
#define COSTS_OF_ALLOCNO(arr, num) \
/* Return pointer to structure containing costs of allocno or pseudo
with given NUM in array ARR. */
#define COSTS(arr, num) \
((struct costs *) ((char *) (arr) + (num) * struct_costs_size))
/* Record register class preferences of each allocno. Null value
means no preferences. It happens on the 1st iteration of the cost
calculation. */
static enum reg_class *allocno_pref;
/* Return index in COSTS when processing reg with REGNO. */
#define COST_INDEX(regno) (allocno_p \
? ALLOCNO_NUM (ira_curr_regno_allocno_map[regno]) \
: (int) regno)
/* Allocated buffers for allocno_pref. */
static enum reg_class *allocno_pref_buffer;
/* Record register class preferences of each allocno or pseudo. Null
value means no preferences. It happens on the 1st iteration of the
cost calculation. */
static enum reg_class *pref;
/* Record register class of each allocno with the same regno. */
static enum reg_class *common_classes;
/* Allocated buffers for pref. */
static enum reg_class *pref_buffer;
/* Record cover register class of each allocno with the same regno. */
static enum reg_class *regno_cover_class;
/* Execution frequency of the current insn. */
static int frequency;
@ -189,7 +204,7 @@ static void
record_reg_classes (int n_alts, int n_ops, rtx *ops,
enum machine_mode *modes, const char **constraints,
rtx insn, struct costs **op_costs,
enum reg_class *allocno_pref)
enum reg_class *pref)
{
int alt;
int i, j, k;
@ -320,12 +335,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
were not in the appropriate class. We could use
cover class here but it is less accurate
approximation. */
if (allocno_pref)
if (pref)
{
enum reg_class pref_class
= allocno_pref[ALLOCNO_NUM
(ira_curr_regno_allocno_map
[REGNO (op)])];
enum reg_class pref_class = pref[COST_INDEX (REGNO (op))];
if (pref_class == NO_REGS)
alt_cost
@ -564,12 +576,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
were not in the appropriate class. We could use
cover class here but it is less accurate
approximation. */
if (allocno_pref)
if (pref)
{
enum reg_class pref_class
= allocno_pref[ALLOCNO_NUM
(ira_curr_regno_allocno_map
[REGNO (op)])];
enum reg_class pref_class = pref[COST_INDEX (REGNO (op))];
if (pref_class == NO_REGS)
alt_cost
@ -637,17 +646,18 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
}
}
for (i = 0; i < n_ops; i++)
{
ira_allocno_t a;
rtx op = ops[i];
if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
continue;
a = ira_curr_regno_allocno_map [REGNO (op)];
if (! ALLOCNO_BAD_SPILL_P (a) && insn_allows_mem[i] == 0)
ALLOCNO_BAD_SPILL_P (a) = true;
}
if (allocno_p)
for (i = 0; i < n_ops; i++)
{
ira_allocno_t a;
rtx op = ops[i];
if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
continue;
a = ira_curr_regno_allocno_map [REGNO (op)];
if (! ALLOCNO_BAD_SPILL_P (a) && insn_allows_mem[i] == 0)
ALLOCNO_BAD_SPILL_P (a) = true;
}
/* If this insn is a single set copying operand 1 to operand 0 and
one operand is an allocno with the other a hard reg or an allocno
@ -877,8 +887,7 @@ record_address_regs (enum machine_mode mode, rtx x, int context,
#ifdef FORBIDDEN_INC_DEC_CLASSES
if (REG_P (XEXP (x, 0))
&& REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER)
in_inc_dec[ALLOCNO_NUM (ira_curr_regno_allocno_map
[REGNO (XEXP (x, 0))])] = true;
in_inc_dec[COST_INDEX (REGNO (XEXP (x, 0)))] = true;
#endif
record_address_regs (mode, XEXP (x, 0), 0, code, SCRATCH, 2 * scale);
break;
@ -892,10 +901,9 @@ record_address_regs (enum machine_mode mode, rtx x, int context,
if (REGNO (x) < FIRST_PSEUDO_REGISTER)
break;
ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[REGNO (x)]) = true;
pp = COSTS_OF_ALLOCNO (allocno_costs,
ALLOCNO_NUM (ira_curr_regno_allocno_map
[REGNO (x)]));
if (allocno_p)
ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[REGNO (x)]) = true;
pp = COSTS (costs, COST_INDEX (REGNO (x)));
pp->mem_cost += (ira_memory_move_cost[Pmode][rclass][1] * scale) / 2;
for (k = 0; k < cost_classes_num; k++)
{
@ -922,8 +930,7 @@ record_address_regs (enum machine_mode mode, rtx x, int context,
/* Calculate the costs of insn operands. */
static void
record_operand_costs (rtx insn, struct costs **op_costs,
enum reg_class *allocno_pref)
record_operand_costs (rtx insn, struct costs **op_costs, enum reg_class *pref)
{
const char *constraints[MAX_RECOG_OPERANDS];
enum machine_mode modes[MAX_RECOG_OPERANDS];
@ -976,11 +983,11 @@ record_operand_costs (rtx insn, struct costs **op_costs,
xconstraints[i+1] = constraints[i];
record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
recog_data.operand, modes,
xconstraints, insn, op_costs, allocno_pref);
xconstraints, insn, op_costs, pref);
}
record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
recog_data.operand, modes,
constraints, insn, op_costs, allocno_pref);
constraints, insn, op_costs, pref);
}
@ -1015,17 +1022,17 @@ scan_one_insn (rtx insn)
{
enum reg_class cl = GENERAL_REGS;
rtx reg = SET_DEST (set);
int num = ALLOCNO_NUM (ira_curr_regno_allocno_map[REGNO (reg)]);
int num = COST_INDEX (REGNO (reg));
if (allocno_pref)
cl = allocno_pref[num];
COSTS_OF_ALLOCNO (allocno_costs, num)->mem_cost
if (pref)
cl = pref[num];
COSTS (costs, num)->mem_cost
-= ira_memory_move_cost[GET_MODE (reg)][cl][1] * frequency;
record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0),
0, MEM, SCRATCH, frequency * 2);
}
record_operand_costs (insn, op_costs, allocno_pref);
record_operand_costs (insn, op_costs, pref);
/* Now add the cost for each operand to the total costs for its
allocno. */
@ -1034,9 +1041,7 @@ scan_one_insn (rtx insn)
&& REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER)
{
int regno = REGNO (recog_data.operand[i]);
struct costs *p
= COSTS_OF_ALLOCNO (allocno_costs,
ALLOCNO_NUM (ira_curr_regno_allocno_map[regno]));
struct costs *p = COSTS (costs, COST_INDEX (regno));
struct costs *q = op_costs[i];
p->mem_cost += q->mem_cost;
@ -1051,12 +1056,13 @@ scan_one_insn (rtx insn)
/* Print allocnos costs to file F. */
static void
print_costs (FILE *f)
print_allocno_costs (FILE *f)
{
int k;
ira_allocno_t a;
ira_allocno_iterator ai;
ira_assert (allocno_p);
fprintf (f, "\n");
FOR_EACH_ALLOCNO (a, ai)
{
@ -1085,57 +1091,114 @@ print_costs (FILE *f)
)
{
fprintf (f, " %s:%d", reg_class_names[rclass],
COSTS_OF_ALLOCNO (allocno_costs, i)->cost[k]);
COSTS (costs, i)->cost[k]);
if (flag_ira_region == IRA_REGION_ALL
|| flag_ira_region == IRA_REGION_MIXED)
fprintf (f, ",%d", COSTS_OF_ALLOCNO (total_costs, i)->cost[k]);
fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]);
}
}
fprintf (f, " MEM:%i\n", COSTS_OF_ALLOCNO (allocno_costs, i)->mem_cost);
fprintf (f, " MEM:%i\n", COSTS (costs, i)->mem_cost);
}
}
/* Print pseudo costs to file F. */
static void
print_pseudo_costs (FILE *f)
{
int regno, k;
int rclass;
ira_assert (! allocno_p);
fprintf (f, "\n");
for (regno = max_reg_num () - 1; regno >= FIRST_PSEUDO_REGISTER; regno--)
{
if (regno_reg_rtx[regno] == NULL_RTX)
continue;
fprintf (f, " r%d costs:", regno);
for (k = 0; k < cost_classes_num; k++)
{
rclass = cost_classes[k];
if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
#ifdef FORBIDDEN_INC_DEC_CLASSES
&& (! in_inc_dec[regno] || ! forbidden_inc_dec_class[rclass])
#endif
#ifdef CANNOT_CHANGE_MODE_CLASS
&& ! invalid_mode_change_p (regno, (enum reg_class) rclass,
PSEUDO_REGNO_MODE (regno))
#endif
)
fprintf (f, " %s:%d", reg_class_names[rclass],
COSTS (costs, regno)->cost[k]);
}
fprintf (f, " MEM:%i\n", COSTS (costs, regno)->mem_cost);
}
}
/* Traverse the BB represented by LOOP_TREE_NODE to update the allocno
costs. */
static void
process_bb_for_costs (basic_block bb)
{
rtx insn;
frequency = REG_FREQ_FROM_BB (bb);
if (frequency == 0)
frequency = 1;
FOR_BB_INSNS (bb, insn)
insn = scan_one_insn (insn);
}
/* Traverse the BB represented by LOOP_TREE_NODE to update the allocno
costs. */
static void
process_bb_node_for_costs (ira_loop_tree_node_t loop_tree_node)
{
basic_block bb;
rtx insn;
bb = loop_tree_node->bb;
if (bb == NULL)
return;
frequency = REG_FREQ_FROM_BB (bb);
if (frequency == 0)
frequency = 1;
FOR_BB_INSNS (bb, insn)
insn = scan_one_insn (insn);
if (bb != NULL)
process_bb_for_costs (bb);
}
/* Find costs of register classes and memory for allocnos and their
best costs. */
/* Find costs of register classes and memory for allocnos or pseudos
and their best costs. Set up preferred, alternative and cover
classes for pseudos. */
static void
find_allocno_class_costs (void)
find_costs_and_classes (FILE *dump_file)
{
int i, k;
int i, k, start;
int pass;
basic_block bb;
init_recog ();
#ifdef FORBIDDEN_INC_DEC_CLASSES
in_inc_dec = ira_allocate (sizeof (bool) * ira_allocnos_num);
in_inc_dec = ira_allocate (sizeof (bool) * cost_elements_num);
#endif /* FORBIDDEN_INC_DEC_CLASSES */
allocno_pref = NULL;
pref = NULL;
start = 0;
if (!resize_reg_info () && allocno_p && pseudo_classes_defined_p)
{
ira_allocno_t a;
ira_allocno_iterator ai;
pref = pref_buffer;
FOR_EACH_ALLOCNO (a, ai)
pref[ALLOCNO_NUM (a)] = reg_preferred_class (ALLOCNO_REGNO (a));
if (flag_expensive_optimizations)
start = 1;
}
if (allocno_p)
/* Clear the flag for the next compiled function. */
pseudo_classes_defined_p = false;
/* Normally we scan the insns once and determine the best class to
use for each allocno. However, if -fexpensive-optimizations are
on, we do so twice, the second time using the tentative best
classes to guide the selection. */
for (pass = 0; pass <= flag_expensive_optimizations; pass++)
for (pass = start; pass <= flag_expensive_optimizations; pass++)
{
if (internal_flag_ira_verbose > 0 && ira_dump_file)
fprintf (ira_dump_file, "\nPass %i for finding allocno costs\n\n",
pass);
if ((!allocno_p || internal_flag_ira_verbose > 0) && dump_file)
fprintf (dump_file,
"\nPass %i for finding pseudo/allocno costs\n\n", pass);
/* We could use only cover classes. Unfortunately it does not
work well for some targets where some subclass of cover class
is costly and wrong cover class is chosen. */
@ -1154,20 +1217,31 @@ find_allocno_class_costs (void)
= sizeof (struct costs) + sizeof (int) * (cost_classes_num - 1);
/* Zero out our accumulation of the cost of each class for each
allocno. */
memset (allocno_costs, 0, ira_allocnos_num * struct_costs_size);
memset (costs, 0, cost_elements_num * struct_costs_size);
#ifdef FORBIDDEN_INC_DEC_CLASSES
memset (in_inc_dec, 0, ira_allocnos_num * sizeof (bool));
memset (in_inc_dec, 0, cost_elements_num * sizeof (bool));
#endif
/* Scan the instructions and record each time it would save code
to put a certain allocno in a certain class. */
ira_traverse_loop_tree (true, ira_loop_tree_root,
process_bb_node_for_costs, NULL);
if (allocno_p)
{
/* Scan the instructions and record each time it would save code
to put a certain allocno in a certain class. */
ira_traverse_loop_tree (true, ira_loop_tree_root,
process_bb_node_for_costs, NULL);
memcpy (total_allocno_costs, costs,
max_struct_costs_size * ira_allocnos_num);
}
else
{
basic_block bb;
FOR_EACH_BB (bb)
process_bb_for_costs (bb);
}
memcpy (total_costs, allocno_costs,
max_struct_costs_size * ira_allocnos_num);
if (pass == 0)
allocno_pref = allocno_pref_buffer;
pref = pref_buffer;
/* Now for each allocno look at how desirable each class is and
find which class is preferred. */
@ -1182,41 +1256,52 @@ find_allocno_class_costs (void)
int inc_dec_p = false;
#endif
if (ira_regno_allocno_map[i] == NULL)
continue;
memset (temp_costs, 0, struct_costs_size);
/* Find cost of all allocnos with the same regno. */
for (a = ira_regno_allocno_map[i];
a != NULL;
a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
if (! allocno_p)
{
a_num = ALLOCNO_NUM (a);
if ((flag_ira_region == IRA_REGION_ALL
|| flag_ira_region == IRA_REGION_MIXED)
&& (parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) != NULL
&& (parent_a = parent->regno_allocno_map[i]) != NULL
/* There are no caps yet. */
&& bitmap_bit_p (ALLOCNO_LOOP_TREE_NODE (a)->border_allocnos,
ALLOCNO_NUM (a)))
{
/* Propagate costs to upper levels in the region
tree. */
parent_a_num = ALLOCNO_NUM (parent_a);
for (k = 0; k < cost_classes_num; k++)
COSTS_OF_ALLOCNO (total_costs, parent_a_num)->cost[k]
+= COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k];
COSTS_OF_ALLOCNO (total_costs, parent_a_num)->mem_cost
+= COSTS_OF_ALLOCNO (total_costs, a_num)->mem_cost;
}
for (k = 0; k < cost_classes_num; k++)
temp_costs->cost[k]
+= COSTS_OF_ALLOCNO (allocno_costs, a_num)->cost[k];
temp_costs->mem_cost
+= COSTS_OF_ALLOCNO (allocno_costs, a_num)->mem_cost;
if (regno_reg_rtx[i] == NULL_RTX)
continue;
#ifdef FORBIDDEN_INC_DEC_CLASSES
if (in_inc_dec[a_num])
inc_dec_p = true;
inc_dec_p = in_inc_dec[i];
#endif
memcpy (temp_costs, COSTS (costs, i), struct_costs_size);
}
else
{
if (ira_regno_allocno_map[i] == NULL)
continue;
memset (temp_costs, 0, struct_costs_size);
/* Find cost of all allocnos with the same regno. */
for (a = ira_regno_allocno_map[i];
a != NULL;
a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
{
a_num = ALLOCNO_NUM (a);
if ((flag_ira_region == IRA_REGION_ALL
|| flag_ira_region == IRA_REGION_MIXED)
&& (parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) != NULL
&& (parent_a = parent->regno_allocno_map[i]) != NULL
/* There are no caps yet. */
&& bitmap_bit_p (ALLOCNO_LOOP_TREE_NODE
(a)->border_allocnos,
ALLOCNO_NUM (a)))
{
/* Propagate costs to upper levels in the region
tree. */
parent_a_num = ALLOCNO_NUM (parent_a);
for (k = 0; k < cost_classes_num; k++)
COSTS (total_allocno_costs, parent_a_num)->cost[k]
+= COSTS (total_allocno_costs, a_num)->cost[k];
COSTS (total_allocno_costs, parent_a_num)->mem_cost
+= COSTS (total_allocno_costs, a_num)->mem_cost;
}
for (k = 0; k < cost_classes_num; k++)
temp_costs->cost[k] += COSTS (costs, a_num)->cost[k];
temp_costs->mem_cost += COSTS (costs, a_num)->mem_cost;
#ifdef FORBIDDEN_INC_DEC_CLASSES
if (in_inc_dec[a_num])
inc_dec_p = true;
#endif
}
}
best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
best = ALL_REGS;
@ -1252,35 +1337,42 @@ find_allocno_class_costs (void)
alt_class = reg_class_subunion[alt_class][rclass];
}
alt_class = ira_class_translate[alt_class];
if (best_cost > temp_costs->mem_cost)
regno_cover_class[i] = NO_REGS;
else if (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY)
/* Make the common class the biggest class of best and
alt_class. */
regno_cover_class[i] = alt_class == NO_REGS ? best : alt_class;
else
/* Make the common class a cover class. Remember all
allocnos with the same regno should have the same cover
class. */
regno_cover_class[i] = ira_class_translate[best];
if (pass == flag_expensive_optimizations)
{
if (best_cost > temp_costs->mem_cost)
best = alt_class = NO_REGS;
else if (best == alt_class)
alt_class = NO_REGS;
setup_reg_classes (i, best, alt_class);
if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
fprintf (ira_dump_file,
" r%d: preferred %s, alternative %s\n",
i, reg_class_names[best], reg_class_names[alt_class]);
setup_reg_classes (i, best, alt_class, regno_cover_class[i]);
if ((!allocno_p || internal_flag_ira_verbose > 2)
&& dump_file != NULL)
fprintf (dump_file,
" r%d: preferred %s, alternative %s, cover %s\n",
i, reg_class_names[best], reg_class_names[alt_class],
reg_class_names[regno_cover_class[i]]);
}
if (! allocno_p)
{
pref[i] = best_cost > temp_costs->mem_cost ? NO_REGS : best;
continue;
}
if (best_cost > temp_costs->mem_cost)
common_classes[i] = NO_REGS;
else if (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY)
/* Make the common class the biggest class of best and
alt_class. */
common_classes[i] = alt_class == NO_REGS ? best : alt_class;
else
/* Make the common class a cover class. Remember all
allocnos with the same regno should have the same cover
class. */
common_classes[i] = ira_class_translate[best];
for (a = ira_regno_allocno_map[i];
a != NULL;
a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
{
a_num = ALLOCNO_NUM (a);
if (common_classes[i] == NO_REGS)
if (regno_cover_class[i] == NO_REGS)
best = NO_REGS;
else
{
@ -1292,7 +1384,7 @@ find_allocno_class_costs (void)
for (k = 0; k < cost_classes_num; k++)
{
rclass = cost_classes[k];
if (! ira_class_subset_p[rclass][common_classes[i]])
if (! ira_class_subset_p[rclass][regno_cover_class[i]])
continue;
/* Ignore classes that are too small for this
operand or invalid for an operand that was
@ -1307,50 +1399,50 @@ find_allocno_class_costs (void)
#endif
)
;
else if (COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k]
else if (COSTS (total_allocno_costs, a_num)->cost[k]
< best_cost)
{
best_cost
= COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k];
allocno_cost
= COSTS_OF_ALLOCNO (allocno_costs, a_num)->cost[k];
= COSTS (total_allocno_costs, a_num)->cost[k];
allocno_cost = COSTS (costs, a_num)->cost[k];
best = (enum reg_class) rclass;
}
else if (COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k]
else if (COSTS (total_allocno_costs, a_num)->cost[k]
== best_cost)
{
best = ira_reg_class_union[best][rclass];
allocno_cost
= MAX (allocno_cost,
COSTS_OF_ALLOCNO (allocno_costs,
a_num)->cost[k]);
= MAX (allocno_cost, COSTS (costs, a_num)->cost[k]);
}
}
ALLOCNO_COVER_CLASS_COST (a) = allocno_cost;
}
ira_assert (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY
|| ira_class_translate[best] == common_classes[i]);
if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL
&& (pass == 0 || allocno_pref[a_num] != best))
|| ira_class_translate[best] == regno_cover_class[i]);
if (internal_flag_ira_verbose > 2 && dump_file != NULL
&& (pass == 0 || pref[a_num] != best))
{
fprintf (ira_dump_file, " a%d (r%d,", a_num, i);
fprintf (dump_file, " a%d (r%d,", a_num, i);
if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
fprintf (ira_dump_file, "b%d", bb->index);
fprintf (dump_file, "b%d", bb->index);
else
fprintf (ira_dump_file, "l%d",
fprintf (dump_file, "l%d",
ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
fprintf (ira_dump_file, ") best %s, cover %s\n",
fprintf (dump_file, ") best %s, cover %s\n",
reg_class_names[best],
reg_class_names[common_classes[i]]);
reg_class_names[regno_cover_class[i]]);
}
allocno_pref[a_num] = best;
pref[a_num] = best;
}
}
if (internal_flag_ira_verbose > 4 && ira_dump_file)
if (internal_flag_ira_verbose > 4 && dump_file)
{
print_costs (ira_dump_file);
fprintf (ira_dump_file,"\n");
if (allocno_p)
print_allocno_costs (dump_file);
else
print_pseudo_costs (dump_file);
fprintf (dump_file,"\n");
}
}
#ifdef FORBIDDEN_INC_DEC_CLASSES
@ -1443,23 +1535,22 @@ setup_allocno_cover_class_and_costs (void)
int *reg_costs;
enum reg_class cover_class, rclass;
enum machine_mode mode;
HARD_REG_SET *pref;
ira_allocno_t a;
ira_allocno_iterator ai;
ira_assert (allocno_p);
FOR_EACH_ALLOCNO (a, ai)
{
i = ALLOCNO_NUM (a);
mode = ALLOCNO_MODE (a);
cover_class = common_classes[ALLOCNO_REGNO (a)];
ira_assert (allocno_pref[i] == NO_REGS || cover_class != NO_REGS);
ALLOCNO_MEMORY_COST (a) = COSTS_OF_ALLOCNO (allocno_costs, i)->mem_cost;
cover_class = regno_cover_class[ALLOCNO_REGNO (a)];
ira_assert (pref[i] == NO_REGS || cover_class != NO_REGS);
ALLOCNO_MEMORY_COST (a) = COSTS (costs, i)->mem_cost;
ira_set_allocno_cover_class (a, cover_class);
if (cover_class == NO_REGS)
continue;
ALLOCNO_AVAILABLE_REGS_NUM (a) = ira_available_class_regs[cover_class];
pref = &reg_class_contents[allocno_pref[i]];
if (optimize && ALLOCNO_COVER_CLASS (a) != allocno_pref[i])
if (optimize && ALLOCNO_COVER_CLASS (a) != pref[i])
{
n = ira_class_hard_regs_num[cover_class];
ALLOCNO_HARD_REG_COSTS (a)
@ -1467,7 +1558,7 @@ setup_allocno_cover_class_and_costs (void)
for (j = n - 1; j >= 0; j--)
{
regno = ira_class_hard_regs[cover_class][j];
if (TEST_HARD_REG_BIT (*pref, regno))
if (TEST_HARD_REG_BIT (reg_class_contents[pref[i]], regno))
reg_costs[j] = ALLOCNO_COVER_CLASS_COST (a);
else
{
@ -1482,7 +1573,7 @@ setup_allocno_cover_class_and_costs (void)
== cover_class);
num = cost_class_nums[cover_class];
}
reg_costs[j] = COSTS_OF_ALLOCNO (allocno_costs, i)->cost[num];
reg_costs[j] = COSTS (costs, i)->cost[num];
}
}
}
@ -1569,27 +1660,58 @@ ira_finish_costs_once (void)
/* Common initialization function for ira_costs and
ira_set_pseudo_classes. */
static void
init_costs (void)
{
costs = (struct costs *) ira_allocate (max_struct_costs_size
* cost_elements_num);
pref_buffer
= (enum reg_class *) ira_allocate (sizeof (enum reg_class)
* cost_elements_num);
regno_cover_class
= (enum reg_class *) ira_allocate (sizeof (enum reg_class)
* max_reg_num ());
}
/* Common finalization function for ira_costs and
ira_set_pseudo_classes. */
static void
finish_costs (void)
{
ira_free (regno_cover_class);
ira_free (pref_buffer);
ira_free (costs);
}
/* Entry function which defines cover class, memory and hard register
costs for each allocno. */
void
ira_costs (void)
{
allocno_costs = (struct costs *) ira_allocate (max_struct_costs_size
* ira_allocnos_num);
total_costs = (struct costs *) ira_allocate (max_struct_costs_size
* ira_allocnos_num);
allocno_pref_buffer
= (enum reg_class *) ira_allocate (sizeof (enum reg_class)
* ira_allocnos_num);
common_classes
= (enum reg_class *) ira_allocate (sizeof (enum reg_class)
* max_reg_num ());
find_allocno_class_costs ();
allocno_p = true;
cost_elements_num = ira_allocnos_num;
init_costs ();
total_allocno_costs = (struct costs *) ira_allocate (max_struct_costs_size
* ira_allocnos_num);
find_costs_and_classes (ira_dump_file);
setup_allocno_cover_class_and_costs ();
ira_free (common_classes);
ira_free (allocno_pref_buffer);
ira_free (total_costs);
ira_free (allocno_costs);
finish_costs ();
ira_free (total_allocno_costs);
}
/* Entry function which defines classes for pseudos. */
void
ira_set_pseudo_classes (FILE *dump_file)
{
allocno_p = false;
internal_flag_ira_verbose = flag_ira_verbose;
cost_elements_num = max_reg_num ();
init_costs ();
find_costs_and_classes (dump_file);
pseudo_classes_defined_p = true;
finish_costs ();
}

View File

@ -565,18 +565,7 @@ extern int ira_reg_cost, ira_mem_cost;
extern int ira_load_cost, ira_store_cost, ira_shuffle_cost;
extern int ira_move_loops_num, ira_additional_jumps_num;
/* Map: hard register number -> cover class it belongs to. If the
corresponding class is NO_REGS, the hard register is not available
for allocation. */
extern enum reg_class ira_hard_regno_cover_class[FIRST_PSEUDO_REGISTER];
/* Map: register class x machine mode -> number of hard registers of
given class needed to store value of given mode. If the number for
some hard-registers of the register class is different, the size
will be negative. */
extern int ira_reg_class_nregs[N_REG_CLASSES][MAX_MACHINE_MODE];
/* Maximal value of the previous array elements. */
/* Maximal value of element of array ira_reg_class_nregs. */
extern int ira_max_nregs;
/* The number of bits in each element of array used to implement a bit
@ -730,10 +719,9 @@ ira_allocno_set_iter_next (ira_allocno_set_iterator *i)
extern HARD_REG_SET ira_reg_mode_hard_regset
[FIRST_PSEUDO_REGISTER][NUM_MACHINE_MODES];
/* Arrays analogous to macros MEMORY_MOVE_COST and REGISTER_MOVE_COST.
Don't use ira_register_move_cost directly. Use function of
/* Array analogous to macro REGISTER_MOVE_COST. Don't use
ira_register_move_cost directly. Use function of
ira_get_may_move_cost instead. */
extern short ira_memory_move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][2];
extern move_table *ira_register_move_cost[MAX_MACHINE_MODE];
/* Similar to may_move_in_cost but it is calculated in IRA instead of
@ -755,29 +743,12 @@ extern move_table *ira_may_move_out_cost[MAX_MACHINE_MODE];
allocation. */
extern int ira_class_subset_p[N_REG_CLASSES][N_REG_CLASSES];
/* Array of number of hard registers of given class which are
available for the allocation. The order is defined by the
allocation order. */
extern short ira_class_hard_regs[N_REG_CLASSES][FIRST_PSEUDO_REGISTER];
/* The number of elements of the above array for given register
class. */
extern int ira_class_hard_regs_num[N_REG_CLASSES];
/* Index (in ira_class_hard_regs) for given register class and hard
register (in general case a hard register can belong to several
register classes). The index is negative for hard registers
unavailable for the allocation. */
extern short ira_class_hard_reg_index[N_REG_CLASSES][FIRST_PSEUDO_REGISTER];
/* Function specific hard registers can not be used for the register
allocation. */
extern HARD_REG_SET ira_no_alloc_regs;
/* Number of given class hard registers available for the register
allocation for given classes. */
extern int ira_available_class_regs[N_REG_CLASSES];
/* Array whose values are hard regset of hard registers available for
the allocation of given register class whose HARD_REGNO_MODE_OK
values for given mode are zero. */
@ -789,16 +760,6 @@ extern HARD_REG_SET prohibited_class_mode_regs
prohibited. */
extern HARD_REG_SET ira_prohibited_mode_move_regs[NUM_MACHINE_MODES];
/* Number of cover classes. Cover classes is non-intersected register
classes containing all hard-registers available for the
allocation. */
extern int ira_reg_class_cover_size;
/* The array containing cover classes (see also comments for macro
IRA_COVER_CLASSES). Only first IRA_REG_CLASS_COVER_SIZE elements are
used for this. */
extern enum reg_class ira_reg_class_cover[N_REG_CLASSES];
/* The value is number of elements in the subsequent array. */
extern int ira_important_classes_num;
@ -812,11 +773,6 @@ extern enum reg_class ira_important_classes[N_REG_CLASSES];
classes. */
extern int ira_important_class_nums[N_REG_CLASSES];
/* Map of all register classes to corresponding cover class containing
the given class. If given class is not a subset of a cover class,
we translate it into the cheapest cover class. */
extern enum reg_class ira_class_translate[N_REG_CLASSES];
/* The biggest important class inside of intersection of the two
classes (that is calculated taking only hard registers available
for allocation into account). If the both classes contain no hard

View File

@ -702,7 +702,8 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const)
? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT (c, constraints));
if ((cl != NO_REGS && next_cl != cl)
|| ira_available_class_regs[next_cl] > 1)
|| (ira_available_class_regs[next_cl]
> ira_reg_class_nregs[next_cl][GET_MODE (op)]))
return NO_REGS;
cl = next_cl;
break;
@ -712,8 +713,10 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const)
next_cl
= single_reg_class (recog_data.constraints[c - '0'],
recog_data.operand[c - '0'], NULL_RTX);
if ((cl != NO_REGS && next_cl != cl) || next_cl == NO_REGS
|| ira_available_class_regs[next_cl] > 1)
if ((cl != NO_REGS && next_cl != cl)
|| next_cl == NO_REGS
|| (ira_available_class_regs[next_cl]
> ira_reg_class_nregs[next_cl][GET_MODE (op)]))
return NO_REGS;
cl = next_cl;
break;
@ -736,6 +739,62 @@ single_reg_operand_class (int op_num)
recog_data.operand[op_num], NULL_RTX);
}
/* The function sets up hard register set *SET to hard registers which
might be used by insn reloads because the constraints are too
strict. */
void
ira_implicitly_set_insn_hard_regs (HARD_REG_SET *set)
{
int i, c, regno;
bool ignore_p;
enum reg_class cl;
rtx op;
enum machine_mode mode;
CLEAR_HARD_REG_SET (*set);
for (i = 0; i < recog_data.n_operands; i++)
{
op = recog_data.operand[i];
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) == SCRATCH
|| (REG_P (op) && (regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER))
{
const char *p = recog_data.constraints[i];
mode = (GET_CODE (op) == SCRATCH
? GET_MODE (op) : PSEUDO_REGNO_MODE (regno));
cl = NO_REGS;
for (ignore_p = false; (c = *p); p += CONSTRAINT_LEN (c, p))
if (c == '#')
ignore_p = true;
else if (c == ',')
ignore_p = false;
else if (! ignore_p)
switch (c)
{
case 'r':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'h': case 'j': case 'k': case 'l':
case 'q': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D':
case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'W': case 'Y': case 'Z':
cl = (c == 'r'
? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT (c, p));
if (cl != NO_REGS
&& (ira_available_class_regs[cl]
<= ira_reg_class_nregs[cl][mode]))
IOR_HARD_REG_SET (*set, reg_class_contents[cl]);
break;
}
}
}
}
/* Processes input operands, if IN_P, or output operands otherwise of
the current insn with FREQ to find allocno which can use only one
hard register and makes other currently living allocnos conflicting

View File

@ -1422,8 +1422,8 @@ compute_regs_asm_clobbered (char *regs_asm_clobbered)
/* Set up ELIMINABLE_REGSET, IRA_NO_ALLOC_REGS, and REGS_EVER_LIVE. */
static void
setup_eliminable_regset (void)
void
ira_setup_eliminable_regset (void)
{
/* Like regs_ever_live, but 1 if a reg is set or clobbered from an
asm. Unlike regs_ever_live, elements of this array corresponding
@ -1827,7 +1827,8 @@ setup_preferred_alternate_classes_for_new_pseudos (int start)
old_regno = ORIGINAL_REGNO (regno_reg_rtx[i]);
ira_assert (i != old_regno);
setup_reg_classes (i, reg_preferred_class (old_regno),
reg_alternate_class (old_regno));
reg_alternate_class (old_regno),
reg_cover_class (old_regno));
if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
fprintf (ira_dump_file,
" New r%d: setting preferred %s, alternative %s\n",
@ -1848,10 +1849,7 @@ expand_reg_info (int old_size)
resize_reg_info ();
for (i = old_size; i < size; i++)
{
reg_renumber[i] = -1;
setup_reg_classes (i, GENERAL_REGS, ALL_REGS);
}
setup_reg_classes (i, GENERAL_REGS, ALL_REGS, GENERAL_REGS);
}
/* Return TRUE if there is too high register pressure in the function.
@ -3160,8 +3158,8 @@ ira (FILE *f)
}
max_regno_before_ira = allocated_reg_info_size = max_reg_num ();
allocate_reg_info ();
setup_eliminable_regset ();
resize_reg_info ();
ira_setup_eliminable_regset ();
ira_overall_cost = ira_reg_cost = ira_mem_cost = 0;
ira_load_cost = ira_store_cost = ira_shuffle_cost = 0;

View File

@ -20,14 +20,63 @@ 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/>. */
/* Number of given class hard registers available for the register
allocation for given classes. */
extern int ira_available_class_regs[N_REG_CLASSES];
/* Map: hard register number -> cover class it belongs to. If the
corresponding class is NO_REGS, the hard register is not available
for allocation. */
extern enum reg_class ira_hard_regno_cover_class[FIRST_PSEUDO_REGISTER];
/* Number of cover classes. Cover classes is non-intersected register
classes containing all hard-registers available for the
allocation. */
extern int ira_reg_class_cover_size;
/* The array containing cover classes (see also comments for macro
IRA_COVER_CLASSES). Only first IRA_REG_CLASS_COVER_SIZE elements are
used for this. */
extern enum reg_class ira_reg_class_cover[N_REG_CLASSES];
/* Map of all register classes to corresponding cover class containing
the given class. If given class is not a subset of a cover class,
we translate it into the cheapest cover class. */
extern enum reg_class ira_class_translate[N_REG_CLASSES];
/* Map: register class x machine mode -> number of hard registers of
given class needed to store value of given mode. If the number for
some hard-registers of the register class is different, the size
will be negative. */
extern int ira_reg_class_nregs[N_REG_CLASSES][MAX_MACHINE_MODE];
/* Function specific hard registers can not be used for the register
allocation. */
extern HARD_REG_SET ira_no_alloc_regs;
/* True if we have allocno conflicts. It is false for non-optimized
mode or when the conflict table is too big. */
extern bool ira_conflicts_p;
/* Array analogous to macro MEMORY_MOVE_COST. */
extern short ira_memory_move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][2];
/* Array of number of hard registers of given class which are
available for the allocation. The order is defined by the
allocation order. */
extern short ira_class_hard_regs[N_REG_CLASSES][FIRST_PSEUDO_REGISTER];
/* The number of elements of the above array for given register
class. */
extern int ira_class_hard_regs_num[N_REG_CLASSES];
extern void ira_init_once (void);
extern void ira_init (void);
extern void ira_finish_once (void);
extern void ira_setup_eliminable_regset (void);
extern rtx ira_eliminate_regs (rtx, enum machine_mode);
extern void ira_set_pseudo_classes (FILE *);
extern void ira_implicitly_set_insn_hard_regs (HARD_REG_SET *);
extern void ira_sort_regnos_for_alter_reg (int *, int, unsigned int *);
extern void ira_mark_allocation_change (int);

View File

@ -776,8 +776,8 @@ init_optimization_passes (void)
NEXT_PASS (pass_mode_switching);
NEXT_PASS (pass_match_asm_constraints);
NEXT_PASS (pass_sms);
NEXT_PASS (pass_sched);
NEXT_PASS (pass_subregs_of_mode_init);
NEXT_PASS (pass_sched);
NEXT_PASS (pass_ira);
NEXT_PASS (pass_subregs_of_mode_finish);
NEXT_PASS (pass_postreload);

View File

@ -898,6 +898,10 @@ struct reg_pref
but since it is recommended that there be a class corresponding to the
union of most major pair of classes, that generality is not required. */
char altclass;
/* coverclass is a register class that IRA uses for allocating
the pseudo. */
char coverclass;
};
/* Record preferences of each pseudo. This is available after RA is
@ -925,65 +929,51 @@ reg_alternate_class (int regno)
return (enum reg_class) reg_pref[regno].altclass;
}
/* Initialize some global data for this pass. */
static unsigned int
reginfo_init (void)
/* Return the reg_class which is used by IRA for its allocation. */
enum reg_class
reg_cover_class (int regno)
{
if (df)
df_compute_regs_ever_live (true);
if (reg_pref == 0)
return NO_REGS;
/* This prevents dump_flow_info from losing if called
before reginfo is run. */
reg_pref = NULL;
/* No more global register variables may be declared. */
no_global_reg_vars = 1;
return 1;
return (enum reg_class) reg_pref[regno].coverclass;
}
struct rtl_opt_pass pass_reginfo_init =
{
{
RTL_PASS,
"reginfo", /* name */
NULL, /* gate */
reginfo_init, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0 /* todo_flags_finish */
}
};
/* Current size of reg_info. */
static int reg_info_size;
/* Allocate space for reg info. */
void
static void
allocate_reg_info (void)
{
int size = max_reg_num ();
reg_info_size = max_reg_num ();
gcc_assert (! reg_pref && ! reg_renumber);
reg_renumber = XNEWVEC (short, size);
reg_pref = XCNEWVEC (struct reg_pref, size);
memset (reg_renumber, -1, size * sizeof (short));
reg_renumber = XNEWVEC (short, reg_info_size);
reg_pref = XCNEWVEC (struct reg_pref, reg_info_size);
memset (reg_renumber, -1, reg_info_size * sizeof (short));
}
/* Resize reg info. The new elements will be uninitialized. */
void
bool
resize_reg_info (void)
{
int size = max_reg_num ();
int old;
gcc_assert (reg_pref != NULL);
if (reg_info_size == max_reg_num ())
return false;
old = reg_info_size;
reg_info_size = max_reg_num ();
gcc_assert (reg_pref && reg_renumber);
reg_renumber = XRESIZEVEC (short, reg_renumber, size);
reg_pref = XRESIZEVEC (struct reg_pref, reg_pref, size);
reg_renumber = XRESIZEVEC (short, reg_renumber, reg_info_size);
reg_pref = XRESIZEVEC (struct reg_pref, reg_pref, reg_info_size);
memset (reg_pref + old, -1,
(reg_info_size - old) * sizeof (struct reg_pref));
memset (reg_renumber + old, -1, (reg_info_size - old) * sizeof (short));
return true;
}
@ -1004,19 +994,55 @@ free_reg_info (void)
}
}
/* Initialize some global data for this pass. */
static unsigned int
reginfo_init (void)
{
if (df)
df_compute_regs_ever_live (true);
/* This prevents dump_flow_info from losing if called
before reginfo is run. */
reg_pref = NULL;
allocate_reg_info ();
/* No more global register variables may be declared. */
no_global_reg_vars = 1;
return 1;
}
struct rtl_opt_pass pass_reginfo_init =
{
{
RTL_PASS,
"reginfo", /* name */
NULL, /* gate */
reginfo_init, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0 /* todo_flags_finish */
}
};
/* Set up preferred and alternate classes for REGNO as PREFCLASS and
ALTCLASS. */
/* Set up preferred, alternate, and cover classes for REGNO as
PREFCLASS, ALTCLASS, and COVERCLASS. */
void
setup_reg_classes (int regno,
enum reg_class prefclass, enum reg_class altclass)
enum reg_class prefclass, enum reg_class altclass,
enum reg_class coverclass)
{
if (reg_pref == NULL)
return;
reg_pref[regno].prefclass = prefclass;
reg_pref[regno].altclass = altclass;
reg_pref[regno].coverclass = coverclass;
}

View File

@ -112,6 +112,7 @@ a register with any other reload. */
#include "params.h"
#include "target.h"
#include "df.h"
#include "ira.h"
/* True if X is a constant that can be forced into the constant pool. */
#define CONST_POOL_OK_P(X) \
@ -2589,6 +2590,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS];
int goal_alternative_swapped;
int best;
int best_small_class_operands_num;
int commutative;
char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
rtx substed_operand[MAX_RECOG_OPERANDS];
@ -2914,6 +2916,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
all the operands together against the register constraints. */
best = MAX_RECOG_OPERANDS * 2 + 600;
best_small_class_operands_num = 0;
swapped = 0;
goal_alternative_swapped = 0;
@ -3697,22 +3700,48 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
/* If this alternative can be made to work by reloading,
and it needs less reloading than the others checked so far,
record it as the chosen goal for reloading. */
if (! bad && best > losers)
if (! bad)
{
for (i = 0; i < noperands; i++)
bool change_p = false;
int small_class_operands_num = 0;
if (best >= losers)
{
goal_alternative[i] = this_alternative[i];
goal_alternative_win[i] = this_alternative_win[i];
goal_alternative_match_win[i] = this_alternative_match_win[i];
goal_alternative_offmemok[i] = this_alternative_offmemok[i];
goal_alternative_matches[i] = this_alternative_matches[i];
goal_alternative_earlyclobber[i]
= this_alternative_earlyclobber[i];
for (i = 0; i < noperands; i++)
small_class_operands_num
+= SMALL_REGISTER_CLASS_P (this_alternative[i]) ? 1 : 0;
if (best > losers
|| (best == losers
/* If the cost of the reloads is the same,
prefer alternative which requires minimal
number of small register classes for the
operands. This improves chances of reloads
for insn requiring small register
classes. */
&& (small_class_operands_num
< best_small_class_operands_num)))
change_p = true;
}
if (change_p)
{
for (i = 0; i < noperands; i++)
{
goal_alternative[i] = this_alternative[i];
goal_alternative_win[i] = this_alternative_win[i];
goal_alternative_match_win[i]
= this_alternative_match_win[i];
goal_alternative_offmemok[i]
= this_alternative_offmemok[i];
goal_alternative_matches[i] = this_alternative_matches[i];
goal_alternative_earlyclobber[i]
= this_alternative_earlyclobber[i];
}
goal_alternative_swapped = swapped;
best = losers;
best_small_class_operands_num = small_class_operands_num;
goal_alternative_number = this_alternative_number;
goal_earlyclobber = this_earlyclobber;
}
goal_alternative_swapped = swapped;
best = losers;
goal_alternative_number = this_alternative_number;
goal_earlyclobber = this_earlyclobber;
}
}

View File

@ -1898,10 +1898,8 @@ extern rtx remove_free_EXPR_LIST_node (rtx *);
/* Initialize may_move_cost and friends for mode M. */
extern void init_move_cost (enum machine_mode);
/* Allocate register info memory. */
extern void allocate_reg_info (void);
/* Resize reg info. */
extern void resize_reg_info (void);
extern bool resize_reg_info (void);
/* Free up register info memory. */
extern void free_reg_info (void);
@ -1912,7 +1910,9 @@ extern const char *decode_asm_operands (rtx, rtx *, rtx **, const char **,
extern enum reg_class reg_preferred_class (int);
extern enum reg_class reg_alternate_class (int);
extern void setup_reg_classes (int, enum reg_class, enum reg_class);
extern enum reg_class reg_cover_class (int);
extern void setup_reg_classes (int, enum reg_class, enum reg_class,
enum reg_class);
extern void split_all_insns (void);
extern unsigned int split_all_insns_noflow (void);

View File

@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "sched-int.h"
#include "params.h"
#include "cselib.h"
#include "ira.h"
#ifdef INSN_SCHEDULING
@ -396,6 +397,15 @@ static regset reg_pending_clobbers;
static regset reg_pending_uses;
static enum reg_pending_barrier_mode reg_pending_barrier;
/* Hard registers implicitly clobbered or used (or may be implicitly
clobbered or used) by the currently analyzed insn. For example,
insn in its constraint has one register class. Even if there is
currently no hard register in the insn, the particular hard
register will be in the insn after reload pass because the
constraint requires it. */
static HARD_REG_SET implicit_reg_pending_clobbers;
static HARD_REG_SET implicit_reg_pending_uses;
/* To speed up the test for duplicate dependency links we keep a
record of dependencies created by add_dependence when the average
number of instructions in a basic block is very large.
@ -417,8 +427,8 @@ static int cache_size;
static int deps_may_trap_p (const_rtx);
static void add_dependence_list (rtx, rtx, int, enum reg_note);
static void add_dependence_list_and_free (struct deps *, rtx,
rtx *, int, enum reg_note);
static void add_dependence_list_and_free (struct deps *, rtx,
rtx *, int, enum reg_note);
static void delete_all_dependences (rtx);
static void fixup_sched_groups (rtx);
@ -1367,7 +1377,7 @@ add_dependence_list (rtx insn, rtx list, int uncond, enum reg_note dep_type)
is not readonly. */
static void
add_dependence_list_and_free (struct deps *deps, rtx insn, rtx *listp,
add_dependence_list_and_free (struct deps *deps, rtx insn, rtx *listp,
int uncond, enum reg_note dep_type)
{
rtx list, next;
@ -1625,7 +1635,7 @@ haifa_note_mem_dep (rtx mem, rtx pending_mem, rtx pending_insn, ds_t ds)
{
dep_def _dep, *dep = &_dep;
init_dep_1 (dep, pending_insn, cur_insn, ds_to_dt (ds),
init_dep_1 (dep, pending_insn, cur_insn, ds_to_dt (ds),
current_sched_info->flags & USE_DEPS_LIST ? ds : -1);
maybe_add_or_update_dep_1 (dep, false, pending_mem, mem);
}
@ -1691,6 +1701,327 @@ ds_to_dt (ds_t ds)
return REG_DEP_ANTI;
}
}
/* Functions for computation of info needed for register pressure
sensitive insn scheduling. */
/* Allocate and return reg_use_data structure for REGNO and INSN. */
static struct reg_use_data *
create_insn_reg_use (int regno, rtx insn)
{
struct reg_use_data *use;
use = (struct reg_use_data *) xmalloc (sizeof (struct reg_use_data));
use->regno = regno;
use->insn = insn;
use->next_insn_use = INSN_REG_USE_LIST (insn);
INSN_REG_USE_LIST (insn) = use;
return use;
}
/* Allocate and return reg_set_data structure for REGNO and INSN. */
static struct reg_set_data *
create_insn_reg_set (int regno, rtx insn)
{
struct reg_set_data *set;
set = (struct reg_set_data *) xmalloc (sizeof (struct reg_set_data));
set->regno = regno;
set->insn = insn;
set->next_insn_set = INSN_REG_SET_LIST (insn);
INSN_REG_SET_LIST (insn) = set;
return set;
}
/* Set up insn register uses for INSN and dependency context DEPS. */
static void
setup_insn_reg_uses (struct deps *deps, rtx insn)
{
unsigned i;
reg_set_iterator rsi;
rtx list;
struct reg_use_data *use, *use2, *next;
struct deps_reg *reg_last;
EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
{
if (i < FIRST_PSEUDO_REGISTER
&& TEST_HARD_REG_BIT (ira_no_alloc_regs, i))
continue;
if (find_regno_note (insn, REG_DEAD, i) == NULL_RTX
&& ! REGNO_REG_SET_P (reg_pending_sets, i)
&& ! REGNO_REG_SET_P (reg_pending_clobbers, i))
/* Ignore use which is not dying. */
continue;
use = create_insn_reg_use (i, insn);
use->next_regno_use = use;
reg_last = &deps->reg_last[i];
/* Create the cycle list of uses. */
for (list = reg_last->uses; list; list = XEXP (list, 1))
{
use2 = create_insn_reg_use (i, XEXP (list, 0));
next = use->next_regno_use;
use->next_regno_use = use2;
use2->next_regno_use = next;
}
}
}
/* Register pressure info for the currently processed insn. */
static struct reg_pressure_data reg_pressure_info[N_REG_CLASSES];
/* Return TRUE if INSN has the use structure for REGNO. */
static bool
insn_use_p (rtx insn, int regno)
{
struct reg_use_data *use;
for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
if (use->regno == regno)
return true;
return false;
}
/* Update the register pressure info after birth of pseudo register REGNO
in INSN. Arguments CLOBBER_P and UNUSED_P say correspondingly that
the register is in clobber or unused after the insn. */
static void
mark_insn_pseudo_birth (rtx insn, int regno, bool clobber_p, bool unused_p)
{
int incr, new_incr;
enum reg_class cl;
gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
cl = sched_regno_cover_class[regno];
if (cl != NO_REGS)
{
incr = ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (regno)];
if (clobber_p)
{
new_incr = reg_pressure_info[cl].clobber_increase + incr;
reg_pressure_info[cl].clobber_increase = new_incr;
}
else if (unused_p)
{
new_incr = reg_pressure_info[cl].unused_set_increase + incr;
reg_pressure_info[cl].unused_set_increase = new_incr;
}
else
{
new_incr = reg_pressure_info[cl].set_increase + incr;
reg_pressure_info[cl].set_increase = new_incr;
if (! insn_use_p (insn, regno))
reg_pressure_info[cl].change += incr;
create_insn_reg_set (regno, insn);
}
gcc_assert (new_incr < (1 << INCREASE_BITS));
}
}
/* Like mark_insn_pseudo_regno_birth except that NREGS saying how many
hard registers involved in the birth. */
static void
mark_insn_hard_regno_birth (rtx insn, int regno, int nregs,
bool clobber_p, bool unused_p)
{
enum reg_class cl;
int new_incr, last = regno + nregs;
while (regno < last)
{
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
{
cl = sched_regno_cover_class[regno];
if (cl != NO_REGS)
{
if (clobber_p)
{
new_incr = reg_pressure_info[cl].clobber_increase + 1;
reg_pressure_info[cl].clobber_increase = new_incr;
}
else if (unused_p)
{
new_incr = reg_pressure_info[cl].unused_set_increase + 1;
reg_pressure_info[cl].unused_set_increase = new_incr;
}
else
{
new_incr = reg_pressure_info[cl].set_increase + 1;
reg_pressure_info[cl].set_increase = new_incr;
if (! insn_use_p (insn, regno))
reg_pressure_info[cl].change += 1;
create_insn_reg_set (regno, insn);
}
gcc_assert (new_incr < (1 << INCREASE_BITS));
}
}
regno++;
}
}
/* Update the register pressure info after birth of pseudo or hard
register REG in INSN. Arguments CLOBBER_P and UNUSED_P say
correspondingly that the register is in clobber or unused after the
insn. */
static void
mark_insn_reg_birth (rtx insn, rtx reg, bool clobber_p, bool unused_p)
{
int regno;
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
if (! REG_P (reg))
return;
regno = REGNO (reg);
if (regno < FIRST_PSEUDO_REGISTER)
mark_insn_hard_regno_birth (insn, regno,
hard_regno_nregs[regno][GET_MODE (reg)],
clobber_p, unused_p);
else
mark_insn_pseudo_birth (insn, regno, clobber_p, unused_p);
}
/* Update the register pressure info after death of pseudo register
REGNO. */
static void
mark_pseudo_death (int regno)
{
int incr;
enum reg_class cl;
gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
cl = sched_regno_cover_class[regno];
if (cl != NO_REGS)
{
incr = ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (regno)];
reg_pressure_info[cl].change -= incr;
}
}
/* Like mark_pseudo_death except that NREGS saying how many hard
registers involved in the death. */
static void
mark_hard_regno_death (int regno, int nregs)
{
enum reg_class cl;
int last = regno + nregs;
while (regno < last)
{
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
{
cl = sched_regno_cover_class[regno];
if (cl != NO_REGS)
reg_pressure_info[cl].change -= 1;
}
regno++;
}
}
/* Update the register pressure info after death of pseudo or hard
register REG. */
static void
mark_reg_death (rtx reg)
{
int regno;
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
if (! REG_P (reg))
return;
regno = REGNO (reg);
if (regno < FIRST_PSEUDO_REGISTER)
mark_hard_regno_death (regno, hard_regno_nregs[regno][GET_MODE (reg)]);
else
mark_pseudo_death (regno);
}
/* Process SETTER of REG. DATA is an insn containing the setter. */
static void
mark_insn_reg_store (rtx reg, const_rtx setter, void *data)
{
if (setter != NULL_RTX && GET_CODE (setter) != SET)
return;
mark_insn_reg_birth
((rtx) data, reg, false,
find_reg_note ((const_rtx) data, REG_UNUSED, reg) != NULL_RTX);
}
/* Like mark_insn_reg_store except notice just CLOBBERs; ignore SETs. */
static void
mark_insn_reg_clobber (rtx reg, const_rtx setter, void *data)
{
if (GET_CODE (setter) == CLOBBER)
mark_insn_reg_birth ((rtx) data, reg, true, false);
}
/* Set up reg pressure info related to INSN. */
static void
setup_insn_reg_pressure_info (rtx insn)
{
int i, len;
enum reg_class cl;
static struct reg_pressure_data *pressure_info;
rtx link;
gcc_assert (sched_pressure_p);
if (! INSN_P (insn))
return;
for (i = 0; i < ira_reg_class_cover_size; i++)
{
cl = ira_reg_class_cover[i];
reg_pressure_info[cl].clobber_increase = 0;
reg_pressure_info[cl].set_increase = 0;
reg_pressure_info[cl].unused_set_increase = 0;
reg_pressure_info[cl].change = 0;
}
note_stores (PATTERN (insn), mark_insn_reg_clobber, insn);
note_stores (PATTERN (insn), mark_insn_reg_store, insn);
#ifdef AUTO_INC_DEC
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC)
mark_insn_reg_store (XEXP (link, 0), NULL_RTX, insn);
#endif
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD)
mark_reg_death (XEXP (link, 0));
len = sizeof (struct reg_pressure_data) * ira_reg_class_cover_size;
pressure_info
= INSN_REG_PRESSURE (insn) = (struct reg_pressure_data *) xmalloc (len);
INSN_MAX_REG_PRESSURE (insn) = (int *) xmalloc (ira_reg_class_cover_size
* sizeof (int));
for (i = 0; i < ira_reg_class_cover_size; i++)
{
cl = ira_reg_class_cover[i];
pressure_info[i].clobber_increase
= reg_pressure_info[cl].clobber_increase;
pressure_info[i].set_increase = reg_pressure_info[cl].set_increase;
pressure_info[i].unused_set_increase
= reg_pressure_info[cl].unused_set_increase;
pressure_info[i].change = reg_pressure_info[cl].change;
}
}
/* Internal variable for sched_analyze_[12] () functions.
@ -1905,10 +2236,16 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
/* Treat all writes to a stack register as modifying the TOS. */
if (regno >= FIRST_STACK_REG && regno <= LAST_STACK_REG)
{
int nregs;
/* Avoid analyzing the same register twice. */
if (regno != FIRST_STACK_REG)
sched_analyze_reg (deps, FIRST_STACK_REG, mode, code, insn);
sched_analyze_reg (deps, FIRST_STACK_REG, mode, USE, insn);
nregs = hard_regno_nregs[FIRST_STACK_REG][mode];
while (--nregs >= 0)
SET_HARD_REG_BIT (implicit_reg_pending_uses,
FIRST_STACK_REG + nregs);
}
#endif
}
@ -2243,6 +2580,16 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
unsigned i;
reg_set_iterator rsi;
if (! reload_completed)
{
HARD_REG_SET temp;
extract_insn (insn);
preprocess_constraints ();
ira_implicitly_set_insn_hard_regs (&temp);
IOR_HARD_REG_SET (implicit_reg_pending_clobbers, temp);
}
can_start_lhs_rhs_p = (NONJUMP_INSN_P (insn)
&& code == SET);
@ -2263,7 +2610,8 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
and others know that a value is dead. Depend on the last call
instruction so that reg-stack won't get confused. */
if (code == CLOBBER)
add_dependence_list (insn, deps->last_function_call, 1, REG_DEP_OUTPUT);
add_dependence_list (insn, deps->last_function_call, 1,
REG_DEP_OUTPUT);
}
else if (code == PARALLEL)
{
@ -2326,6 +2674,8 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_ANTI);
add_dependence_list (insn, reg_last->implicit_sets,
0, REG_DEP_ANTI);
add_dependence_list (insn, reg_last->clobbers, 0,
REG_DEP_ANTI);
@ -2381,6 +2731,12 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
|| (NONJUMP_INSN_P (insn) && control_flow_insn_p (insn)))
reg_pending_barrier = MOVE_BARRIER;
if (sched_pressure_p)
{
setup_insn_reg_uses (deps, insn);
setup_insn_reg_pressure_info (insn);
}
/* Add register dependencies for insn. */
if (DEBUG_INSN_P (insn))
{
@ -2421,119 +2777,160 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
if (prev && NONDEBUG_INSN_P (prev))
add_dependence (insn, prev, REG_DEP_ANTI);
}
/* If the current insn is conditional, we can't free any
of the lists. */
else if (sched_has_condition_p (insn))
{
EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
if (!deps->readonly)
{
reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
reg_last->uses_length++;
}
}
EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
if (!deps->readonly)
{
reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
reg_last->clobbers_length++;
}
}
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
if (!deps->readonly)
{
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
SET_REGNO_REG_SET (&deps->reg_conditional_sets, i);
}
}
}
else
{
EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
add_dependence_list (insn, reg_last->implicit_sets, 0, REG_DEP_ANTI);
add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
if (!deps->readonly)
{
reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
reg_last->uses_length++;
}
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (implicit_reg_pending_uses, i))
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
add_dependence_list (insn, reg_last->implicit_sets, 0,
REG_DEP_ANTI);
add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
if (!deps->readonly)
{
reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
reg_last->uses_length++;
}
}
if (!deps->readonly)
{
reg_last->uses_length++;
reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
}
}
EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
if (reg_last->uses_length > MAX_PENDING_LIST_LENGTH
|| reg_last->clobbers_length > MAX_PENDING_LIST_LENGTH)
{
add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
REG_DEP_OUTPUT);
add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
REG_DEP_ANTI);
add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
REG_DEP_OUTPUT);
if (!deps->readonly)
{
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
reg_last->clobbers_length = 0;
reg_last->uses_length = 0;
}
}
else
{
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
}
if (!deps->readonly)
{
reg_last->clobbers_length++;
reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
}
}
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
REG_DEP_OUTPUT);
add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
REG_DEP_OUTPUT);
add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
REG_DEP_ANTI);
if (!deps->readonly)
{
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
reg_last->uses_length = 0;
reg_last->clobbers_length = 0;
CLEAR_REGNO_REG_SET (&deps->reg_conditional_sets, i);
}
}
/* If the current insn is conditional, we can't free any
of the lists. */
if (sched_has_condition_p (insn))
{
EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->implicit_sets, 0,
REG_DEP_ANTI);
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
if (!deps->readonly)
{
reg_last->clobbers
= alloc_INSN_LIST (insn, reg_last->clobbers);
reg_last->clobbers_length++;
}
}
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->implicit_sets, 0,
REG_DEP_ANTI);
add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
if (!deps->readonly)
{
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
SET_REGNO_REG_SET (&deps->reg_conditional_sets, i);
}
}
}
else
{
EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
if (reg_last->uses_length > MAX_PENDING_LIST_LENGTH
|| reg_last->clobbers_length > MAX_PENDING_LIST_LENGTH)
{
add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
REG_DEP_OUTPUT);
add_dependence_list_and_free (deps, insn,
&reg_last->implicit_sets, 0,
REG_DEP_ANTI);
add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
REG_DEP_ANTI);
add_dependence_list_and_free
(deps, insn, &reg_last->clobbers, 0, REG_DEP_OUTPUT);
if (!deps->readonly)
{
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
reg_last->clobbers_length = 0;
reg_last->uses_length = 0;
}
}
else
{
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->implicit_sets, 0,
REG_DEP_ANTI);
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
}
if (!deps->readonly)
{
reg_last->clobbers_length++;
reg_last->clobbers
= alloc_INSN_LIST (insn, reg_last->clobbers);
}
}
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
REG_DEP_OUTPUT);
add_dependence_list_and_free (deps, insn,
&reg_last->implicit_sets,
0, REG_DEP_ANTI);
add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
REG_DEP_OUTPUT);
add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
REG_DEP_ANTI);
if (!deps->readonly)
{
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
reg_last->uses_length = 0;
reg_last->clobbers_length = 0;
CLEAR_REGNO_REG_SET (&deps->reg_conditional_sets, i);
}
}
}
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (implicit_reg_pending_clobbers, i))
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, 0, REG_DEP_ANTI);
add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_ANTI);
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
if (!deps->readonly)
reg_last->implicit_sets
= alloc_INSN_LIST (insn, reg_last->implicit_sets);
}
if (!deps->readonly)
{
IOR_REG_SET (&deps->reg_last_in_use, reg_pending_uses);
IOR_REG_SET (&deps->reg_last_in_use, reg_pending_clobbers);
IOR_REG_SET (&deps->reg_last_in_use, reg_pending_sets);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (implicit_reg_pending_uses, i)
|| TEST_HARD_REG_BIT (implicit_reg_pending_clobbers, i))
SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
/* Set up the pending barrier found. */
deps->last_reg_pending_barrier = reg_pending_barrier;
@ -2542,6 +2939,8 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
CLEAR_REG_SET (reg_pending_uses);
CLEAR_REG_SET (reg_pending_clobbers);
CLEAR_REG_SET (reg_pending_sets);
CLEAR_HARD_REG_SET (implicit_reg_pending_clobbers);
CLEAR_HARD_REG_SET (implicit_reg_pending_uses);
/* Add dependencies if a scheduling barrier was found. */
if (reg_pending_barrier)
@ -2554,12 +2953,14 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
add_dependence_list
(insn, reg_last->sets, 0,
reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
add_dependence_list
(insn, reg_last->clobbers, 0,
reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
add_dependence_list (insn, reg_last->sets, 0,
reg_pending_barrier == TRUE_BARRIER
? REG_DEP_TRUE : REG_DEP_ANTI);
add_dependence_list (insn, reg_last->implicit_sets, 0,
REG_DEP_ANTI);
add_dependence_list (insn, reg_last->clobbers, 0,
reg_pending_barrier == TRUE_BARRIER
? REG_DEP_TRUE : REG_DEP_ANTI);
}
}
else
@ -2569,12 +2970,15 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
REG_DEP_ANTI);
add_dependence_list_and_free
(deps, insn, &reg_last->sets, 0,
reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
add_dependence_list_and_free
(deps, insn, &reg_last->clobbers, 0,
reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
reg_pending_barrier == TRUE_BARRIER
? REG_DEP_TRUE : REG_DEP_ANTI);
add_dependence_list_and_free (deps, insn,
&reg_last->implicit_sets, 0,
REG_DEP_ANTI);
add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
reg_pending_barrier == TRUE_BARRIER
? REG_DEP_TRUE : REG_DEP_ANTI);
if (!deps->readonly)
{
@ -2750,7 +3154,7 @@ deps_analyze_insn (struct deps *deps, rtx insn)
if (global_regs[i])
{
SET_REGNO_REG_SET (reg_pending_sets, i);
SET_REGNO_REG_SET (reg_pending_uses, i);
SET_HARD_REG_BIT (implicit_reg_pending_uses, i);
}
/* Other call-clobbered hard regs may be clobbered.
Since we only have a choice between 'might be clobbered'
@ -2763,7 +3167,7 @@ deps_analyze_insn (struct deps *deps, rtx insn)
by the function, but it is certain that the stack pointer
is among them, but be conservative. */
else if (fixed_regs[i])
SET_REGNO_REG_SET (reg_pending_uses, i);
SET_HARD_REG_BIT (implicit_reg_pending_uses, i);
/* The frame pointer is normally not used by the function
itself, but by the debugger. */
/* ??? MIPS o32 is an exception. It uses the frame pointer
@ -2772,7 +3176,7 @@ deps_analyze_insn (struct deps *deps, rtx insn)
else if (i == FRAME_POINTER_REGNUM
|| (i == HARD_FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed)))
SET_REGNO_REG_SET (reg_pending_uses, i);
SET_HARD_REG_BIT (implicit_reg_pending_uses, i);
}
/* For each insn which shouldn't cross a call, add a dependence
@ -2988,6 +3392,8 @@ free_deps (struct deps *deps)
free_INSN_LIST_list (&reg_last->uses);
if (reg_last->sets)
free_INSN_LIST_list (&reg_last->sets);
if (reg_last->implicit_sets)
free_INSN_LIST_list (&reg_last->implicit_sets);
if (reg_last->clobbers)
free_INSN_LIST_list (&reg_last->clobbers);
}
@ -3025,9 +3431,12 @@ remove_from_deps (struct deps *deps, rtx insn)
remove_from_dependence_list (insn, &reg_last->uses);
if (reg_last->sets)
remove_from_dependence_list (insn, &reg_last->sets);
if (reg_last->implicit_sets)
remove_from_dependence_list (insn, &reg_last->implicit_sets);
if (reg_last->clobbers)
remove_from_dependence_list (insn, &reg_last->clobbers);
if (!reg_last->uses && !reg_last->sets && !reg_last->clobbers)
if (!reg_last->uses && !reg_last->sets && !reg_last->implicit_sets
&& !reg_last->clobbers)
CLEAR_REGNO_REG_SET (&deps->reg_last_in_use, i);
}
@ -3167,6 +3576,8 @@ sched_deps_finish (void)
void
init_deps_global (void)
{
CLEAR_HARD_REG_SET (implicit_reg_pending_clobbers);
CLEAR_HARD_REG_SET (implicit_reg_pending_uses);
reg_pending_sets = ALLOC_REG_SET (&reg_obstack);
reg_pending_clobbers = ALLOC_REG_SET (&reg_obstack);
reg_pending_uses = ALLOC_REG_SET (&reg_obstack);

View File

@ -441,6 +441,7 @@ struct deps_reg
{
rtx uses;
rtx sets;
rtx implicit_sets;
rtx clobbers;
int uses_length;
int clobbers_length;
@ -642,6 +643,14 @@ extern spec_info_t spec_info;
extern struct haifa_sched_info *current_sched_info;
/* Do register pressure sensitive insn scheduling if the flag is set
up. */
extern bool sched_pressure_p;
/* Map regno -> its cover class. The map defined only when
SCHED_PRESSURE_P is true. */
extern enum reg_class *sched_regno_cover_class;
/* Indexed by INSN_UID, the collection of all data associated with
a single instruction. */
@ -687,6 +696,52 @@ struct _haifa_deps_insn_data
unsigned int cant_move : 1;
};
/* Bits used for storing values of the fields in the following
structure. */
#define INCREASE_BITS 8
/* The structure describes how the corresponding insn increases the
register pressure for each cover class. */
struct reg_pressure_data
{
/* Pressure increase for given class because of clobber. */
unsigned int clobber_increase : INCREASE_BITS;
/* Increase in register pressure for given class because of register
sets. */
unsigned int set_increase : INCREASE_BITS;
/* Pressure increase for given class because of unused register
set. */
unsigned int unused_set_increase : INCREASE_BITS;
/* Pressure change: #sets - #deaths. */
int change : INCREASE_BITS;
};
/* The following structure describes usage of registers by insns. */
struct reg_use_data
{
/* Regno used in the insn. */
int regno;
/* Insn using the regno. */
rtx insn;
/* Cyclic list of elements with the same regno. */
struct reg_use_data *next_regno_use;
/* List of elements with the same insn. */
struct reg_use_data *next_insn_use;
};
/* The following structure describes used sets of registers by insns.
Registers are pseudos whose cover class is not NO_REGS or hard
registers available for allocations. */
struct reg_set_data
{
/* Regno used in the insn. */
int regno;
/* Insn setting the regno. */
rtx insn;
/* List of elements with the same insn. */
struct reg_set_data *next_insn_set;
};
struct _haifa_insn_data
{
/* We can't place 'struct _deps_list' into h_i_d instead of deps_list_t
@ -712,10 +767,6 @@ struct _haifa_insn_data
short cost;
/* This weight is an estimation of the insn's contribution to
register pressure. */
short reg_weight;
/* Set if there's DEF-USE dependence between some speculatively
moved load insn and this one. */
unsigned int fed_by_spec_load : 1;
@ -740,6 +791,26 @@ struct _haifa_insn_data
/* Original pattern of the instruction. */
rtx orig_pat;
/* The following array contains info how the insn increases register
pressure. There is an element for each cover class of pseudos
referenced in insns. */
struct reg_pressure_data *reg_pressure;
/* The following array contains maximal reg pressure between last
scheduled insn and given insn. There is an element for each
cover class of pseudos referenced in insns. This info updated
after scheduling each insn for each insn between the two
mentioned insns. */
int *max_reg_pressure;
/* The following list contains info about used pseudos and hard
registers available for allocation. */
struct reg_use_data *reg_use_list;
/* The following list contains info about set pseudos and hard
registers available for allocation. */
struct reg_set_data *reg_set_list;
/* Info about how scheduling the insn changes cost of register
pressure excess (between source and target). */
int reg_pressure_excess_cost_change;
};
typedef struct _haifa_insn_data haifa_insn_data_def;
@ -755,7 +826,12 @@ extern VEC(haifa_insn_data_def, heap) *h_i_d;
/* Accessor macros for h_i_d. There are more in haifa-sched.c and
sched-rgn.c. */
#define INSN_PRIORITY(INSN) (HID (INSN)->priority)
#define INSN_REG_WEIGHT(INSN) (HID (INSN)->reg_weight)
#define INSN_REG_PRESSURE(INSN) (HID (INSN)->reg_pressure)
#define INSN_MAX_REG_PRESSURE(INSN) (HID (INSN)->max_reg_pressure)
#define INSN_REG_USE_LIST(INSN) (HID (INSN)->reg_use_list)
#define INSN_REG_SET_LIST(INSN) (HID (INSN)->reg_set_list)
#define INSN_REG_PRESSURE_EXCESS_COST_CHANGE(INSN) \
(HID (INSN)->reg_pressure_excess_cost_change)
#define INSN_PRIORITY_STATUS(INSN) (HID (INSN)->priority_status)
typedef struct _haifa_deps_insn_data haifa_deps_insn_data_def;
@ -1153,7 +1229,9 @@ extern void extend_dependency_caches (int, bool);
extern void debug_ds (ds_t);
/* Functions in haifa-sched.c. */
extern void sched_init_region_reg_pressure_info (void);
extern int haifa_classify_insn (const_rtx);
extern void get_ebb_head_tail (basic_block, basic_block, rtx *, rtx *);
extern int no_real_insns_p (const_rtx, const_rtx);
@ -1163,6 +1241,7 @@ extern int dep_cost_1 (dep_t, dw_t);
extern int dep_cost (dep_t);
extern int set_priorities (rtx, rtx);
extern void sched_setup_bb_reg_pressure_info (basic_block, rtx);
extern void schedule_block (basic_block *);
extern int cycle_issued_insns;

View File

@ -2613,6 +2613,8 @@ deps_join (struct deps *succ_deps, struct deps *pred_deps)
succ_rl->uses = concat_INSN_LIST (pred_rl->uses, succ_rl->uses);
succ_rl->sets = concat_INSN_LIST (pred_rl->sets, succ_rl->sets);
succ_rl->implicit_sets
= concat_INSN_LIST (pred_rl->implicit_sets, succ_rl->implicit_sets);
succ_rl->clobbers = concat_INSN_LIST (pred_rl->clobbers,
succ_rl->clobbers);
succ_rl->uses_length += pred_rl->uses_length;
@ -2690,12 +2692,14 @@ propagate_deps (int bb, struct deps *pred_deps)
bb's successors.
Specifically for reg-reg data dependences, the block insns are
scanned by sched_analyze () top-to-bottom. Two lists are
scanned by sched_analyze () top-to-bottom. Three lists are
maintained by sched_analyze (): reg_last[].sets for register DEFs,
and reg_last[].uses for register USEs.
reg_last[].implicit_sets for implicit hard register DEFs, and
reg_last[].uses for register USEs.
When analysis is completed for bb, we update for its successors:
; - DEFS[succ] = Union (DEFS [succ], DEFS [bb])
; - IMPLICIT_DEFS[succ] = Union (IMPLICIT_DEFS [succ], IMPLICIT_DEFS [bb])
; - USES[succ] = Union (USES [succ], DEFS [bb])
The mechanism for computing mem-mem data dependence is very
@ -2934,6 +2938,28 @@ schedule_region (int rgn)
sched_extend_ready_list (rgn_n_insns);
if (sched_pressure_p)
{
sched_init_region_reg_pressure_info ();
for (bb = 0; bb < current_nr_blocks; bb++)
{
basic_block first_bb, last_bb;
rtx head, tail;
first_bb = EBB_FIRST_BB (bb);
last_bb = EBB_LAST_BB (bb);
get_ebb_head_tail (first_bb, last_bb, &head, &tail);
if (no_real_insns_p (head, tail))
{
gcc_assert (first_bb == last_bb);
continue;
}
sched_setup_bb_reg_pressure_info (first_bb, PREV_INSN (head));
}
}
/* Now we can schedule all blocks. */
for (bb = 0; bb < current_nr_blocks; bb++)
{