[multiple changes]

2008-08-26  Vladimir Makarov  <vmakarov@redhat.com>

	* ira-build.c, ira-color.c, ira-costs.c, ira.h, ira-lives.c,
	ira.c, ira-conflicts.c, ira-emit.c, ira-int.h: New files.

	* doc/passes.texi: Describe IRA.

	* doc/tm.texi (IRA_COVER_CLASSES,
	IRA_HARD_REGNO_ADD_COST_MULTIPLIER): Describe the new macros.

	* doc/invoke.texi (ira-max-loops-num): Describe the new parameter.
	(-fira, -fira-algorithm, -fira-coalesce, -fno-ira-move-spills,
	-fira-propagate-cost, -fno-ira-share-save-slots,
	-fno-ira-share-spill-slots, -fira-verbose): Describe new options.

	* flags.h (ira_algorithm): New enumeration.
	(flag_ira_algorithm, flag_ira_verbose): New external variable
	declarations.

	* postreload.c (gate_handle_postreload): Don't do post reload
	optimizations unless the reload is completed.

	* reload.c (push_reload, find_dummy_reload): Use DF_LR_OUT for
	IRA.

	* tree-pass.h (pass_ira): New external variable declaration.

	* reload.h: Add 2008 to the Copyright.
    
	* cfgloopanal.c: Include params.h.
	(estimate_reg_pressure_cost): Decrease cost for IRA optimization
	mode.
    
	* params.h (IRA_MAX_LOOPS_NUM): New macro.

	* toplev.c (ira.h): New include.
	(flag_ira_algorithm, flag_ira_verbose): New external variables.
	(backend_init_target): Call ira_init.
	(backend_init): Call ira_init_once.
	(finalize): Call finish_ira_once.

	* toplev.h (flag_ira, flag_ira_coalesce, flag_ira_move_spills,
	flag_ira_share_save_slots, flag_ira_share_spill_slots): New
	external variables.

	* regs.h (contains_reg_of_mode, move_cost, may_move_in_cost,
	may_move_out_cost): New external variable declarations.
	(move_table): New typedef.
    
	* caller-save.c: Include headers output.h and ira.h.
	(no_caller_save_reg_set): New global variable.
	(save_slots_num, save_slots): New variables.
	(reg_save_code, reg_restore_code, add_stored_regs): Add
	prototypes.
	(init_caller_save): Set up no_caller_save_reg_set.
	(init_save_areas): Reset save_slots_num.
	(saved_hard_reg): New structure.
	(hard_reg_map, saved_regs_num, all_saved_regs): New variables.
	(initiate_saved_hard_regs, new_saved_hard_reg,
	finish_saved_hard_regs, saved_hard_reg_compare_func): New
	functions.
	(setup_save_areas): Add code for sharing stack slots.
	(all_blocks): New variable.
	(save_call_clobbered_regs): Process pseudo-register too.
	(mark_set_regs): Process pseudo-register too.
	(insert_one_insn): Put the insn after bb note in a empty basic
	block.  Add insn check.
    
	* global.c (eliminable_regset): Make it external.
	(mark_elimination): Use DF_LR_IN for IRA.
	(pseudo_for_reload_consideration_p): New.
	(build_insn_chain): Make it external.  Don't ignore spilled
	pseudos for IRA.  Use pseudo_for_reload_consideration_p.
	(gate_handle_global_alloc): New function.
	(pass_global_alloc): Add the gate function.

	* opts.c (decode_options): Set up flag_ira.  Print the warning for
	-fira.
	(common_handle_option): Process -fira-algorithm and -fira-verbose.

	* timevar.def (TV_IRA, TV_RELOAD): New passes.

	* regmove.c (regmove_optimize): Don't do replacement of output for
	IRA.

	* hard-reg-set.h (no_caller_save_reg_set, reg_class_subclasses):
	New external variable declarations.

	* local-alloc.c (update_equiv_regs): Make it external.  Return
	true if jump label rebuilding should be done.  Rescan new_insn for
	notes.
	(gate_handle_local_alloc): New function.
	(pass_local_alloc): Add the gate function.

	* alias.c (value_addr_p, stack_addr_p): New functions.
	(nonoverlapping_memrefs_p): Use them for IRA.

	* common.opt (fira, fira-algorithm, fira-coalesce,
	fira-move-spills, fira-share-save-slots, fira-share-spill-slots,
	fira-verbose): New options.

	* regclass.c (reg_class_subclasses, contains_reg_of_mode,
	move_cost, may_move_in_cost, may_move_out_cost): Make the
	variables external.
	(move_table): Remove typedef.
	(init_move_cost): Make it external.
	(allocate_reg_info, resize_reg_info, setup_reg_classes): New
	functions.

	* rtl.h (init_move_cost, allocate_reg_info, resize_reg_info,
	setup_reg_classes): New function prototypes.
	(eliminable_regset): New external variable declaration.
	(build_insn_chain, update_equiv_regs): New function prototypes.
    
	* Makefile.in (IRA_INT_H): New definition.
	(OBJS-common): Add ira.o, ira-build.o, ira-costs.o,
	ira-conflicts.o, ira-color.o, ira-emit.o, and ira-lives.o.
	(reload1.o, toplev.o): Add dependence on ira.h.
	(cfgloopanal.o): Add PARAMS_H.
	(caller-save.o): Add dependence on output.h and ira.h.
	(ira.o, ira-build.o, ira-costs.o, ira-conflicts.o, ira-color.o,
	ira-emit.o, ira-lives.o): New entries.

	* passes.c (pass_ira): New pass.

	* params.def (PARAM_IRA_MAX_LOOPS_NUM): New parameter.

	* reload1.c (ira.h): Include the header.
	(changed_allocation_pseudos): New bitmap.
	(init_reload): Initiate the bitmap.
	(compute_use_by_pseudos): Permits spilled registers in FROM.
	(temp_pseudo_reg_arr): New variable.
	(reload): Allocate and free temp_pseudo_reg_arr.  Sort pseudos for
	IRA.  Call alter_reg with the additional parameter.  Don't clear
	spilled_pseudos for IRA.  Restore original insn chain for IRA.
	Clear changed_allocation_pseudos at the end of reload.
	(calculate_needs_all_insns): Call IRA's mark_memory_move_deletion.
	(hard_regno_to_pseudo_regno): New variable.
	(count_pseudo): Check spilled pseudos.  Set up
	hard_regno_to_pseudo_regno.
	(count_spilled_pseudo): Check spilled pseudos. Update
	hard_regno_to_pseudo_regno.
	(find_reg): Use better_spill_reload_regno_p.  Check
	hard_regno_to_pseudo_regno.
	(alter_reg): Set up spilled_pseudos.  Add a new parameter.  Add
	code for IRA.
	(eliminate_regs_1): Use additional parameter for alter_reg.
	(finish_spills): Set up pseudo_previous_regs only for spilled
	pseudos.  Call reassign_pseudos once for all spilled pseudos, pass
	more arguments.  Don't clear live_throughout and dead_or_set for
	spilled pseudos.  Use additional parameter for alter_reg.  Call
	mark_allocation_change.  Set up changed_allocation_pseudos.
	Remove sanity check.
	(emit_input_reload_insns, delete_output_reload): Use additional
	parameter for alter_reg.  Call mark_allocation_change.
	(substitute, gen_reload_chain_without_interm_reg_p): New
	functions.
	(reloads_conflict): Use gen_reload_chain_without_interm_reg_p.
    
	* testsuite/gcc.dg/20080410-1.c: New file.
	
	* config/s390/s390.h (IRA_COVER_CLASSES,
	IRA_HARD_REGNO_ADD_COST_MULTIPLIER): Define.

	* config/sparc/sparc.h (IRA_COVER_CLASSES): New macro.

	* config/i386/i386.h (IRA_COVER_CLASSES): Ditto.

	* config/ia64/ia64.h (IRA_COVER_CLASSES): Ditto.

	* config/rs6000/rs6000.h (IRA_COVER_CLASSES): Ditto.

	* config/arm/arm.h (IRA_COVER_CLASSES): Ditto.
    
	* config/alpha/alpha.h (IRA_COVER_CLASSES): Ditto.
    
	2008-08-24  Jeff Law  <law@redhat.com>
	* ira.c (setup_reg_class_intersect_union): Prefer smallest class
	when ignoring unavailable registers.

	2008-08-24  Jeff Law  <law@redhat.com>
	* ira-color.c (coalesced_pseudo_reg_slot_compare): Check
	FRAME_GROWS_DOWNWARD and STACK_GROWS_DOWNWARD.
	* ira.c (setup_eliminable_regset): Check stack_realign_needed.
	* config/mn10300/mn10300.h (IRA_COVER_CLASSES): New macro.

	2008-06-03 Steve Chamberlain <steve.chamberlain@gmail.com>
	* ira-build.c (allocno_range_compare_func): Stabilize sort.

	2008-05-29 Andy Hutchinson <hutchinsonandy@aim.com>
	* config/avr/avr.h (IRA_COVER_CLASSES): New macro.
	* reload1.c (find_reg): Process registers in register allocation order.

	2008-05-10 Richard Sandiford <rsandifo@nildram.co.uk>
	* toplev.c (backend_init_target): Move ira_init call from
	here...
	(lang_dependent_init_target): ...to here.

	2008-05-10 Richard Sandiford <rsandifo@nildram.co.uk>
	* ira.c (setup_class_subset_and_memory_move_costs): Don't
	calculate memory move costs for NO_REGS.

	2008-05-05 Kaz Kojima <kkojima@gcc.gnu.org>
	* ira-color.c (ira_fast_allocation): Use no_stack_reg_p only if
	STACK_REGS is defined.

	2008-04-08 Andrew Pinski <andrew_pinski@playstation.sony.com>
	* config/spu/spu.h (IRA_COVER_CLASSES): New macro.

	2008-04-04 Bernd Schmidt <bernd.schmidt@analog.com>
	* config/bfin/bfin.h (IRA_COVER_CLASSES): New macro.

	2008-04-04 Kaz Kojima <kkojima@gcc.gnu.org>
	* config/sh/sh.h (IRA_COVER_CLASSES): Define.
	* config/sh/sh.md (movsicc_true+3): Check if emit returns a
	barrier.

From-SVN: r139590
This commit is contained in:
Vladimir Makarov 2008-08-26 12:39:58 +00:00 committed by Vladimir Makarov
parent 8ff27c248c
commit 058e97ecf3
52 changed files with 14704 additions and 176 deletions

View File

@ -1,3 +1,220 @@
2008-08-26 Vladimir Makarov <vmakarov@redhat.com>
* ira-build.c, ira-color.c, ira-costs.c, ira.h, ira-lives.c,
ira.c, ira-conflicts.c, ira-emit.c, ira-int.h: New files.
* doc/passes.texi: Describe IRA.
* doc/tm.texi (IRA_COVER_CLASSES,
IRA_HARD_REGNO_ADD_COST_MULTIPLIER): Describe the new macros.
* doc/invoke.texi (ira-max-loops-num): Describe the new parameter.
(-fira, -fira-algorithm, -fira-coalesce, -fno-ira-move-spills,
-fira-propagate-cost, -fno-ira-share-save-slots,
-fno-ira-share-spill-slots, -fira-verbose): Describe new options.
* flags.h (ira_algorithm): New enumeration.
(flag_ira_algorithm, flag_ira_verbose): New external variable
declarations.
* postreload.c (gate_handle_postreload): Don't do post reload
optimizations unless the reload is completed.
* reload.c (push_reload, find_dummy_reload): Use DF_LR_OUT for
IRA.
* tree-pass.h (pass_ira): New external variable declaration.
* reload.h: Add 2008 to the Copyright.
* cfgloopanal.c: Include params.h.
(estimate_reg_pressure_cost): Decrease cost for IRA optimization
mode.
* params.h (IRA_MAX_LOOPS_NUM): New macro.
* toplev.c (ira.h): New include.
(flag_ira_algorithm, flag_ira_verbose): New external variables.
(backend_init_target): Call ira_init.
(backend_init): Call ira_init_once.
(finalize): Call finish_ira_once.
* toplev.h (flag_ira, flag_ira_coalesce, flag_ira_move_spills,
flag_ira_share_save_slots, flag_ira_share_spill_slots): New
external variables.
* regs.h (contains_reg_of_mode, move_cost, may_move_in_cost,
may_move_out_cost): New external variable declarations.
(move_table): New typedef.
* caller-save.c: Include headers output.h and ira.h.
(no_caller_save_reg_set): New global variable.
(save_slots_num, save_slots): New variables.
(reg_save_code, reg_restore_code, add_stored_regs): Add
prototypes.
(init_caller_save): Set up no_caller_save_reg_set.
(init_save_areas): Reset save_slots_num.
(saved_hard_reg): New structure.
(hard_reg_map, saved_regs_num, all_saved_regs): New variables.
(initiate_saved_hard_regs, new_saved_hard_reg,
finish_saved_hard_regs, saved_hard_reg_compare_func): New
functions.
(setup_save_areas): Add code for sharing stack slots.
(all_blocks): New variable.
(save_call_clobbered_regs): Process pseudo-register too.
(mark_set_regs): Process pseudo-register too.
(insert_one_insn): Put the insn after bb note in a empty basic
block. Add insn check.
* global.c (eliminable_regset): Make it external.
(mark_elimination): Use DF_LR_IN for IRA.
(pseudo_for_reload_consideration_p): New.
(build_insn_chain): Make it external. Don't ignore spilled
pseudos for IRA. Use pseudo_for_reload_consideration_p.
(gate_handle_global_alloc): New function.
(pass_global_alloc): Add the gate function.
* opts.c (decode_options): Set up flag_ira. Print the warning for
-fira.
(common_handle_option): Process -fira-algorithm and -fira-verbose.
* timevar.def (TV_IRA, TV_RELOAD): New passes.
* regmove.c (regmove_optimize): Don't do replacement of output for
IRA.
* hard-reg-set.h (no_caller_save_reg_set, reg_class_subclasses):
New external variable declarations.
* local-alloc.c (update_equiv_regs): Make it external. Return
true if jump label rebuilding should be done. Rescan new_insn for
notes.
(gate_handle_local_alloc): New function.
(pass_local_alloc): Add the gate function.
* alias.c (value_addr_p, stack_addr_p): New functions.
(nonoverlapping_memrefs_p): Use them for IRA.
* common.opt (fira, fira-algorithm, fira-coalesce,
fira-move-spills, fira-share-save-slots, fira-share-spill-slots,
fira-verbose): New options.
* regclass.c (reg_class_subclasses, contains_reg_of_mode,
move_cost, may_move_in_cost, may_move_out_cost): Make the
variables external.
(move_table): Remove typedef.
(init_move_cost): Make it external.
(allocate_reg_info, resize_reg_info, setup_reg_classes): New
functions.
* rtl.h (init_move_cost, allocate_reg_info, resize_reg_info,
setup_reg_classes): New function prototypes.
(eliminable_regset): New external variable declaration.
(build_insn_chain, update_equiv_regs): New function prototypes.
* Makefile.in (IRA_INT_H): New definition.
(OBJS-common): Add ira.o, ira-build.o, ira-costs.o,
ira-conflicts.o, ira-color.o, ira-emit.o, and ira-lives.o.
(reload1.o, toplev.o): Add dependence on ira.h.
(cfgloopanal.o): Add PARAMS_H.
(caller-save.o): Add dependence on output.h and ira.h.
(ira.o, ira-build.o, ira-costs.o, ira-conflicts.o, ira-color.o,
ira-emit.o, ira-lives.o): New entries.
* passes.c (pass_ira): New pass.
* params.def (PARAM_IRA_MAX_LOOPS_NUM): New parameter.
* reload1.c (ira.h): Include the header.
(changed_allocation_pseudos): New bitmap.
(init_reload): Initiate the bitmap.
(compute_use_by_pseudos): Permits spilled registers in FROM.
(temp_pseudo_reg_arr): New variable.
(reload): Allocate and free temp_pseudo_reg_arr. Sort pseudos for
IRA. Call alter_reg with the additional parameter. Don't clear
spilled_pseudos for IRA. Restore original insn chain for IRA.
Clear changed_allocation_pseudos at the end of reload.
(calculate_needs_all_insns): Call IRA's mark_memory_move_deletion.
(hard_regno_to_pseudo_regno): New variable.
(count_pseudo): Check spilled pseudos. Set up
hard_regno_to_pseudo_regno.
(count_spilled_pseudo): Check spilled pseudos. Update
hard_regno_to_pseudo_regno.
(find_reg): Use better_spill_reload_regno_p. Check
hard_regno_to_pseudo_regno.
(alter_reg): Set up spilled_pseudos. Add a new parameter. Add
code for IRA.
(eliminate_regs_1): Use additional parameter for alter_reg.
(finish_spills): Set up pseudo_previous_regs only for spilled
pseudos. Call reassign_pseudos once for all spilled pseudos, pass
more arguments. Don't clear live_throughout and dead_or_set for
spilled pseudos. Use additional parameter for alter_reg. Call
mark_allocation_change. Set up changed_allocation_pseudos.
Remove sanity check.
(emit_input_reload_insns, delete_output_reload): Use additional
parameter for alter_reg. Call mark_allocation_change.
(substitute, gen_reload_chain_without_interm_reg_p): New
functions.
(reloads_conflict): Use gen_reload_chain_without_interm_reg_p.
* testsuite/gcc.dg/20080410-1.c: New file.
* config/s390/s390.h (IRA_COVER_CLASSES,
IRA_HARD_REGNO_ADD_COST_MULTIPLIER): Define.
* config/sparc/sparc.h (IRA_COVER_CLASSES): New macro.
* config/i386/i386.h (IRA_COVER_CLASSES): Ditto.
* config/ia64/ia64.h (IRA_COVER_CLASSES): Ditto.
* config/rs6000/rs6000.h (IRA_COVER_CLASSES): Ditto.
* config/arm/arm.h (IRA_COVER_CLASSES): Ditto.
* config/alpha/alpha.h (IRA_COVER_CLASSES): Ditto.
2008-08-24 Jeff Law <law@redhat.com>
* ira.c (setup_reg_class_intersect_union): Prefer smallest class
when ignoring unavailable registers.
2008-08-24 Jeff Law <law@redhat.com>
* ira-color.c (coalesced_pseudo_reg_slot_compare): Check
FRAME_GROWS_DOWNWARD and STACK_GROWS_DOWNWARD.
* ira.c (setup_eliminable_regset): Check stack_realign_needed.
* config/mn10300/mn10300.h (IRA_COVER_CLASSES): New macro.
2008-06-03 Steve Chamberlain <steve.chamberlain@gmail.com>
* ira-build.c (allocno_range_compare_func): Stabilize sort.
2008-05-29 Andy Hutchinson <hutchinsonandy@aim.com>
* config/avr/avr.h (IRA_COVER_CLASSES): New macro.
* reload1.c (find_reg): Process registers in register allocation order.
2008-05-10 Richard Sandiford <rsandifo@nildram.co.uk>
* toplev.c (backend_init_target): Move ira_init call from
here...
(lang_dependent_init_target): ...to here.
2008-05-10 Richard Sandiford <rsandifo@nildram.co.uk>
* ira.c (setup_class_subset_and_memory_move_costs): Don't
calculate memory move costs for NO_REGS.
2008-05-05 Kaz Kojima <kkojima@gcc.gnu.org>
* ira-color.c (ira_fast_allocation): Use no_stack_reg_p only if
STACK_REGS is defined.
2008-04-08 Andrew Pinski <andrew_pinski@playstation.sony.com>
* config/spu/spu.h (IRA_COVER_CLASSES): New macro.
2008-04-04 Bernd Schmidt <bernd.schmidt@analog.com>
* config/bfin/bfin.h (IRA_COVER_CLASSES): New macro.
2008-04-04 Kaz Kojima <kkojima@gcc.gnu.org>
* config/sh/sh.h (IRA_COVER_CLASSES): Define.
* config/sh/sh.md (movsicc_true+3): Check if emit returns a
barrier.
2008-08-26 Victor Kaplansky <victork@il.ibm.com>
Dorit Nuzman <dorit@il.ibm.com>

View File

@ -849,6 +849,7 @@ TREE_DATA_REF_H = tree-data-ref.h $(LAMBDA_H) omega.h graphds.h tree-chrec.h
VARRAY_H = varray.h $(MACHMODE_H) $(SYSTEM_H) coretypes.h $(TM_H)
TREE_INLINE_H = tree-inline.h $(VARRAY_H) pointer-set.h
REAL_H = real.h $(MACHMODE_H)
IRA_INT_H = ira.h ira-int.h $(CFGLOOP_H) alloc-pool.h
DBGCNT_H = dbgcnt.h dbgcnt.def
EBIMAP_H = ebitmap.h sbitmap.h
IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h $(CGRAPH_H)
@ -1097,6 +1098,13 @@ OBJS-common = \
init-regs.o \
integrate.o \
intl.o \
ira.o \
ira-build.o \
ira-costs.o \
ira-conflicts.o \
ira-color.o \
ira-emit.o \
ira-lives.o \
jump.o \
lambda-code.o \
lambda-mat.o \
@ -2408,7 +2416,7 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(INSN_ATTR_H) output.h $(DIAGNOSTIC_H) debug.h insn-config.h intl.h \
$(RECOG_H) Makefile $(TOPLEV_H) dwarf2out.h sdbout.h dbxout.h $(EXPR_H) \
hard-reg-set.h $(BASIC_BLOCK_H) graph.h except.h $(REGS_H) $(TIMEVAR_H) \
value-prof.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \
value-prof.h $(PARAMS_H) $(TM_P_H) reload.h ira.h dwarf2asm.h $(TARGET_H) \
langhooks.h insn-flags.h $(CFGLAYOUT_H) $(CFGLOOP_H) hosthooks.h \
$(CGRAPH_H) $(COVERAGE_H) alloc-pool.h $(GGC_H) $(INTEGRATE_H) \
opts.h params.def tree-mudflap.h $(REAL_H) tree-pass.h $(GIMPLE_H)
@ -2771,7 +2779,7 @@ cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) coretypes.h $(TM_H) \
$(GGC_H)
cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) \
$(OBSTACK_H) output.h graphds.h
$(OBSTACK_H) output.h graphds.h $(PARAMS_H)
graphds.o : graphds.c graphds.h $(CONFIG_H) $(SYSTEM_H) $(BITMAP_H) $(OBSTACK_H) \
coretypes.h vec.h vecprim.h
loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
@ -2835,7 +2843,7 @@ 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) \
addresses.h except.h $(TREE_H) $(REAL_H) $(FLAGS_H) $(MACHMODE_H) \
$(OBSTACK_H) $(DF_H) $(TARGET_H) dse.h
$(OBSTACK_H) $(DF_H) $(TARGET_H) dse.h ira.h
rtlhooks.o : rtlhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
rtlhooks-def.h $(EXPR_H) $(RECOG_H)
postreload.o : postreload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
@ -2851,7 +2859,7 @@ postreload-gcse.o : postreload-gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
caller-save.o : caller-save.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) $(FUNCTION_H) \
addresses.h $(RECOG_H) reload.h $(EXPR_H) $(TOPLEV_H) $(TM_P_H) $(DF_H) \
gt-caller-save.h $(GGC_H)
output.h ira.h gt-caller-save.h $(GGC_H)
bt-load.o : bt-load.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) except.h \
$(RTL_H) hard-reg-set.h $(REGS_H) $(TM_P_H) $(FIBHEAP_H) output.h $(EXPR_H) \
$(TARGET_H) $(FLAGS_H) $(INSN_ATTR_H) $(FUNCTION_H) tree-pass.h $(TOPLEV_H) \
@ -2872,6 +2880,37 @@ stack-ptr-mod.o : stack-ptr-mod.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
init-regs.o : init-regs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TREE_H) $(RTL_H) $(REGS_H) $(EXPR_H) tree-pass.h \
$(BASIC_BLOCK_H) $(FLAGS_H) $(DF_H)
ira-build.o: ira-build.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) \
$(PARAMS_H) $(DF_H) sparseset.h $(IRA_INT_H)
ira-costs.o: ira-costs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(RTL_H) insn-config.h $(RECOG_H) \
$(REGS_H) hard-reg-set.h $(FLAGS_H) errors.h \
$(EXPR_H) $(BASIC_BLOCK_H) $(TM_P_H) \
$(IRA_INT_H)
ira-conflicts.o: ira-conflicts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
$(DF_H) sparseset.h $(IRA_INT_H)
ira-color.o: ira-color.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
$(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
$(DF_H) $(SPLAY_TREE_H) $(IRA_INT_H)
ira-emit.o: ira-emit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
$(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
$(IRA_INT_H)
ira-lives.o: ira-lives.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
$(DF_H) sparseset.h $(IRA_INT_H)
ira.o: ira.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TARGET_H) $(TM_H) $(RTL_H) $(RECOG_H) \
$(REGS_H) hard-reg-set.h $(FLAGS_H) $(OBSTACK_H) \
$(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) \
$(DF_H) $(IRA_INT_H) $(PARAMS_H) $(TIMEVAR_H) $(INTEGRATE_H) \
tree-pass.h output.h
regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
insn-config.h $(TIMEVAR_H) tree-pass.h $(DF_H)\
$(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \

View File

@ -1975,6 +1975,34 @@ adjust_offset_for_component_ref (tree x, rtx offset)
return GEN_INT (ioffset);
}
/* The function returns nonzero if X is an address containg VALUE. */
static int
value_addr_p (rtx x)
{
if (GET_CODE (x) == VALUE)
return 1;
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == VALUE)
return 1;
return 0;
}
/* The function returns nonzero if X is a stack address. */
static int
stack_addr_p (rtx x)
{
if (x == hard_frame_pointer_rtx || x == frame_pointer_rtx
|| x == arg_pointer_rtx || x == stack_pointer_rtx)
return 1;
if (GET_CODE (x) == PLUS
&& (XEXP (x, 0) == hard_frame_pointer_rtx
|| XEXP (x, 0) == frame_pointer_rtx
|| XEXP (x, 0) == arg_pointer_rtx
|| XEXP (x, 0) == stack_pointer_rtx)
&& CONSTANT_P (XEXP (x, 1)))
return 1;
return 0;
}
/* Return nonzero if we can determine the exprs corresponding to memrefs
X and Y and they do not overlap. */
@ -1984,9 +2012,27 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
tree exprx = MEM_EXPR (x), expry = MEM_EXPR (y);
rtx rtlx, rtly;
rtx basex, basey;
rtx x_addr, y_addr;
rtx moffsetx, moffsety;
HOST_WIDE_INT offsetx = 0, offsety = 0, sizex, sizey, tem;
if (flag_ira && optimize && reload_completed)
{
/* We need this code for IRA because of stack slot sharing. RTL
in decl can be different than RTL used in insns. It is a
safe code although it can be conservative sometime. */
x_addr = canon_rtx (get_addr (XEXP (x, 0)));
y_addr = canon_rtx (get_addr (XEXP (y, 0)));
if (value_addr_p (x_addr) || value_addr_p (y_addr))
return 0;
if (stack_addr_p (x_addr) && stack_addr_p (y_addr)
&& memrefs_conflict_p (SIZE_FOR_MODE (y), y_addr,
SIZE_FOR_MODE (x), x_addr, 0))
return 0;
}
/* Unless both have exprs, we can't tell anything. */
if (exprx == 0 || expry == 0)
return 0;

View File

@ -1,6 +1,6 @@
/* Save and restore call-clobbered registers which are live across a call.
Copyright (C) 1989, 1992, 1994, 1995, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GCC.
@ -35,9 +35,14 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h"
#include "tm_p.h"
#include "addresses.h"
#include "output.h"
#include "df.h"
#include "ggc.h"
/* Call used hard registers which can not be saved because there is no
insn for this. */
HARD_REG_SET no_caller_save_reg_set;
#ifndef MAX_MOVE_MAX
#define MAX_MOVE_MAX MOVE_MAX
#endif
@ -62,6 +67,12 @@ static enum machine_mode
static rtx
regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
/* The number of elements in the subsequent array. */
static int save_slots_num;
/* Allocated slots so far. */
static rtx save_slots[FIRST_PSEUDO_REGISTER];
/* We will only make a register eligible for caller-save if it can be
saved in its widest mode with a simple SET insn as long as the memory
address is valid. We record the INSN_CODE is those insns here since
@ -86,7 +97,17 @@ static int n_regs_saved;
static HARD_REG_SET referenced_regs;
static int reg_save_code (int, enum machine_mode);
static int reg_restore_code (int, enum machine_mode);
struct saved_hard_reg;
static void initiate_saved_hard_regs (void);
static struct saved_hard_reg *new_saved_hard_reg (int, int);
static void finish_saved_hard_regs (void);
static int saved_hard_reg_compare_func (const void *, const void *);
static void mark_set_regs (rtx, const_rtx, void *);
static void add_stored_regs (rtx, const_rtx, void *);
static void mark_referenced_regs (rtx);
static int insert_save (struct insn_chain *, int, int, HARD_REG_SET *,
enum machine_mode *);
@ -95,7 +116,9 @@ static int insert_restore (struct insn_chain *, int, int, int,
static struct insn_chain *insert_one_insn (struct insn_chain *, int, int,
rtx);
static void add_stored_regs (rtx, const_rtx, void *);
static GTY(()) rtx savepat;
static GTY(()) rtx restpat;
static GTY(()) rtx test_reg;
@ -180,6 +203,7 @@ init_caller_save (void)
rtx address;
int i, j;
CLEAR_HARD_REG_SET (no_caller_save_reg_set);
/* First find all the registers that we need to deal with and all
the modes that they can have. If we can't find a mode to use,
we can't have the register live over calls. */
@ -217,7 +241,7 @@ init_caller_save (void)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT
(reg_class_contents
[(int) base_reg_class (regno_save_mode [i][1], PLUS, CONST_INT)], i))
[(int) base_reg_class (regno_save_mode[i][1], PLUS, CONST_INT)], i))
break;
gcc_assert (i < FIRST_PSEUDO_REGISTER);
@ -264,10 +288,14 @@ init_caller_save (void)
{
call_fixed_regs[i] = 1;
SET_HARD_REG_BIT (call_fixed_reg_set, i);
if (call_used_regs[i])
SET_HARD_REG_BIT (no_caller_save_reg_set, i);
}
}
}
/* Initialize save areas by showing that we haven't allocated any yet. */
void
@ -278,6 +306,100 @@ init_save_areas (void)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = 1; j <= MOVE_MAX_WORDS; j++)
regno_save_mem[i][j] = 0;
save_slots_num = 0;
}
/* The structure represents a hard register which should be saved
through the call. It is used when the integrated register
allocator (IRA) is used and sharing save slots is on. */
struct saved_hard_reg
{
/* Order number starting with 0. */
int num;
/* The hard regno. */
int hard_regno;
/* Execution frequency of all calls through which given hard
register should be saved. */
int call_freq;
/* Stack slot reserved to save the hard register through calls. */
rtx slot;
/* True if it is first hard register in the chain of hard registers
sharing the same stack slot. */
int first_p;
/* Order number of the next hard register structure with the same
slot in the chain. -1 represents end of the chain. */
int next;
};
/* Map: hard register number to the corresponding structure. */
static struct saved_hard_reg *hard_reg_map[FIRST_PSEUDO_REGISTER];
/* The number of all structures representing hard registers should be
saved, in order words, the number of used elements in the following
array. */
static int saved_regs_num;
/* Pointers to all the structures. Index is the order number of the
corresponding structure. */
static struct saved_hard_reg *all_saved_regs[FIRST_PSEUDO_REGISTER];
/* First called function for work with saved hard registers. */
static void
initiate_saved_hard_regs (void)
{
int i;
saved_regs_num = 0;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
hard_reg_map[i] = NULL;
}
/* Allocate and return new saved hard register with given REGNO and
CALL_FREQ. */
static struct saved_hard_reg *
new_saved_hard_reg (int regno, int call_freq)
{
struct saved_hard_reg *saved_reg;
saved_reg
= (struct saved_hard_reg *) xmalloc (sizeof (struct saved_hard_reg));
hard_reg_map[regno] = all_saved_regs[saved_regs_num] = saved_reg;
saved_reg->num = saved_regs_num++;
saved_reg->hard_regno = regno;
saved_reg->call_freq = call_freq;
saved_reg->first_p = FALSE;
saved_reg->next = -1;
return saved_reg;
}
/* Free memory allocated for the saved hard registers. */
static void
finish_saved_hard_regs (void)
{
int i;
for (i = 0; i < saved_regs_num; i++)
free (all_saved_regs[i]);
}
/* The function is used to sort the saved hard register structures
according their frequency. */
static int
saved_hard_reg_compare_func (const void *v1p, const void *v2p)
{
const struct saved_hard_reg *p1 = *(struct saved_hard_reg * const *) v1p;
const struct saved_hard_reg *p2 = *(struct saved_hard_reg * const *) v2p;
if (flag_omit_frame_pointer)
{
if (p1->call_freq - p2->call_freq != 0)
return p1->call_freq - p2->call_freq;
}
else if (p2->call_freq - p1->call_freq != 0)
return p2->call_freq - p1->call_freq;
return p1->num - p2->num;
}
/* Allocate save areas for any hard registers that might need saving.
@ -286,6 +408,10 @@ init_save_areas (void)
overestimate slightly (especially if some of these registers are later
used as spill registers), but it should not be significant.
For IRA we use priority coloring to decrease stack slots needed for
saving hard registers through calls. We build conflicts for them
to do coloring.
Future work:
In the fallback case we should iterate backwards across all possible
@ -317,65 +443,297 @@ setup_save_areas (void)
unsigned int regno = reg_renumber[i];
unsigned int endregno
= end_hard_regno (GET_MODE (regno_reg_rtx[i]), regno);
for (r = regno; r < endregno; r++)
if (call_used_regs[r])
SET_HARD_REG_BIT (hard_regs_used, r);
}
/* Now run through all the call-used hard-registers and allocate
space for them in the caller-save area. Try to allocate space
in a manner which allows multi-register saves/restores to be done. */
if (flag_ira && optimize && flag_ira_share_save_slots)
{
rtx insn, slot;
struct insn_chain *chain, *next;
char *saved_reg_conflicts;
unsigned int regno;
int next_k, freq;
struct saved_hard_reg *saved_reg, *saved_reg2, *saved_reg3;
int call_saved_regs_num;
struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER];
HARD_REG_SET hard_regs_to_save, used_regs, this_insn_sets;
reg_set_iterator rsi;
int best_slot_num;
int prev_save_slots_num;
rtx prev_save_slots[FIRST_PSEUDO_REGISTER];
initiate_saved_hard_regs ();
/* Create hard reg saved regs. */
for (chain = reload_insn_chain; chain != 0; chain = next)
{
insn = chain->insn;
next = chain->next;
if (GET_CODE (insn) != CALL_INSN
|| find_reg_note (insn, REG_NORETURN, NULL))
continue;
freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
&chain->live_throughout);
COPY_HARD_REG_SET (used_regs, call_used_reg_set);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = MOVE_MAX_WORDS; j > 0; j--)
{
int do_save = 1;
/* Record all registers set in this call insn. These don't
need to be saved. N.B. the call insn might set a subreg
of a multi-hard-reg pseudo; then the pseudo is considered
live during the call, but the subreg that is set
isn't. */
CLEAR_HARD_REG_SET (this_insn_sets);
note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
/* Sibcalls are considered to set the return value. */
if (SIBLING_CALL_P (insn) && crtl->return_rtx)
mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
/* If no mode exists for this size, try another. Also break out
if we have already saved this hard register. */
if (regno_save_mode[i][j] == VOIDmode || regno_save_mem[i][1] != 0)
continue;
/* See if any register in this group has been saved. */
for (k = 0; k < j; k++)
if (regno_save_mem[i + k][1])
AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
AND_HARD_REG_SET (hard_regs_to_save, used_regs);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
{
if (hard_reg_map[regno] != NULL)
hard_reg_map[regno]->call_freq += freq;
else
saved_reg = new_saved_hard_reg (regno, freq);
}
/* Look through all live pseudos, mark their hard registers. */
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
{
do_save = 0;
break;
int r = reg_renumber[regno];
int bound;
if (r < 0)
continue;
bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
for (; r < bound; r++)
if (TEST_HARD_REG_BIT (used_regs, r))
{
if (hard_reg_map[r] != NULL)
hard_reg_map[r]->call_freq += freq;
else
saved_reg = new_saved_hard_reg (r, freq);
SET_HARD_REG_BIT (hard_regs_to_save, r);
}
}
if (! do_save)
continue;
}
/* Find saved hard register conflicts. */
saved_reg_conflicts = (char *) xmalloc (saved_regs_num * saved_regs_num);
memset (saved_reg_conflicts, 0, saved_regs_num * saved_regs_num);
for (chain = reload_insn_chain; chain != 0; chain = next)
{
call_saved_regs_num = 0;
insn = chain->insn;
next = chain->next;
if (GET_CODE (insn) != CALL_INSN
|| find_reg_note (insn, REG_NORETURN, NULL))
continue;
REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
&chain->live_throughout);
COPY_HARD_REG_SET (used_regs, call_used_reg_set);
for (k = 0; k < j; k++)
if (! TEST_HARD_REG_BIT (hard_regs_used, i + k))
/* Record all registers set in this call insn. These don't
need to be saved. N.B. the call insn might set a subreg
of a multi-hard-reg pseudo; then the pseudo is considered
live during the call, but the subreg that is set
isn't. */
CLEAR_HARD_REG_SET (this_insn_sets);
note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
/* Sibcalls are considered to set the return value,
compare flow.c:propagate_one_insn. */
if (SIBLING_CALL_P (insn) && crtl->return_rtx)
mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
AND_HARD_REG_SET (hard_regs_to_save, used_regs);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
{
gcc_assert (hard_reg_map[regno] != NULL);
call_saved_regs[call_saved_regs_num++] = hard_reg_map[regno];
}
/* Look through all live pseudos, mark their hard registers. */
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
{
do_save = 0;
break;
int r = reg_renumber[regno];
int bound;
if (r < 0)
continue;
bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
for (; r < bound; r++)
if (TEST_HARD_REG_BIT (used_regs, r))
call_saved_regs[call_saved_regs_num++] = hard_reg_map[r];
}
if (! do_save)
continue;
/* We have found an acceptable mode to store in. Since hard
register is always saved in the widest mode available,
the mode may be wider than necessary, it is OK to reduce
the alignment of spill space. We will verify that it is
equal to or greater than required when we restore and save
the hard register in insert_restore and insert_save. */
regno_save_mem[i][j]
= assign_stack_local_1 (regno_save_mode[i][j],
GET_MODE_SIZE (regno_save_mode[i][j]),
0, true);
/* Setup single word save area just in case... */
for (k = 0; k < j; k++)
/* This should not depend on WORDS_BIG_ENDIAN.
The order of words in regs is the same as in memory. */
regno_save_mem[i + k][1]
= adjust_address_nv (regno_save_mem[i][j],
regno_save_mode[i + k][1],
k * UNITS_PER_WORD);
}
for (i = 0; i < call_saved_regs_num; i++)
{
saved_reg = call_saved_regs[i];
for (j = 0; j < call_saved_regs_num; j++)
if (i != j)
{
saved_reg2 = call_saved_regs[j];
saved_reg_conflicts[saved_reg->num * saved_regs_num
+ saved_reg2->num]
= saved_reg_conflicts[saved_reg2->num * saved_regs_num
+ saved_reg->num]
= TRUE;
}
}
}
/* Sort saved hard regs. */
qsort (all_saved_regs, saved_regs_num, sizeof (struct saved_hard_reg *),
saved_hard_reg_compare_func);
/* Initiate slots available from the previous reload
iteration. */
prev_save_slots_num = save_slots_num;
memcpy (prev_save_slots, save_slots, save_slots_num * sizeof (rtx));
save_slots_num = 0;
/* Allocate stack slots for the saved hard registers. */
for (i = 0; i < saved_regs_num; i++)
{
saved_reg = all_saved_regs[i];
regno = saved_reg->hard_regno;
for (j = 0; j < i; j++)
{
saved_reg2 = all_saved_regs[j];
if (! saved_reg2->first_p)
continue;
slot = saved_reg2->slot;
for (k = j; k >= 0; k = next_k)
{
saved_reg3 = all_saved_regs[k];
next_k = saved_reg3->next;
if (saved_reg_conflicts[saved_reg->num * saved_regs_num
+ saved_reg3->num])
break;
}
if (k < 0
&& (GET_MODE_SIZE (regno_save_mode[regno][1])
<= GET_MODE_SIZE (regno_save_mode
[saved_reg2->hard_regno][1])))
{
saved_reg->slot
= adjust_address_nv
(slot, regno_save_mode[saved_reg->hard_regno][1], 0);
regno_save_mem[regno][1] = saved_reg->slot;
saved_reg->next = saved_reg2->next;
saved_reg2->next = i;
if (dump_file != NULL)
fprintf (dump_file, "%d uses slot of %d\n",
regno, saved_reg2->hard_regno);
break;
}
}
if (j == i)
{
saved_reg->first_p = TRUE;
for (best_slot_num = -1, j = 0; j < prev_save_slots_num; j++)
{
slot = prev_save_slots[j];
if (slot == NULL_RTX)
continue;
if (GET_MODE_SIZE (regno_save_mode[regno][1])
<= GET_MODE_SIZE (GET_MODE (slot))
&& best_slot_num < 0)
best_slot_num = j;
if (GET_MODE (slot) == regno_save_mode[regno][1])
break;
}
if (best_slot_num >= 0)
{
saved_reg->slot = prev_save_slots[best_slot_num];
saved_reg->slot
= adjust_address_nv
(saved_reg->slot,
regno_save_mode[saved_reg->hard_regno][1], 0);
if (dump_file != NULL)
fprintf (dump_file,
"%d uses a slot from prev iteration\n", regno);
prev_save_slots[best_slot_num] = NULL_RTX;
if (best_slot_num + 1 == prev_save_slots_num)
prev_save_slots_num--;
}
else
{
saved_reg->slot
= assign_stack_local_1
(regno_save_mode[regno][1],
GET_MODE_SIZE (regno_save_mode[regno][1]), 0, true);
if (dump_file != NULL)
fprintf (dump_file, "%d uses a new slot\n", regno);
}
regno_save_mem[regno][1] = saved_reg->slot;
save_slots[save_slots_num++] = saved_reg->slot;
}
}
free (saved_reg_conflicts);
finish_saved_hard_regs ();
}
else
{
/* Now run through all the call-used hard-registers and allocate
space for them in the caller-save area. Try to allocate space
in a manner which allows multi-register saves/restores to be done. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = MOVE_MAX_WORDS; j > 0; j--)
{
int do_save = 1;
/* If no mode exists for this size, try another. Also break out
if we have already saved this hard register. */
if (regno_save_mode[i][j] == VOIDmode || regno_save_mem[i][1] != 0)
continue;
/* See if any register in this group has been saved. */
for (k = 0; k < j; k++)
if (regno_save_mem[i + k][1])
{
do_save = 0;
break;
}
if (! do_save)
continue;
for (k = 0; k < j; k++)
if (! TEST_HARD_REG_BIT (hard_regs_used, i + k))
{
do_save = 0;
break;
}
if (! do_save)
continue;
/* We have found an acceptable mode to store in. Since
hard register is always saved in the widest mode
available, the mode may be wider than necessary, it is
OK to reduce the alignment of spill space. We will
verify that it is equal to or greater than required
when we restore and save the hard register in
insert_restore and insert_save. */
regno_save_mem[i][j]
= assign_stack_local_1 (regno_save_mode[i][j],
GET_MODE_SIZE (regno_save_mode[i][j]),
0, true);
/* Setup single word save area just in case... */
for (k = 0; k < j; k++)
/* This should not depend on WORDS_BIG_ENDIAN.
The order of words in regs is the same as in memory. */
regno_save_mem[i + k][1]
= adjust_address_nv (regno_save_mem[i][j],
regno_save_mode[i + k][1],
k * UNITS_PER_WORD);
}
}
/* Now loop again and set the alias set of any save areas we made to
the alias set used to represent frame objects. */
@ -384,7 +742,9 @@ setup_save_areas (void)
if (regno_save_mem[i][j] != 0)
set_mem_alias_set (regno_save_mem[i][j], get_frame_alias_set ());
}
/* Find the places where hard regs are live across calls and save them. */
void
@ -461,7 +821,8 @@ save_call_clobbered_regs (void)
int nregs;
enum machine_mode mode;
gcc_assert (r >= 0);
if (r < 0)
continue;
nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
mode = HARD_REGNO_CALLER_SAVE_MODE
(r, nregs, PSEUDO_REGNO_MODE (regno));
@ -497,7 +858,7 @@ save_call_clobbered_regs (void)
}
}
if (chain->next == 0 || chain->next->block > chain->block)
if (chain->next == 0 || chain->next->block != chain->block)
{
int regno;
/* At the end of the basic block, we must restore any registers that
@ -713,7 +1074,8 @@ insert_restore (struct insn_chain *chain, int before_p, int regno,
/* Verify that the alignment of spill space is equal to or greater
than required. */
gcc_assert (GET_MODE_ALIGNMENT (GET_MODE (mem)) <= MEM_ALIGN (mem));
gcc_assert (MIN (MAX_SUPPORTED_STACK_ALIGNMENT,
GET_MODE_ALIGNMENT (GET_MODE (mem))) <= MEM_ALIGN (mem));
pat = gen_rtx_SET (VOIDmode,
gen_rtx_REG (GET_MODE (mem),
@ -790,7 +1152,8 @@ insert_save (struct insn_chain *chain, int before_p, int regno,
/* Verify that the alignment of spill space is equal to or greater
than required. */
gcc_assert (GET_MODE_ALIGNMENT (GET_MODE (mem)) <= MEM_ALIGN (mem));
gcc_assert (MIN (MAX_SUPPORTED_STACK_ALIGNMENT,
GET_MODE_ALIGNMENT (GET_MODE (mem))) <= MEM_ALIGN (mem));
pat = gen_rtx_SET (VOIDmode, mem,
gen_rtx_REG (GET_MODE (mem),

View File

@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "expr.h"
#include "output.h"
#include "graphds.h"
#include "params.h"
/* Checks whether BB is executed exactly once in each LOOP iteration. */
@ -372,6 +373,7 @@ init_set_costs (void)
unsigned
estimate_reg_pressure_cost (unsigned n_new, unsigned n_old)
{
unsigned cost;
unsigned regs_needed = n_new + n_old;
/* If we have enough registers, we should use them and not restrict
@ -379,12 +381,25 @@ estimate_reg_pressure_cost (unsigned n_new, unsigned n_old)
if (regs_needed + target_res_regs <= target_avail_regs)
return 0;
/* If we are close to running out of registers, try to preserve them. */
if (regs_needed <= target_avail_regs)
return target_reg_cost * n_new;
/* If we run out of registers, it is very expensive to add another one. */
return target_spill_cost * n_new;
/* If we are close to running out of registers, try to preserve
them. */
cost = target_reg_cost * n_new;
else
/* If we run out of registers, it is very expensive to add another
one. */
cost = target_spill_cost * n_new;
if (optimize && flag_ira && (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
|| flag_ira_algorithm == IRA_ALGORITHM_MIXED)
&& number_of_loops () <= (unsigned) IRA_MAX_LOOPS_NUM)
/* IRA regional allocation deals with high register pressure
better. So decrease the cost (to do more accurate the cost
calculation for IRA, we need to know how many registers lives
through the loop transparently). */
cost /= 2;
return cost;
}
/* Sets EDGE_LOOP_EXIT flag for all loop exits. */

View File

@ -653,6 +653,30 @@ Common Report Var(flag_ipa_struct_reorg)
Perform structure layout optimizations based
on profiling information.
fira
Common Report Var(flag_ira) Init(0)
Use integrated register allocator.
fira-algorithm=
Common Joined RejectNegative
-fira-algorithm=[regional|CB|mixed] Set the used IRA algorithm
fira-coalesce
Common Report Var(flag_ira_coalesce) Init(0)
Do optimistic coalescing.
fira-share-save-slots
Common Report Var(flag_ira_share_save_slots) Init(1)
Share slots for saving different hard registers.
fira-share-spill-slots
Common Report Var(flag_ira_share_spill_slots) Init(1)
Share stack slots for spilled pseudo-registers.
fira-verbose=
Common RejectNegative Joined UInteger
-fira-verbose=<number> Control IRA's level of diagnostic messages.
fivopts
Common Report Var(flag_ivopts) Init(1) Optimization
Optimize induction variables on trees

View File

@ -553,6 +553,19 @@ enum reg_class {
{0x00000000, 0x7fffffff}, /* FLOAT_REGS */ \
{0xffffffff, 0xffffffff} }
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, FLOAT_REGS, LIM_REG_CLASSES \
}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression

View File

@ -1185,6 +1185,20 @@ enum reg_class
or could index an array. */
#define REGNO_REG_CLASS(REGNO) arm_regno_class (REGNO)
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, FPA_REGS, CIRRUS_REGS, VFP_REGS, IWMMXT_GR_REGS, IWMMXT_REGS,\
LIM_REG_CLASSES \
}
/* FPA registers can't do subreg as all values are reformatted to internal
precision. VFP registers may only be accessed in the mode they
were set. */

View File

@ -291,6 +291,19 @@ enum reg_class {
#define REGNO_REG_CLASS(R) avr_regno_reg_class(R)
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, LIM_REG_CLASSES \
}
#define BASE_REG_CLASS (reload_completed ? BASE_POINTER_REGS : POINTER_REGS)
#define INDEX_REG_CLASS NO_REGS

View File

@ -711,6 +711,19 @@ enum reg_class
: (REGNO) >= REG_RETS ? PROLOGUE_REGS \
: NO_REGS)
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
MOST_REGS, AREGS, CCREGS, LIM_REG_CLASSES \
}
/* When defined, the compiler allows registers explicitly used in the
rtl to be used as spill registers but prevents the compiler from
extending the lifetime of these registers. */

View File

@ -1274,6 +1274,19 @@ enum reg_class
{ 0xffffffff,0x1fffff } \
}
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, FLOAT_REGS, MMX_REGS, SSE_REGS, LIM_REG_CLASSES \
}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression

View File

@ -800,6 +800,19 @@ enum reg_class
0xFFFFFFFF, 0xFFFFFFFF, 0x3FFF }, \
}
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
PR_REGS, BR_REGS, AR_M_REGS, AR_I_REGS, GR_REGS, FR_REGS, LIM_REG_CLASSES \
}
/* A C expression whose value is a register class containing hard register
REGNO. In general there is more than one such class; choose a class which
is "minimal", meaning that no smaller class also contains the register. */

View File

@ -295,6 +295,19 @@ enum reg_class {
{ 0xffffffff, 0x3ffff } /* ALL_REGS */ \
}
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, FP_REGS, LIM_REG_CLASSES \
}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression

View File

@ -1128,6 +1128,22 @@ enum reg_class
{ 0xffffffff, 0xffffffff, 0xffffffff, 0x0003ffff } /* ALL_REGS */ \
}
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, SPECIAL_REGS, FLOAT_REGS, ALTIVEC_REGS, \
/*VRSAVE_REGS,*/ VSCR_REGS, SPE_ACC_REGS, SPEFSCR_REGS, \
/* MQ_REGS, LINK_REGS, CTR_REGS, */ \
CR_REGS, XER_REGS, LIM_REG_CLASSES \
}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression

View File

@ -478,6 +478,30 @@ enum reg_class
{ 0xffffffff, 0x0000003f }, /* ALL_REGS */ \
}
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, FP_REGS, CC_REGS, ACCESS_REGS, LIM_REG_CLASSES \
}
/* In some case register allocation order is not enough for IRA to
generate a good code. The following macro (if defined) increases
cost of REGNO for a pseudo approximately by pseudo usage frequency
multiplied by the macro value.
We avoid usage of BASE_REGNUM by nonzero macro value because the
reload can decide not to use the hard register because some
constant was forced to be in memory. */
#define IRA_HARD_REGNO_ADD_COST_MULTIPLIER(regno) \
(regno == BASE_REGNUM ? 0.0 : 0.5)
/* Register -> class mapping. */
extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])

View File

@ -1499,6 +1499,20 @@ enum reg_class
extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
#define REGNO_REG_CLASS(REGNO) regno_reg_class[(REGNO)]
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, FP_REGS, PR_REGS, T_REGS, MAC_REGS, TARGET_REGS, \
LIM_REG_CLASSES \
}
/* When defined, the compiler allows registers explicitly used in the
rtl to be used as spill registers but prevents the compiler from
extending the lifetime of these registers. */

View File

@ -1143,7 +1143,7 @@
(set (match_dup 4) (match_dup 5))]
"
{
rtx set1, set2;
rtx set1, set2, insn2;
rtx replacements[4];
/* We want to replace occurrences of operands[0] with operands[1] and
@ -1173,7 +1173,10 @@
extract_insn (emit_insn (set1));
if (! constrain_operands (1))
goto failure;
extract_insn (emit (set2));
insn2 = emit (set2);
if (GET_CODE (insn2) == BARRIER)
goto failure;
extract_insn (insn2);
if (! constrain_operands (1))
{
rtx tmp;

View File

@ -1078,6 +1078,19 @@ enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, FP_REGS,
{-1, -1, -1, 0x20}, /* GENERAL_OR_EXTRA_FP_REGS */ \
{-1, -1, -1, 0x3f}} /* ALL_REGS */
/* The following macro defines cover classes for Integrated Register
Allocator. Cover classes is a set of non-intersected register
classes covering all hard registers used for register allocation
purpose. Any move between two registers of a cover class should be
cheaper than load or store of the registers. The macro value is
array of register classes with LIM_REG_CLASSES used as the end
marker. */
#define IRA_COVER_CLASSES \
{ \
GENERAL_REGS, EXTRA_FP_REGS, FPCC_REGS, LIM_REG_CLASSES \
}
/* Defines invalid mode changes. Borrowed from pa64-regs.h.
SImode loads to floating-point registers are not zero-extended.

View File

@ -196,6 +196,9 @@ enum reg_class {
LIM_REG_CLASSES
};
/* SPU is simple, it really only has one class of registers. */
#define IRA_COVER_CLASSES { GENERAL_REGS, LIM_REG_CLASSES }
#define N_REG_CLASSES (int) LIM_REG_CLASSES
#define REG_CLASS_NAMES \

View File

@ -274,7 +274,8 @@ Objective-C and Objective-C++ Dialects}.
@xref{Debugging Options,,Options for Debugging Your Program or GCC}.
@gccoptlist{-d@var{letters} -dumpspecs -dumpmachine -dumpversion @gol
-fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol
-fdump-noaddr -fdump-unnumbered -fdump-translation-unit@r{[}-@var{n}@r{]} @gol
-fdump-noaddr -fdump-unnumbered @gol
-fdump-translation-unit@r{[}-@var{n}@r{]} @gol
-fdump-class-hierarchy@r{[}-@var{n}@r{]} @gol
-fdump-ipa-all -fdump-ipa-cgraph -fdump-ipa-inline @gol
-fdump-statistics @gol
@ -332,7 +333,10 @@ Objective-C and Objective-C++ Dialects}.
-finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
-finline-small-functions -fipa-cp -fipa-cp-clone -fipa-marix-reorg -fipa-pta @gol
-fipa-pure-const -fipa-reference -fipa-struct-reorg @gol
-fipa-type-escape -fivopts -fkeep-inline-functions -fkeep-static-consts @gol
-fipa-type-escape -fira -fira-algorithm=@var{algorithm} @gol
-fira-coalesce -fno-ira-share-save-slots @gol
-fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
-fivopts -fkeep-inline-functions -fkeep-static-consts @gol
-fmerge-all-constants -fmerge-constants -fmodulo-sched @gol
-fmodulo-sched-allow-regmoves -fmove-loop-invariants -fmudflap @gol
-fmudflapir -fmudflapth -fno-branch-count-reg -fno-default-inline @gol
@ -5673,6 +5677,49 @@ optimization.
Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
@item -fira
@opindex fira
Use the integrated register allocator (@acronym{IRA}) for register
allocation. It is a default if @acronym{IRA} has been ported for the
target.
@item -fira-algorithm=@var{algorithm}
Use specified algorithm for the integrated register allocator. The
@var{algorithm} argument should be one of @code{regional}, @code{CB},
or @code{mixed}. The second algorithm specifies Chaitin-Briggs
coloring, the first one specifies regional coloring based on
Chaitin-Briggs coloring, and the third one which is the default
specifies a mix of Chaitin-Briggs and regional algorithms where loops
with small register pressure are ignored. The first algorithm can
give best result for machines with small size and irregular register
set, the second one is faster and generates decent code and the
smallest size code, and the mixed algorithm usually give the best
results in most cases and for most architectures.
@item -fira-coalesce
@opindex fira-coalesce
Do optimistic register coalescing. This option might be profitable for
architectures with big regular register files.
@item -fno-ira-share-save-slots
@opindex fno-ira-share-save-slots
Switch off sharing stack slots used for saving call used hard
registers living through a call. Each hard register will get a
separate stack slot and as a result function stack frame will be
bigger.
@item -fno-ira-share-spill-slots
@opindex fno-ira-share-spill-slots
Switch off sharing stack slots allocated for pseudo-registers. Each
pseudo-register which did not get a hard register will get a separate
stack slot and as a result function stack frame will be bigger.
@item -fira-verbose=@var{n}
@opindex fira-verbose
Set up how verbose dump file for the integrated register allocator
will be. Default value is 5. If the value is greater or equal to 10,
the dump file will be stderr as if the value were @var{n} minus 10.
@item -fdelayed-branch
@opindex fdelayed-branch
If supported for the target machine, attempt to reorder instructions
@ -7384,6 +7431,13 @@ processing. If this limit is hit, SCCVN processing for the whole
function will not be done and optimizations depending on it will
be disabled. The default maximum SCC size is 10000.
@item ira-max-loops-num
IRA uses a regional register allocation by default. If a function
contains loops more than number given by the parameter, non-regional
register allocator will be used even when option
@option{-fira-algorithm} is given. The default value of the parameter
is 20.
@end table
@end table

View File

@ -841,6 +841,28 @@ Global register allocation. This pass allocates hard registers for
the remaining pseudo registers (those whose life spans are not
contained in one basic block). The pass is located in @file{global.c}.
@item
The optional integrated register allocator (@acronym{IRA}). It can be
used instead of the local and global allocator. It is called
integrated because coalescing, register live range splitting, and hard
register preferencing are done on-the-fly during coloring. It also
has better integration with the reload pass. Pseudo-registers spilled
by the allocator or the reload have still a chance to get
hard-registers if the reload evicts some pseudo-registers from
hard-registers. The allocator helps to choose better pseudos for
spilling based on their live ranges and to coalesce stack slots
allocated for the spilled pseudo-registers. IRA is a regional
register allocator which is transformed into Chaitin-Briggs allocator
if there is one region. By default, IRA chooses regions using
register pressure but the user can force it to use one region or
regions corresponding to all loops.
Source files of the allocator are @file{ira.c}, @file{ira-build.c},
@file{ira-costs.c}, @file{ira-conflicts.c}, @file{ira-color.c},
@file{ira-emit.c}, @file{ira-lives}, plus header files @file{ira.h}
and @file{ira-int.h} used for the communication between the allocator
and the rest of the compiler and between the IRA files.
@cindex reloading
@item
Reloading. This pass renumbers pseudo registers with the hardware

View File

@ -2026,6 +2026,18 @@ The macro body should not assume anything about the contents of
On most machines, it is not necessary to define this macro.
@end defmac
@defmac IRA_HARD_REGNO_ADD_COST_MULTIPLIER (@var{regno})
In some case register allocation order is not enough for the
Integrated Register Allocator (@acronym{IRA}) to generate a good code.
If this macro is defined, it should return a floating point value
based on @var{regno}. The cost of using @var{regno} for a pseudo will
be increased by approximately the pseudo's usage frequency times the
value returned by this macro. Not defining this macro is equivalent
to having it always return @code{0.0}.
On most machines, it is not necessary to define this macro.
@end defmac
@node Values in Registers
@subsection How Values Fit in Registers
@ -2814,6 +2826,19 @@ as below:
@end smallexample
@end defmac
@defmac IRA_COVER_CLASSES
The macro defines cover classes for the Integrated Register Allocator
(@acronym{IRA}). Cover classes are a set of non-intersecting register
classes covering all hard registers used for register allocation
purposes. Any move between two registers in the same cover class
should be cheaper than load or store of the registers. The macro
value should be the initializer for an array of register class values,
with @code{LIM_REG_CLASSES} used as the end marker.
You must define this macro in order to use the integrated register
allocator for the target.
@end defmac
@node Old Constraints
@section Obsolete Macros for Defining Constraints
@cindex defining constraints, obsolete method

View File

@ -205,6 +205,19 @@ extern int flag_debug_asm;
extern int flag_next_runtime;
extern int flag_dump_rtl_in_asm;
/* The algorithm used for the integrated register allocator (IRA). */
enum ira_algorithm
{
IRA_ALGORITHM_REGIONAL,
IRA_ALGORITHM_CB,
IRA_ALGORITHM_MIXED
};
extern enum ira_algorithm flag_ira_algorithm;
extern unsigned int flag_ira_verbose;
/* Other basic status info about current function. */

View File

@ -188,7 +188,7 @@ compute_regs_asm_clobbered (char *regs_asm_clobbered)
/* All registers that can be eliminated. */
static HARD_REG_SET eliminable_regset;
HARD_REG_SET eliminable_regset;
static int regno_compare (const void *, const void *);
static int allocno_compare (const void *, const void *);
@ -197,7 +197,6 @@ static void prune_preferences (void);
static void set_preferences (void);
static void find_reg (int, HARD_REG_SET, int, int, int);
static void dump_conflicts (FILE *);
static void build_insn_chain (void);
/* Look through the list of eliminable registers. Set ELIM_SET to the
@ -1355,7 +1354,8 @@ mark_elimination (int from, int to)
FOR_EACH_BB (bb)
{
regset r = DF_LIVE_IN (bb);
/* We don't use LIVE info in IRA. */
regset r = (flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb));
if (REGNO_REG_SET_P (r, from))
{
CLEAR_REGNO_REG_SET (r, from);
@ -1385,11 +1385,21 @@ print_insn_chains (FILE *file)
print_insn_chain (file, c);
}
/* Return true if pseudo REGNO should be added to set live_throughout
or dead_or_set of the insn chains for reload consideration. */
static bool
pseudo_for_reload_consideration_p (int regno)
{
/* Consider spilled pseudos too for IRA because they still have a
chance to get hard-registers in the reload when IRA is used. */
return reg_renumber[regno] >= 0 || (flag_ira && optimize);
}
/* Walk the insns of the current function and build reload_insn_chain,
and record register life information. */
static void
void
build_insn_chain (void)
{
unsigned int i;
@ -1412,7 +1422,6 @@ build_insn_chain (void)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (eliminable_regset, i))
bitmap_set_bit (elim_regset, i);
FOR_EACH_BB_REVERSE (bb)
{
bitmap_iterator bi;
@ -1430,7 +1439,7 @@ build_insn_chain (void)
EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), FIRST_PSEUDO_REGISTER, i, bi)
{
if (reg_renumber[i] >= 0)
if (pseudo_for_reload_consideration_p (i))
bitmap_set_bit (live_relevant_regs, i);
}
@ -1467,11 +1476,13 @@ build_insn_chain (void)
if (!fixed_regs[regno])
bitmap_set_bit (&c->dead_or_set, regno);
}
else if (reg_renumber[regno] >= 0)
else if (pseudo_for_reload_consideration_p (regno))
bitmap_set_bit (&c->dead_or_set, regno);
}
if ((regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
if ((regno < FIRST_PSEUDO_REGISTER
|| reg_renumber[regno] >= 0
|| (flag_ira && optimize))
&& (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
{
rtx reg = DF_REF_REG (def);
@ -1567,11 +1578,12 @@ build_insn_chain (void)
if (!fixed_regs[regno])
bitmap_set_bit (&c->dead_or_set, regno);
}
else if (reg_renumber[regno] >= 0)
else if (pseudo_for_reload_consideration_p (regno))
bitmap_set_bit (&c->dead_or_set, regno);
}
if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
if (regno < FIRST_PSEUDO_REGISTER
|| pseudo_for_reload_consideration_p (regno))
{
if (GET_CODE (reg) == SUBREG
&& !DF_REF_FLAGS_IS_SET (use,
@ -1748,6 +1760,13 @@ dump_global_regs (FILE *file)
fprintf (file, "\n\n");
}
static bool
gate_handle_global_alloc (void)
{
return ! flag_ira;
}
/* Run old register allocator. Return TRUE if we must exit
rest_of_compilation upon return. */
static unsigned int
@ -1811,7 +1830,7 @@ struct rtl_opt_pass pass_global_alloc =
{
RTL_PASS,
"greg", /* name */
NULL, /* gate */
gate_handle_global_alloc, /* gate */
rest_of_handle_global_alloc, /* execute */
NULL, /* sub */
NULL, /* next */

View File

@ -538,6 +538,11 @@ extern char global_regs[FIRST_PSEUDO_REGISTER];
extern HARD_REG_SET regs_invalidated_by_call;
/* Call used hard registers which can not be saved because there is no
insn for this. */
extern HARD_REG_SET no_caller_save_reg_set;
#ifdef REG_ALLOC_ORDER
/* Table of register numbers in the order in which to try to use them. */
@ -556,6 +561,10 @@ extern HARD_REG_SET reg_class_contents[N_REG_CLASSES];
extern unsigned int reg_class_size[N_REG_CLASSES];
/* For each reg class, table listing all the classes contained in it. */
extern enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
/* For each pair of reg classes,
a largest reg class contained in their union. */

2449
gcc/ira-build.c Normal file

File diff suppressed because it is too large Load Diff

2955
gcc/ira-color.c Normal file

File diff suppressed because it is too large Load Diff

777
gcc/ira-conflicts.c Normal file
View File

@ -0,0 +1,777 @@
/* IRA conflict builder.
Copyright (C) 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "regs.h"
#include "rtl.h"
#include "tm_p.h"
#include "target.h"
#include "flags.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "insn-config.h"
#include "recog.h"
#include "toplev.h"
#include "params.h"
#include "df.h"
#include "sparseset.h"
#include "ira-int.h"
/* This file contains code responsible for allocno conflict creation,
allocno copy creation and allocno info accumulation on upper level
regions. */
/* ira_allocnos_num array of arrays of bits, recording whether two
allocno's conflict (can't go in the same hardware register).
Some arrays will be used as conflict bit vector of the
corresponding allocnos see function build_allocno_conflicts. */
static IRA_INT_TYPE **conflicts;
/* Macro to test a conflict of A1 and A2 in `conflicts'. */
#define CONFLICT_ALLOCNO_P(A1, A2) \
(ALLOCNO_MIN (A1) <= ALLOCNO_CONFLICT_ID (A2) \
&& ALLOCNO_CONFLICT_ID (A2) <= ALLOCNO_MAX (A1) \
&& TEST_ALLOCNO_SET_BIT (conflicts[ALLOCNO_NUM (A1)], \
ALLOCNO_CONFLICT_ID (A2), \
ALLOCNO_MIN (A1), \
ALLOCNO_MAX (A1)))
/* Build allocno conflict table by processing allocno live ranges. */
static void
build_conflict_bit_table (void)
{
int i, num, id, allocated_words_num, conflict_bit_vec_words_num;
unsigned int j;
enum reg_class cover_class;
ira_allocno_t allocno, live_a;
allocno_live_range_t r;
ira_allocno_iterator ai;
sparseset allocnos_live;
int allocno_set_words;
allocno_set_words = (ira_allocnos_num + IRA_INT_BITS - 1) / IRA_INT_BITS;
allocnos_live = sparseset_alloc (ira_allocnos_num);
conflicts = (IRA_INT_TYPE **) ira_allocate (sizeof (IRA_INT_TYPE *)
* ira_allocnos_num);
allocated_words_num = 0;
FOR_EACH_ALLOCNO (allocno, ai)
{
num = ALLOCNO_NUM (allocno);
if (ALLOCNO_MAX (allocno) < ALLOCNO_MIN (allocno))
{
conflicts[num] = NULL;
continue;
}
conflict_bit_vec_words_num
= ((ALLOCNO_MAX (allocno) - ALLOCNO_MIN (allocno) + IRA_INT_BITS)
/ IRA_INT_BITS);
allocated_words_num += conflict_bit_vec_words_num;
conflicts[num]
= (IRA_INT_TYPE *) ira_allocate (sizeof (IRA_INT_TYPE)
* conflict_bit_vec_words_num);
memset (conflicts[num], 0,
sizeof (IRA_INT_TYPE) * conflict_bit_vec_words_num);
}
if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
fprintf
(ira_dump_file,
"+++Allocating %ld bytes for conflict table (uncompressed size %ld)\n",
(long) allocated_words_num * sizeof (IRA_INT_TYPE),
(long) allocno_set_words * ira_allocnos_num * sizeof (IRA_INT_TYPE));
for (i = 0; i < ira_max_point; i++)
{
for (r = ira_start_point_ranges[i]; r != NULL; r = r->start_next)
{
allocno = r->allocno;
num = ALLOCNO_NUM (allocno);
id = ALLOCNO_CONFLICT_ID (allocno);
cover_class = ALLOCNO_COVER_CLASS (allocno);
sparseset_set_bit (allocnos_live, num);
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, j)
{
live_a = ira_allocnos[j];
if (cover_class == ALLOCNO_COVER_CLASS (live_a)
/* Don't set up conflict for the allocno with itself. */
&& num != (int) j)
{
SET_ALLOCNO_SET_BIT (conflicts[num],
ALLOCNO_CONFLICT_ID (live_a),
ALLOCNO_MIN (allocno),
ALLOCNO_MAX (allocno));
SET_ALLOCNO_SET_BIT (conflicts[j], id,
ALLOCNO_MIN (live_a),
ALLOCNO_MAX (live_a));
}
}
}
for (r = ira_finish_point_ranges[i]; r != NULL; r = r->finish_next)
sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (r->allocno));
}
sparseset_free (allocnos_live);
}
/* Return TRUE if the operand constraint STR is commutative. */
static bool
commutative_constraint_p (const char *str)
{
bool ignore_p;
int c;
for (ignore_p = false;;)
{
c = *str;
if (c == '\0')
break;
str += CONSTRAINT_LEN (c, str);
if (c == '#')
ignore_p = true;
else if (c == ',')
ignore_p = false;
else if (! ignore_p)
{
/* Usually `%' is the first constraint character but the
documentation does not require this. */
if (c == '%')
return true;
}
}
return false;
}
/* Return the number of the operand which should be the same in any
case as operand with number OP_NUM (or negative value if there is
no such operand). If USE_COMMUT_OP_P is TRUE, the function makes
temporarily commutative operand exchange before this. The function
takes only really possible alternatives into consideration. */
static int
get_dup_num (int op_num, bool use_commut_op_p)
{
int curr_alt, c, original, dup;
bool ignore_p, commut_op_used_p;
const char *str;
rtx op;
if (op_num < 0 || recog_data.n_alternatives == 0)
return -1;
op = recog_data.operand[op_num];
ira_assert (REG_P (op));
commut_op_used_p = true;
if (use_commut_op_p)
{
if (commutative_constraint_p (recog_data.constraints[op_num]))
op_num++;
else if (op_num > 0 && commutative_constraint_p (recog_data.constraints
[op_num - 1]))
op_num--;
else
commut_op_used_p = false;
}
str = recog_data.constraints[op_num];
for (ignore_p = false, original = -1, curr_alt = 0;;)
{
c = *str;
if (c == '\0')
break;
if (c == '#')
ignore_p = true;
else if (c == ',')
{
curr_alt++;
ignore_p = false;
}
else if (! ignore_p)
switch (c)
{
case 'X':
return -1;
case 'm':
case 'o':
/* Accept a register which might be placed in memory. */
return -1;
break;
case 'V':
case '<':
case '>':
break;
case 'p':
GO_IF_LEGITIMATE_ADDRESS (VOIDmode, op, win_p);
break;
win_p:
return -1;
case 'g':
return -1;
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':
{
enum reg_class cl;
cl = (c == 'r'
? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, str));
if (cl != NO_REGS)
return -1;
#ifdef EXTRA_CONSTRAINT_STR
else if (EXTRA_CONSTRAINT_STR (op, c, str))
return -1;
#endif
break;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (original != -1 && original != c)
return -1;
original = c;
break;
}
str += CONSTRAINT_LEN (c, str);
}
if (original == -1)
return -1;
dup = original - '0';
if (use_commut_op_p)
{
if (commutative_constraint_p (recog_data.constraints[dup]))
dup++;
else if (dup > 0
&& commutative_constraint_p (recog_data.constraints[dup -1]))
dup--;
else if (! commut_op_used_p)
return -1;
}
return dup;
}
/* Return the operand which should be, in any case, the same as
operand with number OP_NUM. If USE_COMMUT_OP_P is TRUE, the
function makes temporarily commutative operand exchange before
this. */
static rtx
get_dup (int op_num, bool use_commut_op_p)
{
int n = get_dup_num (op_num, use_commut_op_p);
if (n < 0)
return NULL_RTX;
else
return recog_data.operand[n];
}
/* Process registers REG1 and REG2 in move INSN with execution
frequency FREQ. The function also processes the registers in a
potential move insn (INSN == NULL in this case) with frequency
FREQ. The function can modify hard register costs of the
corresponding allocnos or create a copy involving the corresponding
allocnos. The function does nothing if the both registers are hard
registers. When nothing is changed, the function returns
FALSE. */
static bool
process_regs_for_copy (rtx reg1, rtx reg2, rtx insn, int freq)
{
int hard_regno, cost, index;
ira_allocno_t a;
enum reg_class rclass, cover_class;
enum machine_mode mode;
ira_copy_t cp;
gcc_assert (REG_P (reg1) && REG_P (reg2));
if (HARD_REGISTER_P (reg1))
{
if (HARD_REGISTER_P (reg2))
return false;
hard_regno = REGNO (reg1);
a = ira_curr_regno_allocno_map[REGNO (reg2)];
}
else if (HARD_REGISTER_P (reg2))
{
hard_regno = REGNO (reg2);
a = ira_curr_regno_allocno_map[REGNO (reg1)];
}
else if (!CONFLICT_ALLOCNO_P (ira_curr_regno_allocno_map[REGNO (reg1)],
ira_curr_regno_allocno_map[REGNO (reg2)]))
{
cp = ira_add_allocno_copy (ira_curr_regno_allocno_map[REGNO (reg1)],
ira_curr_regno_allocno_map[REGNO (reg2)],
freq, insn, ira_curr_loop_tree_node);
bitmap_set_bit (ira_curr_loop_tree_node->local_copies, cp->num);
return true;
}
else
return false;
rclass = REGNO_REG_CLASS (hard_regno);
mode = ALLOCNO_MODE (a);
cover_class = ALLOCNO_COVER_CLASS (a);
if (! ira_class_subset_p[rclass][cover_class])
return false;
if (reg_class_size[rclass] <= (unsigned) CLASS_MAX_NREGS (rclass, mode))
/* It is already taken into account in ira-costs.c. */
return false;
index = ira_class_hard_reg_index[cover_class][hard_regno];
if (index < 0)
return false;
if (HARD_REGISTER_P (reg1))
cost = ira_register_move_cost[mode][cover_class][rclass] * freq;
else
cost = ira_register_move_cost[mode][rclass][cover_class] * freq;
ira_allocate_and_set_costs
(&ALLOCNO_HARD_REG_COSTS (a), cover_class,
ALLOCNO_COVER_CLASS_COST (a));
ira_allocate_and_set_costs
(&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), cover_class, 0);
ALLOCNO_HARD_REG_COSTS (a)[index] -= cost;
ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[index] -= cost;
return true;
}
/* Process all of the output registers of the current insn and
the input register REG (its operand number OP_NUM) which dies in the
insn as if there were a move insn between them with frequency
FREQ. */
static void
process_reg_shuffles (rtx reg, int op_num, int freq)
{
int i;
rtx another_reg;
gcc_assert (REG_P (reg));
for (i = 0; i < recog_data.n_operands; i++)
{
another_reg = recog_data.operand[i];
if (!REG_P (another_reg) || op_num == i
|| recog_data.operand_type[i] != OP_OUT)
continue;
process_regs_for_copy (reg, another_reg, NULL_RTX, freq);
}
}
/* Process INSN and create allocno copies if necessary. For example,
it might be because INSN is a pseudo-register move or INSN is two
operand insn. */
static void
add_insn_allocno_copies (rtx insn)
{
rtx set, operand, dup;
const char *str;
bool commut_p, bound_p;
int i, j, freq;
freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
if (freq == 0)
freq = 1;
if ((set = single_set (insn)) != NULL_RTX
&& REG_P (SET_DEST (set)) && REG_P (SET_SRC (set))
&& ! side_effects_p (set)
&& find_reg_note (insn, REG_DEAD, SET_SRC (set)) != NULL_RTX)
process_regs_for_copy (SET_DEST (set), SET_SRC (set), insn, freq);
else
{
extract_insn (insn);
for (i = 0; i < recog_data.n_operands; i++)
{
operand = recog_data.operand[i];
if (REG_P (operand)
&& find_reg_note (insn, REG_DEAD, operand) != NULL_RTX)
{
str = recog_data.constraints[i];
while (*str == ' ' && *str == '\t')
str++;
bound_p = false;
for (j = 0, commut_p = false; j < 2; j++, commut_p = true)
if ((dup = get_dup (i, commut_p)) != NULL_RTX
&& REG_P (dup) && GET_MODE (operand) == GET_MODE (dup)
&& process_regs_for_copy (operand, dup, NULL_RTX, freq))
bound_p = true;
if (bound_p)
continue;
/* If an operand dies, prefer its hard register for the
output operands by decreasing the hard register cost
or creating the corresponding allocno copies. The
cost will not correspond to a real move insn cost, so
make the frequency smaller. */
process_reg_shuffles (operand, i, freq < 8 ? 1 : freq / 8);
}
}
}
}
/* Add copies originated from BB given by LOOP_TREE_NODE. */
static void
add_copies (ira_loop_tree_node_t loop_tree_node)
{
basic_block bb;
rtx insn;
bb = loop_tree_node->bb;
if (bb == NULL)
return;
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
add_insn_allocno_copies (insn);
}
/* Propagate copies the corresponding allocnos on upper loop tree
level. */
static void
propagate_copies (void)
{
ira_copy_t cp;
ira_copy_iterator ci;
ira_allocno_t a1, a2, parent_a1, parent_a2;
ira_loop_tree_node_t parent;
FOR_EACH_COPY (cp, ci)
{
a1 = cp->first;
a2 = cp->second;
if (ALLOCNO_LOOP_TREE_NODE (a1) == ira_loop_tree_root)
continue;
ira_assert ((ALLOCNO_LOOP_TREE_NODE (a2) != ira_loop_tree_root));
parent = ALLOCNO_LOOP_TREE_NODE (a1)->parent;
if ((parent_a1 = ALLOCNO_CAP (a1)) == NULL)
parent_a1 = parent->regno_allocno_map[ALLOCNO_REGNO (a1)];
if ((parent_a2 = ALLOCNO_CAP (a2)) == NULL)
parent_a2 = parent->regno_allocno_map[ALLOCNO_REGNO (a2)];
ira_assert (parent_a1 != NULL && parent_a2 != NULL);
if (! CONFLICT_ALLOCNO_P (parent_a1, parent_a2))
ira_add_allocno_copy (parent_a1, parent_a1, cp->freq,
cp->insn, cp->loop_tree_node);
}
}
/* Return TRUE if live ranges of allocnos A1 and A2 intersect. It is
used to find a conflict for new allocnos or allocnos with the
different cover classes. */
bool
ira_allocno_live_ranges_intersect_p (ira_allocno_t a1, ira_allocno_t a2)
{
allocno_live_range_t r1, r2;
if (a1 == a2)
return false;
if (ALLOCNO_REG (a1) != NULL && ALLOCNO_REG (a2) != NULL
&& (ORIGINAL_REGNO (ALLOCNO_REG (a1))
== ORIGINAL_REGNO (ALLOCNO_REG (a2))))
return false;
/* Remember the ranges are always kept ordered. */
for (r1 = ALLOCNO_LIVE_RANGES (a1), r2 = ALLOCNO_LIVE_RANGES (a2);
r1 != NULL && r2 != NULL;)
{
if (r1->start > r2->finish)
r1 = r1->next;
else if (r2->start > r1->finish)
r2 = r2->next;
else
return true;
}
return false;
}
/* Return TRUE if live ranges of pseudo-registers REGNO1 and REGNO2
intersect. This should be used when there is only one region.
Currently this is used during reload. */
bool
ira_pseudo_live_ranges_intersect_p (int regno1, int regno2)
{
ira_allocno_t a1, a2;
ira_assert (regno1 >= FIRST_PSEUDO_REGISTER
&& regno2 >= FIRST_PSEUDO_REGISTER);
/* Reg info caclulated by dataflow infrastructure can be different
from one calculated by regclass. */
if ((a1 = ira_loop_tree_root->regno_allocno_map[regno1]) == NULL
|| (a2 = ira_loop_tree_root->regno_allocno_map[regno2]) == NULL)
return false;
return ira_allocno_live_ranges_intersect_p (a1, a2);
}
/* Array used to collect all conflict allocnos for given allocno. */
static ira_allocno_t *collected_conflict_allocnos;
/* Build conflict vectors or bit conflict vectors (whatever is more
profitable) for allocno A from the conflict table and propagate the
conflicts to upper level allocno. */
static void
build_allocno_conflicts (ira_allocno_t a)
{
int i, px, parent_num;
int conflict_bit_vec_words_num;
ira_loop_tree_node_t parent;
ira_allocno_t parent_a, another_a, another_parent_a;
ira_allocno_t *vec;
IRA_INT_TYPE *allocno_conflicts;
ira_allocno_set_iterator asi;
allocno_conflicts = conflicts[ALLOCNO_NUM (a)];
px = 0;
FOR_EACH_ALLOCNO_IN_SET (allocno_conflicts,
ALLOCNO_MIN (a), ALLOCNO_MAX (a), i, asi)
{
another_a = ira_conflict_id_allocno_map[i];
ira_assert (ALLOCNO_COVER_CLASS (a)
== ALLOCNO_COVER_CLASS (another_a));
collected_conflict_allocnos[px++] = another_a;
}
if (ira_conflict_vector_profitable_p (a, px))
{
ira_allocate_allocno_conflict_vec (a, px);
vec = (ira_allocno_t*) ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a);
memcpy (vec, collected_conflict_allocnos, sizeof (ira_allocno_t) * px);
vec[px] = NULL;
ALLOCNO_CONFLICT_ALLOCNOS_NUM (a) = px;
}
else
{
ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) = conflicts[ALLOCNO_NUM (a)];
if (ALLOCNO_MAX (a) < ALLOCNO_MIN (a))
conflict_bit_vec_words_num = 0;
else
conflict_bit_vec_words_num
= ((ALLOCNO_MAX (a) - ALLOCNO_MIN (a) + IRA_INT_BITS)
/ IRA_INT_BITS);
ALLOCNO_CONFLICT_ALLOCNO_ARRAY_SIZE (a)
= conflict_bit_vec_words_num * sizeof (IRA_INT_TYPE);
}
parent = ALLOCNO_LOOP_TREE_NODE (a)->parent;
if ((parent_a = ALLOCNO_CAP (a)) == NULL
&& (parent == NULL
|| (parent_a = parent->regno_allocno_map[ALLOCNO_REGNO (a)])
== NULL))
return;
ira_assert (parent != NULL);
ira_assert (ALLOCNO_COVER_CLASS (a) == ALLOCNO_COVER_CLASS (parent_a));
parent_num = ALLOCNO_NUM (parent_a);
FOR_EACH_ALLOCNO_IN_SET (allocno_conflicts,
ALLOCNO_MIN (a), ALLOCNO_MAX (a), i, asi)
{
another_a = ira_conflict_id_allocno_map[i];
ira_assert (ALLOCNO_COVER_CLASS (a)
== ALLOCNO_COVER_CLASS (another_a));
if ((another_parent_a = ALLOCNO_CAP (another_a)) == NULL
&& (another_parent_a = (parent->regno_allocno_map
[ALLOCNO_REGNO (another_a)])) == NULL)
continue;
ira_assert (ALLOCNO_NUM (another_parent_a) >= 0);
ira_assert (ALLOCNO_COVER_CLASS (another_a)
== ALLOCNO_COVER_CLASS (another_parent_a));
SET_ALLOCNO_SET_BIT (conflicts[parent_num],
ALLOCNO_CONFLICT_ID (another_parent_a),
ALLOCNO_MIN (parent_a),
ALLOCNO_MAX (parent_a));
}
}
/* Build conflict vectors or bit conflict vectors (whatever is more
profitable) of all allocnos from the conflict table. */
static void
build_conflicts (void)
{
int i;
ira_allocno_t a, cap;
collected_conflict_allocnos
= (ira_allocno_t *) ira_allocate (sizeof (ira_allocno_t)
* ira_allocnos_num);
for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
for (a = ira_regno_allocno_map[i];
a != NULL;
a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
{
build_allocno_conflicts (a);
for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
build_allocno_conflicts (cap);
}
ira_free (collected_conflict_allocnos);
}
/* Print hard reg set SET with TITLE to FILE. */
static void
print_hard_reg_set (FILE *file, const char *title, HARD_REG_SET set)
{
int i, start;
fprintf (file, title);
for (start = -1, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (TEST_HARD_REG_BIT (set, i))
{
if (i == 0 || ! TEST_HARD_REG_BIT (set, i - 1))
start = i;
}
if (start >= 0
&& (i == FIRST_PSEUDO_REGISTER - 1 || ! TEST_HARD_REG_BIT (set, i)))
{
if (start == i - 1)
fprintf (file, " %d", start);
else if (start == i - 2)
fprintf (file, " %d %d", start, start + 1);
else
fprintf (file, " %d-%d", start, i - 1);
start = -1;
}
}
fprintf (file, "\n");
}
/* Print information about allocno or only regno (if REG_P) conflicts
to FILE. */
static void
print_conflicts (FILE *file, bool reg_p)
{
ira_allocno_t a;
ira_allocno_iterator ai;
HARD_REG_SET conflicting_hard_regs;
FOR_EACH_ALLOCNO (a, ai)
{
ira_allocno_t conflict_a;
ira_allocno_conflict_iterator aci;
basic_block bb;
if (reg_p)
fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
else
{
fprintf (file, ";; a%d(r%d,", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
fprintf (file, "b%d", bb->index);
else
fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
fprintf (file, ")");
}
fprintf (file, " conflicts:");
if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) != NULL)
FOR_EACH_ALLOCNO_CONFLICT (a, conflict_a, aci)
{
if (reg_p)
fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
else
{
fprintf (file, " a%d(r%d,", ALLOCNO_NUM (conflict_a),
ALLOCNO_REGNO (conflict_a));
if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
fprintf (file, "b%d)", bb->index);
else
fprintf (file, "l%d)",
ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
}
}
COPY_HARD_REG_SET (conflicting_hard_regs,
ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
AND_HARD_REG_SET (conflicting_hard_regs,
reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
print_hard_reg_set (file, "\n;; total conflict hard regs:",
conflicting_hard_regs);
COPY_HARD_REG_SET (conflicting_hard_regs,
ALLOCNO_CONFLICT_HARD_REGS (a));
AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
AND_HARD_REG_SET (conflicting_hard_regs,
reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
print_hard_reg_set (file, ";; conflict hard regs:",
conflicting_hard_regs);
}
fprintf (file, "\n");
}
/* Print information about allocno or only regno (if REG_P) conflicts
to stderr. */
void
ira_debug_conflicts (bool reg_p)
{
print_conflicts (stderr, reg_p);
}
/* Entry function which builds allocno conflicts and allocno copies
and accumulate some allocno info on upper level regions. */
void
ira_build_conflicts (void)
{
ira_allocno_t a;
ira_allocno_iterator ai;
if (optimize)
{
build_conflict_bit_table ();
build_conflicts ();
ira_traverse_loop_tree (true, ira_loop_tree_root, NULL, add_copies);
/* We need finished conflict table for the subsequent call. */
if (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
|| flag_ira_algorithm == IRA_ALGORITHM_MIXED)
propagate_copies ();
/* Now we can free memory for the conflict table (see function
build_allocno_conflicts for details). */
FOR_EACH_ALLOCNO (a, ai)
{
if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) != conflicts[ALLOCNO_NUM (a)])
ira_free (conflicts[ALLOCNO_NUM (a)]);
}
ira_free (conflicts);
}
FOR_EACH_ALLOCNO (a, ai)
{
if (ALLOCNO_CALLS_CROSSED_NUM (a) == 0)
continue;
if (! flag_caller_saves)
{
IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a),
call_used_reg_set);
if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
call_used_reg_set);
}
else
{
IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a),
no_caller_save_reg_set);
if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
no_caller_save_reg_set);
}
}
if (optimize && internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
print_conflicts (ira_dump_file, false);
}

1594
gcc/ira-costs.c Normal file

File diff suppressed because it is too large Load Diff

1019
gcc/ira-emit.c Normal file

File diff suppressed because it is too large Load Diff

1200
gcc/ira-int.h Normal file

File diff suppressed because it is too large Load Diff

967
gcc/ira-lives.c Normal file
View File

@ -0,0 +1,967 @@
/* IRA processing allocno lives to build allocno live ranges.
Copyright (C) 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "regs.h"
#include "rtl.h"
#include "tm_p.h"
#include "target.h"
#include "flags.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "insn-config.h"
#include "recog.h"
#include "toplev.h"
#include "params.h"
#include "df.h"
#include "sparseset.h"
#include "ira-int.h"
/* The code in this file is similar to one in global but the code
works on the allocno basis and creates live ranges instead of
pseudo-register conflicts. */
/* Program points are enumerated by numbers from range
0..IRA_MAX_POINT-1. There are approximately two times more program
points than insns. Program points are places in the program where
liveness info can be changed. In most general case (there are more
complicated cases too) some program points correspond to places
where input operand dies and other ones correspond to places where
output operands are born. */
int ira_max_point;
/* Arrays of size IRA_MAX_POINT mapping a program point to the allocno
live ranges with given start/finish point. */
allocno_live_range_t *ira_start_point_ranges, *ira_finish_point_ranges;
/* Number of the current program point. */
static int curr_point;
/* Point where register pressure excess started or -1 if there is no
register pressure excess. Excess pressure for a register class at
some point means that there are more allocnos of given register
class living at the point than number of hard-registers of the
class available for the allocation. It is defined only for cover
classes. */
static int high_pressure_start_point[N_REG_CLASSES];
/* Allocnos live at current point in the scan. */
static sparseset allocnos_live;
/* Set of hard regs (except eliminable ones) currently live. */
static HARD_REG_SET hard_regs_live;
/* The loop tree node corresponding to the current basic block. */
static ira_loop_tree_node_t curr_bb_node;
/* The function processing birth of register REGNO. It updates living
hard regs and conflict hard regs for living allocnos or starts a
new live range for the allocno corresponding to REGNO if it is
necessary. */
static void
make_regno_born (int regno)
{
unsigned int i;
ira_allocno_t a;
allocno_live_range_t p;
if (regno < FIRST_PSEUDO_REGISTER)
{
SET_HARD_REG_BIT (hard_regs_live, regno);
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
{
SET_HARD_REG_BIT (ALLOCNO_CONFLICT_HARD_REGS (ira_allocnos[i]),
regno);
SET_HARD_REG_BIT (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (ira_allocnos[i]),
regno);
}
return;
}
a = ira_curr_regno_allocno_map[regno];
if (a == NULL)
return;
if ((p = ALLOCNO_LIVE_RANGES (a)) == NULL
|| (p->finish != curr_point && p->finish + 1 != curr_point))
ALLOCNO_LIVE_RANGES (a)
= ira_create_allocno_live_range (a, curr_point, -1,
ALLOCNO_LIVE_RANGES (a));
}
/* Update ALLOCNO_EXCESS_PRESSURE_POINTS_NUM for allocno A. */
static void
update_allocno_pressure_excess_length (ira_allocno_t a)
{
int start;
enum reg_class cover_class;
allocno_live_range_t p;
cover_class = ALLOCNO_COVER_CLASS (a);
if (high_pressure_start_point[cover_class] < 0)
return;
p = ALLOCNO_LIVE_RANGES (a);
ira_assert (p != NULL);
start = (high_pressure_start_point[cover_class] > p->start
? high_pressure_start_point[cover_class] : p->start);
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) += curr_point - start + 1;
}
/* Process the death of register REGNO. This updates hard_regs_live
or finishes the current live range for the allocno corresponding to
REGNO. */
static void
make_regno_dead (int regno)
{
ira_allocno_t a;
allocno_live_range_t p;
if (regno < FIRST_PSEUDO_REGISTER)
{
CLEAR_HARD_REG_BIT (hard_regs_live, regno);
return;
}
a = ira_curr_regno_allocno_map[regno];
if (a == NULL)
return;
p = ALLOCNO_LIVE_RANGES (a);
ira_assert (p != NULL);
p->finish = curr_point;
update_allocno_pressure_excess_length (a);
}
/* Process the birth and, right after then, death of register
REGNO. */
static void
make_regno_born_and_dead (int regno)
{
make_regno_born (regno);
make_regno_dead (regno);
}
/* The current register pressures for each cover class for the current
basic block. */
static int curr_reg_pressure[N_REG_CLASSES];
/* Mark allocno A as currently living and update current register
pressure, maximal register pressure for the current BB, start point
of the register pressure excess, and conflicting hard registers of
A. */
static void
set_allocno_live (ira_allocno_t a)
{
int nregs;
enum reg_class cover_class;
if (sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
return;
sparseset_set_bit (allocnos_live, ALLOCNO_NUM (a));
IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), hard_regs_live);
IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), hard_regs_live);
cover_class = ALLOCNO_COVER_CLASS (a);
nregs = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)];
curr_reg_pressure[cover_class] += nregs;
if (high_pressure_start_point[cover_class] < 0
&& (curr_reg_pressure[cover_class]
> ira_available_class_regs[cover_class]))
high_pressure_start_point[cover_class] = curr_point;
if (curr_bb_node->reg_pressure[cover_class]
< curr_reg_pressure[cover_class])
curr_bb_node->reg_pressure[cover_class] = curr_reg_pressure[cover_class];
}
/* Mark allocno A as currently not living and update current register
pressure, start point of the register pressure excess, and register
pressure excess length for living allocnos. */
static void
clear_allocno_live (ira_allocno_t a)
{
unsigned int i;
enum reg_class cover_class;
if (sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
{
cover_class = ALLOCNO_COVER_CLASS (a);
curr_reg_pressure[cover_class]
-= ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)];
ira_assert (curr_reg_pressure[cover_class] >= 0);
if (high_pressure_start_point[cover_class] >= 0
&& (curr_reg_pressure[cover_class]
<= ira_available_class_regs[cover_class]))
{
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
{
update_allocno_pressure_excess_length (ira_allocnos[i]);
}
high_pressure_start_point[cover_class] = -1;
}
}
sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (a));
}
/* Record all regs that are set in any one insn. Communication from
mark_reg_{store,clobber}. */
static VEC(rtx, heap) *regs_set;
/* Handle the case where REG is set by the insn being scanned, during
the scan to build live ranges and calculate reg pressure info.
Store a 1 in hard_regs_live or allocnos_live for this register or
the corresponding allocno, record how many consecutive hardware
registers it actually needs.
Note that even if REG does not remain alive after this insn, we
must mark it here as live, to ensure a conflict between REG and any
other reg allocnos set in this insn that really do live. This is
because those other allocnos could be considered after this.
REG might actually be something other than a register; if so, we do
nothing.
SETTER is 0 if this register was modified by an auto-increment
(i.e., a REG_INC note was found for it). */
static void
mark_reg_store (rtx reg, const_rtx setter ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
int regno;
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
if (! REG_P (reg))
return;
VEC_safe_push (rtx, heap, regs_set, reg);
regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER)
{
ira_allocno_t a = ira_curr_regno_allocno_map[regno];
if (a != NULL)
{
if (sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
return;
set_allocno_live (a);
}
make_regno_born (regno);
}
else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
{
int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
enum reg_class cover_class;
while (regno < last)
{
if (! TEST_HARD_REG_BIT (hard_regs_live, regno)
&& ! TEST_HARD_REG_BIT (eliminable_regset, regno))
{
cover_class = ira_class_translate[REGNO_REG_CLASS (regno)];
if (cover_class != NO_REGS)
{
curr_reg_pressure[cover_class]++;
if (high_pressure_start_point[cover_class] < 0
&& (curr_reg_pressure[cover_class]
> ira_available_class_regs[cover_class]))
high_pressure_start_point[cover_class] = curr_point;
}
make_regno_born (regno);
if (cover_class != NO_REGS
&& (curr_bb_node->reg_pressure[cover_class]
< curr_reg_pressure[cover_class]))
curr_bb_node->reg_pressure[cover_class]
= curr_reg_pressure[cover_class];
}
regno++;
}
}
}
/* Like mark_reg_store except notice just CLOBBERs; ignore SETs. */
static void
mark_reg_clobber (rtx reg, const_rtx setter, void *data)
{
if (GET_CODE (setter) == CLOBBER)
mark_reg_store (reg, setter, data);
}
/* Record that hard register REG (if it is a hard register) has
conflicts with all the allocno currently live or the corresponding
allocno lives at just the current program point. Do not mark REG
(or the allocno) itself as live. */
static void
mark_reg_conflicts (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)
make_regno_born_and_dead (regno);
else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
{
int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
while (regno < last)
{
make_regno_born_and_dead (regno);
regno++;
}
}
}
/* Mark REG (or the corresponding allocno) as being dead (following
the insn being scanned now). Store a 0 in hard_regs_live or
allocnos_live for the register. */
static void
mark_reg_death (rtx reg)
{
unsigned int i;
int regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER)
{
ira_allocno_t a = ira_curr_regno_allocno_map[regno];
if (a != NULL)
{
if (! sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
return;
clear_allocno_live (a);
}
make_regno_dead (regno);
}
else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
{
int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
enum reg_class cover_class;
while (regno < last)
{
if (TEST_HARD_REG_BIT (hard_regs_live, regno))
{
cover_class = ira_class_translate[REGNO_REG_CLASS (regno)];
if (cover_class != NO_REGS)
{
curr_reg_pressure[cover_class]--;
if (high_pressure_start_point[cover_class] >= 0
&& (curr_reg_pressure[cover_class]
<= ira_available_class_regs[cover_class]))
{
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
{
update_allocno_pressure_excess_length
(ira_allocnos[i]);
}
high_pressure_start_point[cover_class] = -1;
}
ira_assert (curr_reg_pressure[cover_class] >= 0);
}
make_regno_dead (regno);
}
regno++;
}
}
}
/* Checks that CONSTRAINTS permits to use only one hard register. If
it is so, the function returns the class of the hard register.
Otherwise it returns NO_REGS. */
static enum reg_class
single_reg_class (const char *constraints, rtx op, rtx equiv_const)
{
int ignore_p;
enum reg_class cl, next_cl;
int c;
cl = NO_REGS;
for (ignore_p = false;
(c = *constraints);
constraints += CONSTRAINT_LEN (c, constraints))
if (c == '#')
ignore_p = true;
else if (c == ',')
ignore_p = false;
else if (! ignore_p)
switch (c)
{
case ' ':
case '\t':
case '=':
case '+':
case '*':
case '&':
case '%':
case '!':
case '?':
break;
case 'i':
if (CONSTANT_P (op)
|| (equiv_const != NULL_RTX && CONSTANT_P (equiv_const)))
return NO_REGS;
break;
case 'n':
if (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
|| (equiv_const != NULL_RTX
&& (GET_CODE (equiv_const) == CONST_INT
|| (GET_CODE (equiv_const) == CONST_DOUBLE
&& GET_MODE (equiv_const) == VOIDmode))))
return NO_REGS;
break;
case 's':
if ((CONSTANT_P (op) && GET_CODE (op) != CONST_INT
&& (GET_CODE (op) != CONST_DOUBLE || GET_MODE (op) != VOIDmode))
|| (equiv_const != NULL_RTX
&& CONSTANT_P (equiv_const)
&& GET_CODE (equiv_const) != CONST_INT
&& (GET_CODE (equiv_const) != CONST_DOUBLE
|| GET_MODE (equiv_const) != VOIDmode)))
return NO_REGS;
break;
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
if ((GET_CODE (op) == CONST_INT
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, constraints))
|| (equiv_const != NULL_RTX
&& GET_CODE (equiv_const) == CONST_INT
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (equiv_const),
c, constraints)))
return NO_REGS;
break;
case 'E':
case 'F':
if (GET_CODE (op) == CONST_DOUBLE
|| (GET_CODE (op) == CONST_VECTOR
&& GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT)
|| (equiv_const != NULL_RTX
&& (GET_CODE (equiv_const) == CONST_DOUBLE
|| (GET_CODE (equiv_const) == CONST_VECTOR
&& (GET_MODE_CLASS (GET_MODE (equiv_const))
== MODE_VECTOR_FLOAT)))))
return NO_REGS;
break;
case 'G':
case 'H':
if ((GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, constraints))
|| (equiv_const != NULL_RTX
&& GET_CODE (equiv_const) == CONST_DOUBLE
&& CONST_DOUBLE_OK_FOR_CONSTRAINT_P (equiv_const,
c, constraints)))
return NO_REGS;
/* ??? what about memory */
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':
next_cl = (c == 'r'
? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT (c, constraints));
if ((cl != NO_REGS && next_cl != cl)
|| ira_available_class_regs[next_cl] > 1)
return NO_REGS;
cl = next_cl;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
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)
return NO_REGS;
cl = next_cl;
break;
default:
return NO_REGS;
}
return cl;
}
/* The function checks that operand OP_NUM of the current insn can use
only one hard register. If it is so, the function returns the
class of the hard register. Otherwise it returns NO_REGS. */
static enum reg_class
single_reg_operand_class (int op_num)
{
if (op_num < 0 || recog_data.n_alternatives == 0)
return NO_REGS;
return single_reg_class (recog_data.constraints[op_num],
recog_data.operand[op_num], NULL_RTX);
}
/* 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
with the hard register. */
static void
process_single_reg_class_operands (bool in_p, int freq)
{
int i, regno, cost;
unsigned int px;
enum reg_class cl, cover_class;
rtx operand;
ira_allocno_t operand_a, a;
for (i = 0; i < recog_data.n_operands; i++)
{
operand = recog_data.operand[i];
if (in_p && recog_data.operand_type[i] != OP_IN
&& recog_data.operand_type[i] != OP_INOUT)
continue;
if (! in_p && recog_data.operand_type[i] != OP_OUT
&& recog_data.operand_type[i] != OP_INOUT)
continue;
cl = single_reg_operand_class (i);
if (cl == NO_REGS)
continue;
operand_a = NULL;
if (GET_CODE (operand) == SUBREG)
operand = SUBREG_REG (operand);
if (REG_P (operand)
&& (regno = REGNO (operand)) >= FIRST_PSEUDO_REGISTER)
{
enum machine_mode mode;
enum reg_class cover_class;
operand_a = ira_curr_regno_allocno_map[regno];
mode = ALLOCNO_MODE (operand_a);
cover_class = ALLOCNO_COVER_CLASS (operand_a);
if (ira_class_subset_p[cl][cover_class]
&& ira_class_hard_regs_num[cl] != 0
&& (ira_class_hard_reg_index[cover_class]
[ira_class_hard_regs[cl][0]]) >= 0
&& reg_class_size[cl] <= (unsigned) CLASS_MAX_NREGS (cl, mode))
{
/* ??? FREQ */
cost = freq * (in_p
? ira_register_move_cost[mode][cover_class][cl]
: ira_register_move_cost[mode][cl][cover_class]);
ira_allocate_and_set_costs
(&ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a), cover_class, 0);
ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a)
[ira_class_hard_reg_index
[cover_class][ira_class_hard_regs[cl][0]]]
-= cost;
}
}
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, px)
{
a = ira_allocnos[px];
cover_class = ALLOCNO_COVER_CLASS (a);
if (a != operand_a)
{
/* We could increase costs of A instead of making it
conflicting with the hard register. But it works worse
because it will be spilled in reload in anyway. */
IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
reg_class_contents[cl]);
IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a),
reg_class_contents[cl]);
}
}
}
}
/* Process insns of the basic block given by its LOOP_TREE_NODE to
update allocno live ranges, allocno hard register conflicts,
intersected calls, and register pressure info for allocnos for the
basic block for and regions containing the basic block. */
static void
process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
{
int i;
unsigned int j;
basic_block bb;
rtx insn;
edge e;
edge_iterator ei;
bitmap_iterator bi;
bitmap reg_live_in;
unsigned int px;
bb = loop_tree_node->bb;
if (bb != NULL)
{
for (i = 0; i < ira_reg_class_cover_size; i++)
{
curr_reg_pressure[ira_reg_class_cover[i]] = 0;
high_pressure_start_point[ira_reg_class_cover[i]] = -1;
}
curr_bb_node = loop_tree_node;
reg_live_in = DF_LR_IN (bb);
sparseset_clear (allocnos_live);
REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_in);
AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
AND_COMPL_HARD_REG_SET (hard_regs_live, ira_no_alloc_regs);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (hard_regs_live, i))
{
enum reg_class cover_class;
cover_class = REGNO_REG_CLASS (i);
if (cover_class == NO_REGS)
continue;
cover_class = ira_class_translate[cover_class];
curr_reg_pressure[cover_class]++;
if (curr_bb_node->reg_pressure[cover_class]
< curr_reg_pressure[cover_class])
curr_bb_node->reg_pressure[cover_class]
= curr_reg_pressure[cover_class];
ira_assert (curr_reg_pressure[cover_class]
<= ira_available_class_regs[cover_class]);
}
EXECUTE_IF_SET_IN_BITMAP (reg_live_in, FIRST_PSEUDO_REGISTER, j, bi)
{
ira_allocno_t a = ira_curr_regno_allocno_map[j];
if (a == NULL)
continue;
ira_assert (! sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)));
set_allocno_live (a);
make_regno_born (j);
}
#ifdef EH_RETURN_DATA_REGNO
if (bb_has_eh_pred (bb))
{
for (j = 0; ; ++j)
{
unsigned int regno = EH_RETURN_DATA_REGNO (j);
if (regno == INVALID_REGNUM)
break;
make_regno_born_and_dead (regno);
}
}
#endif
/* Allocnos can't go in stack regs at the start of a basic block
that is reached by an abnormal edge. Likewise for call
clobbered regs, because caller-save, fixup_abnormal_edges and
possibly the table driven EH machinery are not quite ready to
handle such allocnos live across such edges. */
FOR_EACH_EDGE (e, ei, bb->preds)
if (e->flags & EDGE_ABNORMAL)
break;
if (e != NULL)
{
#ifdef STACK_REGS
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, px)
{
ALLOCNO_NO_STACK_REG_P (ira_allocnos[px]) = true;
ALLOCNO_TOTAL_NO_STACK_REG_P (ira_allocnos[px]) = true;
}
for (px = FIRST_STACK_REG; px <= LAST_STACK_REG; px++)
make_regno_born_and_dead (px);
#endif
/* No need to record conflicts for call clobbered regs if we
have nonlocal labels around, as we don't ever try to
allocate such regs in this case. */
if (!cfun->has_nonlocal_label)
for (px = 0; px < FIRST_PSEUDO_REGISTER; px++)
if (call_used_regs[px])
make_regno_born_and_dead (px);
}
/* Scan the code of this basic block, noting which allocnos and
hard regs are born or die. */
FOR_BB_INSNS (bb, insn)
{
rtx link;
int freq;
if (! INSN_P (insn))
continue;
freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
if (freq == 0)
freq = 1;
if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
fprintf (ira_dump_file, " Insn %u(l%d): point = %d\n",
INSN_UID (insn), loop_tree_node->parent->loop->num,
curr_point);
/* Check regs_set is an empty set. */
gcc_assert (VEC_empty (rtx, regs_set));
/* Mark any allocnos clobbered by INSN as live, so they
conflict with the inputs. */
note_stores (PATTERN (insn), mark_reg_clobber, NULL);
extract_insn (insn);
process_single_reg_class_operands (true, freq);
/* Mark any allocnos dead after INSN as dead now. */
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD)
mark_reg_death (XEXP (link, 0));
curr_point++;
if (CALL_P (insn))
{
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
{
ira_allocno_t a = ira_allocnos[i];
ALLOCNO_CALL_FREQ (a) += freq;
ALLOCNO_CALLS_CROSSED_NUM (a)++;
/* Don't allocate allocnos that cross calls, if this
function receives a nonlocal goto. */
if (cfun->has_nonlocal_label)
{
SET_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a));
SET_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
}
}
}
/* Mark any allocnos set in INSN as live. Clobbers are
processed again, so they will conflict with the reg
allocnos that are set. */
note_stores (PATTERN (insn), mark_reg_store, NULL);
#ifdef AUTO_INC_DEC
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC)
mark_reg_store (XEXP (link, 0), NULL_RTX, NULL);
#endif
/* If INSN has multiple outputs, then any allocno that dies
here and is used inside of an output must conflict with
the other outputs.
It is unsafe to use !single_set here since it will ignore
an unused output. Just because an output is unused does
not mean the compiler can assume the side effect will not
occur. Consider if ALLOCNO appears in the address of an
output and we reload the output. If we allocate ALLOCNO
to the same hard register as an unused output we could
set the hard register before the output reload insn. */
if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD)
{
int i;
int used_in_output = 0;
rtx reg = XEXP (link, 0);
for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
{
rtx set = XVECEXP (PATTERN (insn), 0, i);
if (GET_CODE (set) == SET
&& ! REG_P (SET_DEST (set))
&& ! rtx_equal_p (reg, SET_DEST (set))
&& reg_overlap_mentioned_p (reg, SET_DEST (set)))
used_in_output = 1;
}
if (used_in_output)
mark_reg_conflicts (reg);
}
process_single_reg_class_operands (false, freq);
/* Mark any allocnos set in INSN and then never used. */
while (! VEC_empty (rtx, regs_set))
{
rtx reg = VEC_pop (rtx, regs_set);
rtx note = find_regno_note (insn, REG_UNUSED, REGNO (reg));
if (note)
mark_reg_death (XEXP (note, 0));
}
curr_point++;
}
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
{
make_regno_dead (ALLOCNO_REGNO (ira_allocnos[i]));
}
curr_point++;
}
/* Propagate register pressure to upper loop tree nodes: */
if (loop_tree_node != ira_loop_tree_root)
for (i = 0; i < ira_reg_class_cover_size; i++)
{
enum reg_class cover_class;
cover_class = ira_reg_class_cover[i];
if (loop_tree_node->reg_pressure[cover_class]
> loop_tree_node->parent->reg_pressure[cover_class])
loop_tree_node->parent->reg_pressure[cover_class]
= loop_tree_node->reg_pressure[cover_class];
}
}
/* Create and set up IRA_START_POINT_RANGES and
IRA_FINISH_POINT_RANGES. */
static void
create_start_finish_chains (void)
{
ira_allocno_t a;
ira_allocno_iterator ai;
allocno_live_range_t r;
ira_start_point_ranges
= (allocno_live_range_t *) ira_allocate (ira_max_point
* sizeof (allocno_live_range_t));
memset (ira_start_point_ranges, 0,
ira_max_point * sizeof (allocno_live_range_t));
ira_finish_point_ranges
= (allocno_live_range_t *) ira_allocate (ira_max_point
* sizeof (allocno_live_range_t));
memset (ira_finish_point_ranges, 0,
ira_max_point * sizeof (allocno_live_range_t));
FOR_EACH_ALLOCNO (a, ai)
{
for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
{
r->start_next = ira_start_point_ranges[r->start];
ira_start_point_ranges[r->start] = r;
r->finish_next = ira_finish_point_ranges[r->finish];
ira_finish_point_ranges[r->finish] = r;
}
}
}
/* Rebuild IRA_START_POINT_RANGES and IRA_FINISH_POINT_RANGES after
new live ranges and program points were added as a result if new
insn generation. */
void
ira_rebuild_start_finish_chains (void)
{
ira_free (ira_finish_point_ranges);
ira_free (ira_start_point_ranges);
create_start_finish_chains ();
}
/* Print live ranges R to file F. */
void
ira_print_live_range_list (FILE *f, allocno_live_range_t r)
{
for (; r != NULL; r = r->next)
fprintf (f, " [%d..%d]", r->start, r->finish);
fprintf (f, "\n");
}
/* Print live ranges R to stderr. */
void
ira_debug_live_range_list (allocno_live_range_t r)
{
ira_print_live_range_list (stderr, r);
}
/* Print live ranges of allocno A to file F. */
static void
print_allocno_live_ranges (FILE *f, ira_allocno_t a)
{
fprintf (f, " a%d(r%d):", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
ira_print_live_range_list (f, ALLOCNO_LIVE_RANGES (a));
}
/* Print live ranges of allocno A to stderr. */
void
ira_debug_allocno_live_ranges (ira_allocno_t a)
{
print_allocno_live_ranges (stderr, a);
}
/* Print live ranges of all allocnos to file F. */
static void
print_live_ranges (FILE *f)
{
ira_allocno_t a;
ira_allocno_iterator ai;
FOR_EACH_ALLOCNO (a, ai)
print_allocno_live_ranges (f, a);
}
/* Print live ranges of all allocnos to stderr. */
void
ira_debug_live_ranges (void)
{
print_live_ranges (stderr);
}
/* The main entry function creates live ranges, set up
CONFLICT_HARD_REGS and TOTAL_CONFLICT_HARD_REGS for allocnos, and
calculate register pressure info. */
void
ira_create_allocno_live_ranges (void)
{
allocnos_live = sparseset_alloc (ira_allocnos_num);
/* Make a vector that mark_reg_{store,clobber} will store in. */
if (!regs_set)
regs_set = VEC_alloc (rtx, heap, 10);
curr_point = 0;
ira_traverse_loop_tree (true, ira_loop_tree_root, NULL,
process_bb_node_lives);
ira_max_point = curr_point;
create_start_finish_chains ();
if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
print_live_ranges (ira_dump_file);
/* Clean up. */
sparseset_free (allocnos_live);
}
/* Free arrays IRA_START_POINT_RANGES and IRA_FINISH_POINT_RANGES. */
void
ira_finish_allocno_live_ranges (void)
{
ira_free (ira_finish_point_ranges);
ira_free (ira_start_point_ranges);
}

2064
gcc/ira.c Normal file

File diff suppressed because it is too large Load Diff

37
gcc/ira.h Normal file
View File

@ -0,0 +1,37 @@
/* Communication between the Integrated Register Allocator (IRA) and
the rest of the compiler.
Copyright (C) 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
extern void ira_init_once (void);
extern void ira_init (void);
extern void ira_finish_once (void);
extern rtx ira_eliminate_regs (rtx, enum machine_mode);
extern void ira_sort_insn_chain (bool);
extern void ira_sort_regnos_for_alter_reg (int *, int, unsigned int *);
extern void ira_mark_allocation_change (int);
extern void ira_mark_memory_move_deletion (int, int);
extern bool ira_reassign_pseudos (int *, int, HARD_REG_SET, HARD_REG_SET *,
HARD_REG_SET *, bitmap);
extern rtx ira_reuse_stack_slot (int, unsigned int, unsigned int);
extern void ira_mark_new_stack_slot (rtx, int, unsigned int);
extern bool ira_better_spill_reload_regno_p (int *, int *, rtx, rtx, rtx);

View File

@ -298,7 +298,6 @@ static int equiv_init_movable_p (rtx, int);
static int contains_replace_regs (rtx);
static int memref_referenced_p (rtx, rtx);
static int memref_used_between_p (rtx, rtx, rtx);
static void update_equiv_regs (void);
static void no_equiv (rtx, const_rtx, void *);
static void block_alloc (int);
static int qty_sugg_compare (int, int);
@ -795,9 +794,11 @@ memref_used_between_p (rtx memref, rtx start, rtx end)
into the using insn. If it succeeds, we can eliminate the register
completely.
Initialize the REG_EQUIV_INIT array of initializing insns. */
Initialize the REG_EQUIV_INIT array of initializing insns.
static void
Return non-zero if jump label rebuilding should be done. */
int
update_equiv_regs (void)
{
rtx insn;
@ -1183,6 +1184,8 @@ update_equiv_regs (void)
new_insn = emit_insn_before (PATTERN (equiv_insn), insn);
REG_NOTES (new_insn) = REG_NOTES (equiv_insn);
REG_NOTES (equiv_insn) = 0;
/* Rescan it to process the notes. */
df_insn_rescan (new_insn);
/* Make sure this insn is recognized before
reload begins, otherwise
@ -1227,6 +1230,7 @@ update_equiv_regs (void)
end_alias_analysis ();
free (reg_equiv);
return recorded_label_ref;
}
/* Mark REG as having no known equivalence.
@ -2442,6 +2446,12 @@ find_stack_regs (void)
}
#endif
static bool
gate_handle_local_alloc (void)
{
return ! flag_ira;
}
/* Run old register allocator. Return TRUE if we must exit
rest_of_compilation upon return. */
static unsigned int
@ -2517,7 +2527,7 @@ struct rtl_opt_pass pass_local_alloc =
{
RTL_PASS,
"lreg", /* name */
NULL, /* gate */
gate_handle_local_alloc, /* gate */
rest_of_handle_local_alloc, /* execute */
NULL, /* sub */
NULL, /* next */

View File

@ -878,6 +878,11 @@ decode_options (unsigned int argc, const char **argv)
flag_section_anchors = 0;
}
#ifdef IRA_COVER_CLASSES
/* Use IRA if it is implemented for the target. */
flag_ira = 1;
#endif
/* Originally we just set the variables if a particular optimization level,
but with the advent of being able to change the optimization level for a
function, we need to reset optimizations. */
@ -1119,6 +1124,14 @@ decode_options (unsigned int argc, const char **argv)
flag_reorder_blocks = 1;
}
#ifndef IRA_COVER_CLASSES
if (flag_ira)
{
inform ("-fira does not work on this architecture");
flag_ira = 0;
}
#endif
/* Save the current optimization options if this is the first call. */
if (first_time_p)
{
@ -1970,6 +1983,21 @@ common_handle_option (size_t scode, const char *arg, int value,
warning (0, "unknown tls-model \"%s\"", arg);
break;
case OPT_fira_algorithm_:
if (!strcmp (arg, "regional"))
flag_ira_algorithm = IRA_ALGORITHM_REGIONAL;
else if (!strcmp (arg, "CB"))
flag_ira_algorithm = IRA_ALGORITHM_CB;
else if (!strcmp (arg, "mixed"))
flag_ira_algorithm = IRA_ALGORITHM_MIXED;
else
warning (0, "unknown ira algorithm \"%s\"", arg);
break;
case OPT_fira_verbose_:
flag_ira_verbose = value;
break;
case OPT_ftracer:
flag_tracer_set = true;
break;

View File

@ -714,6 +714,11 @@ DEFPARAM (PARAM_DF_DOUBLE_QUEUE_THRESHOLD_FACTOR,
"Multiplier used for determining the double-queueing threshold",
2, 0, 0)
DEFPARAM (PARAM_IRA_MAX_LOOPS_NUM,
"ira-max-loops-num",
"max loops number for regional RA",
50, 0, 0)
/* Switch initialization conversion will refuse to create arrays that are
bigger than this parameter times the number of switch branches. */

View File

@ -167,6 +167,8 @@ typedef enum compiler_param
PARAM_VALUE (PARAM_L2_CACHE_SIZE)
#define USE_CANONICAL_TYPES \
PARAM_VALUE (PARAM_USE_CANONICAL_TYPES)
#define IRA_MAX_LOOPS_NUM \
PARAM_VALUE (PARAM_IRA_MAX_LOOPS_NUM)
#define SWITCH_CONVERSION_BRANCH_RATIO \
PARAM_VALUE (PARAM_SWITCH_CONVERSION_BRANCH_RATIO)
#endif /* ! GCC_PARAMS_H */

View File

@ -767,6 +767,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_subregs_of_mode_init);
NEXT_PASS (pass_local_alloc);
NEXT_PASS (pass_global_alloc);
NEXT_PASS (pass_ira);
NEXT_PASS (pass_subregs_of_mode_finish);
NEXT_PASS (pass_postreload);
{

View File

@ -1565,7 +1565,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
static bool
gate_handle_postreload (void)
{
return (optimize > 0);
return (optimize > 0 && reload_completed);
}

View File

@ -178,7 +178,7 @@ static enum reg_class reg_class_superclasses[N_REG_CLASSES][N_REG_CLASSES];
/* For each reg class, table listing all the classes contained in it. */
static enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
/* For each pair of reg classes,
a largest reg class contained in their union. */
@ -211,24 +211,22 @@ bool have_regs_of_mode [MAX_MACHINE_MODE];
/* 1 if class does contain register of given mode. */
static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
typedef unsigned short move_table[N_REG_CLASSES];
char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
/* Maximum cost of moving from a register in one class to a register in
another class. Based on REGISTER_MOVE_COST. */
static move_table *move_cost[MAX_MACHINE_MODE];
move_table *move_cost[MAX_MACHINE_MODE];
/* Similar, but here we don't have to move if the first index is a subset
of the second so in that case the cost is zero. */
static move_table *may_move_in_cost[MAX_MACHINE_MODE];
move_table *may_move_in_cost[MAX_MACHINE_MODE];
/* Similar, but here we don't have to move if the first index is a superset
of the second so in that case the cost is zero. */
static move_table *may_move_out_cost[MAX_MACHINE_MODE];
move_table *may_move_out_cost[MAX_MACHINE_MODE];
/* Keep track of the last mode we initialized move costs for. */
static int last_mode_for_init_move_cost;
@ -313,7 +311,7 @@ init_reg_sets (void)
/* Initialize may_move_cost and friends for mode M. */
static void
void
init_move_cost (enum machine_mode m)
{
static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
@ -1024,6 +1022,7 @@ reg_preferred_class (int regno)
{
if (reg_pref == 0)
return GENERAL_REGS;
return (enum reg_class) reg_pref[regno].prefclass;
}
@ -2283,6 +2282,32 @@ auto_inc_dec_reg_p (rtx reg, enum machine_mode mode)
}
#endif
/* Allocate space for reg info. */
void
allocate_reg_info (void)
{
int 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));
}
/* Resize reg info. The new elements will be uninitialized. */
void
resize_reg_info (void)
{
int 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);
}
/* Free up the space allocated by allocate_reg_info. */
void
free_reg_info (void)
@ -2300,6 +2325,21 @@ free_reg_info (void)
}
}
/* Set up preferred and alternate classes for REGNO as PREFCLASS and
ALTCLASS. */
void
setup_reg_classes (int regno,
enum reg_class prefclass, enum reg_class altclass)
{
if (reg_pref == NULL)
return;
reg_pref[regno].prefclass = prefclass;
reg_pref[regno].altclass = altclass;
}
/* This is the `regscan' pass of the compiler, run just before cse and
again just before loop. It finds the first and last use of each

View File

@ -1117,7 +1117,8 @@ regmove_optimize (rtx f, int nregs)
for (pass = 0; pass <= 2; pass++)
{
if (! flag_regmove && pass >= flag_expensive_optimizations)
/* We need fewer optimizations for IRA. */
if ((! flag_regmove || flag_ira) && pass >= flag_expensive_optimizations)
goto done;
if (dump_file)
@ -1165,7 +1166,9 @@ regmove_optimize (rtx f, int nregs)
}
}
}
if (! flag_regmove)
/* All optimizations important for IRA have been done. */
if (! flag_regmove || flag_ira)
continue;
if (! find_matches (insn, &match))

View File

@ -262,9 +262,27 @@ extern int caller_save_needed;
#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) 0
#endif
/* 1 if the corresponding class does contain register of given
mode. */
extern char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
typedef unsigned short move_table[N_REG_CLASSES];
/* Maximum cost of moving from a register in one class to a register
in another class. */
extern move_table *move_cost[MAX_MACHINE_MODE];
/* Specify number of hard registers given machine mode occupy. */
extern unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
/* Similar, but here we don't have to move if the first index is a
subset of the second so in that case the cost is zero. */
extern move_table *may_move_in_cost[MAX_MACHINE_MODE];
/* Similar, but here we don't have to move if the first index is a
superset of the second so in that case the cost is zero. */
extern move_table *may_move_out_cost[MAX_MACHINE_MODE];
/* Return an exclusive upper bound on the registers occupied by hard
register (reg:MODE REGNO). */

View File

@ -1549,8 +1549,10 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
&& reg_mentioned_p (XEXP (note, 0), in)
/* Check that a former pseudo is valid; see find_dummy_reload. */
&& (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
|| (!bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
ORIGINAL_REGNO (XEXP (note, 0)))
|| (! bitmap_bit_p (flag_ira
? DF_LR_OUT (ENTRY_BLOCK_PTR)
: DF_LIVE_OUT (ENTRY_BLOCK_PTR),
ORIGINAL_REGNO (XEXP (note, 0)))
&& hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1))
&& ! refers_to_regno_for_reload_p (regno,
end_hard_regno (rel_mode,
@ -2027,7 +2029,9 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
can ignore the conflict). We must never introduce writes
to such hardregs, as they would clobber the other live
pseudo. See PR 20973. */
|| (!bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
|| (!bitmap_bit_p (flag_ira
? DF_LR_OUT (ENTRY_BLOCK_PTR)
: DF_LIVE_OUT (ENTRY_BLOCK_PTR),
ORIGINAL_REGNO (in))
/* Similarly, only do this if we can be sure that the death
note is still valid. global can assign some hardreg to

View File

@ -1,6 +1,6 @@
/* Communication between reload.c and reload1.c.
Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1997, 1998,
1999, 2000, 2001, 2003, 2004, 2007 Free Software Foundation, Inc.
/* Communication between reload.c, reload1.c and the rest of compiler.
Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999,
2000, 2001, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
This file is part of GCC.
@ -209,8 +209,9 @@ struct insn_chain
int block;
/* The rtx of the insn. */
rtx insn;
/* Register life information: record all live hard registers, and all
live pseudos that have a hard register. */
/* Register life information: record all live hard registers, and
all live pseudos that have a hard register. This set also
contains pseudos spilled by IRA. */
regset_head live_throughout;
regset_head dead_or_set;

View File

@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h"
#include "except.h"
#include "tree.h"
#include "ira.h"
#include "df.h"
#include "target.h"
#include "dse.h"
@ -257,6 +258,9 @@ static unsigned int spill_stack_slot_width[FIRST_PSEUDO_REGISTER];
/* Record which pseudos needed to be spilled. */
static regset_head spilled_pseudos;
/* Record which pseudos changed their allocation in finish_spills. */
static regset_head changed_allocation_pseudos;
/* Used for communication between order_regs_for_reload and count_pseudo.
Used to avoid counting one pseudo twice. */
static regset_head pseudos_counted;
@ -389,7 +393,7 @@ static void delete_caller_save_insns (void);
static void spill_failure (rtx, enum reg_class);
static void count_spilled_pseudo (int, int, int);
static void delete_dead_insn (rtx);
static void alter_reg (int, int);
static void alter_reg (int, int, bool);
static void set_label_offsets (rtx, rtx, int);
static void check_eliminable_occurrences (rtx);
static void elimination_effects (rtx, enum machine_mode);
@ -443,6 +447,8 @@ static rtx inc_for_reload (rtx, rtx, rtx, int);
static void add_auto_inc_notes (rtx, rtx);
#endif
static void copy_eh_notes (rtx, rtx);
static void substitute (rtx *, const_rtx, rtx);
static bool gen_reload_chain_without_interm_reg_p (int, int);
static int reloads_conflict (int, int);
static rtx gen_reload (rtx, rtx, int, enum reload_type);
static rtx emit_insn_if_valid_for_reload (rtx);
@ -501,6 +507,7 @@ init_reload (void)
reload_startobj = XOBNEWVAR (&reload_obstack, char, 0);
INIT_REG_SET (&spilled_pseudos);
INIT_REG_SET (&changed_allocation_pseudos);
INIT_REG_SET (&pseudos_counted);
}
@ -546,11 +553,11 @@ compute_use_by_pseudos (HARD_REG_SET *to, regset from)
if (r < 0)
{
/* reload_combine uses the information from
DF_LIVE_IN (BASIC_BLOCK), which might still
contain registers that have not actually been allocated
since they have an equivalence. */
gcc_assert (reload_completed);
/* reload_combine uses the information from DF_LIVE_IN,
which might still contain registers that have not
actually been allocated since they have an
equivalence. */
gcc_assert ((flag_ira && optimize) || reload_completed);
}
else
add_to_hard_reg_set (to, PSEUDO_REGNO_MODE (regno), r);
@ -684,6 +691,9 @@ static int something_needs_operands_changed;
/* Nonzero means we couldn't get enough spill regs. */
static int failure;
/* Temporary array of pseudo-register number. */
static int *temp_pseudo_reg_arr;
/* Main entry point for the reload pass.
FIRST is the first insn of the function being compiled.
@ -700,7 +710,7 @@ static int failure;
int
reload (rtx first, int global)
{
int i;
int i, n;
rtx insn;
struct elim_table *ep;
basic_block bb;
@ -883,12 +893,21 @@ reload (rtx first, int global)
offsets_known_at = XNEWVEC (char, num_labels);
offsets_at = (HOST_WIDE_INT (*)[NUM_ELIMINABLE_REGS]) xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT));
/* Alter each pseudo-reg rtx to contain its hard reg number.
Assign stack slots to the pseudos that lack hard regs or equivalents.
/* Alter each pseudo-reg rtx to contain its hard reg number. Assign
stack slots to the pseudos that lack hard regs or equivalents.
Do not touch virtual registers. */
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
alter_reg (i, -1);
temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1);
for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
temp_pseudo_reg_arr[n++] = i;
if (flag_ira && optimize)
/* Ask IRA to order pseudo-registers for better stack slot
sharing. */
ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_width);
for (i = 0; i < n; i++)
alter_reg (temp_pseudo_reg_arr[i], -1, false);
/* If we have some registers we think can be eliminated, scan all insns to
see if there is an insn that sets one of these registers to something
@ -1002,7 +1021,7 @@ reload (rtx first, int global)
the loop. */
reg_equiv_memory_loc[i] = 0;
reg_equiv_init[i] = 0;
alter_reg (i, -1);
alter_reg (i, -1, true);
}
}
@ -1036,7 +1055,12 @@ reload (rtx first, int global)
calculate_needs_all_insns (global);
CLEAR_REG_SET (&spilled_pseudos);
if (! flag_ira || ! optimize)
/* Don't do it for IRA. We need this info because we don't
change live_throughout and dead_or_set for chains when IRA
is used. */
CLEAR_REG_SET (&spilled_pseudos);
did_spill = 0;
something_changed = 0;
@ -1094,6 +1118,11 @@ reload (rtx first, int global)
obstack_free (&reload_obstack, reload_firstobj);
}
if (flag_ira && optimize)
/* Restore the original insn chain order for correct reload work
(e.g. for correct inheritance). */
ira_sort_insn_chain (false);
/* If global-alloc was run, notify it of any register eliminations we have
done. */
if (global)
@ -1163,6 +1192,7 @@ reload (rtx first, int global)
regs. */
failed:
CLEAR_REG_SET (&changed_allocation_pseudos);
CLEAR_REG_SET (&spilled_pseudos);
reload_in_progress = 0;
@ -1333,6 +1363,8 @@ reload (rtx first, int global)
VEC_free (rtx, gc, reg_equiv_memory_loc_vec);
reg_equiv_memory_loc = 0;
free (temp_pseudo_reg_arr);
if (offsets_known_at)
free (offsets_known_at);
if (offsets_at)
@ -1573,10 +1605,24 @@ calculate_needs_all_insns (int global)
{
rtx set = single_set (insn);
if (set
&& SET_SRC (set) == SET_DEST (set)
&& REG_P (SET_SRC (set))
&& REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
&&
((SET_SRC (set) == SET_DEST (set)
&& REG_P (SET_SRC (set))
&& REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
|| (REG_P (SET_SRC (set)) && REG_P (SET_DEST (set))
&& reg_renumber[REGNO (SET_SRC (set))] < 0
&& reg_renumber[REGNO (SET_DEST (set))] < 0
&& reg_equiv_memory_loc[REGNO (SET_SRC (set))] != NULL
&& reg_equiv_memory_loc[REGNO (SET_DEST (set))] != NULL
&& rtx_equal_p (reg_equiv_memory_loc
[REGNO (SET_SRC (set))],
reg_equiv_memory_loc
[REGNO (SET_DEST (set))]))))
{
if (flag_ira && optimize)
/* Inform IRA about the insn deletion. */
ira_mark_memory_move_deletion (REGNO (SET_DEST (set)),
REGNO (SET_SRC (set)));
delete_insn (insn);
/* Delete it from the reload chain. */
if (chain->prev)
@ -1665,6 +1711,10 @@ static int spill_cost[FIRST_PSEUDO_REGISTER];
only the first hard reg for a multi-reg pseudo. */
static int spill_add_cost[FIRST_PSEUDO_REGISTER];
/* Map of hard regno to pseudo regno currently occupying the hard
reg. */
static int hard_regno_to_pseudo_regno[FIRST_PSEUDO_REGISTER];
/* Update the spill cost arrays, considering that pseudo REG is live. */
static void
@ -1675,7 +1725,10 @@ count_pseudo (int reg)
int nregs;
if (REGNO_REG_SET_P (&pseudos_counted, reg)
|| REGNO_REG_SET_P (&spilled_pseudos, reg))
|| REGNO_REG_SET_P (&spilled_pseudos, reg)
/* Ignore spilled pseudo-registers which can be here only if IRA
is used. */
|| (flag_ira && optimize && r < 0))
return;
SET_REGNO_REG_SET (&pseudos_counted, reg);
@ -1683,10 +1736,12 @@ count_pseudo (int reg)
gcc_assert (r >= 0);
spill_add_cost[r] += freq;
nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
while (nregs-- > 0)
spill_cost[r + nregs] += freq;
{
hard_regno_to_pseudo_regno[r + nregs] = reg;
spill_cost[r + nregs] += freq;
}
}
/* Calculate the SPILL_COST and SPILL_ADD_COST arrays and determine the
@ -1704,6 +1759,8 @@ order_regs_for_reload (struct insn_chain *chain)
memset (spill_cost, 0, sizeof spill_cost);
memset (spill_add_cost, 0, sizeof spill_add_cost);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
hard_regno_to_pseudo_regno[i] = -1;
/* Count number of uses of each hard reg by pseudo regs allocated to it
and then order them by decreasing use. First exclude hard registers
@ -1746,18 +1803,25 @@ static HARD_REG_SET used_spill_regs_local;
static void
count_spilled_pseudo (int spilled, int spilled_nregs, int reg)
{
int freq = REG_FREQ (reg);
int r = reg_renumber[reg];
int nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
if (REGNO_REG_SET_P (&spilled_pseudos, reg)
/* Ignore spilled pseudo-registers which can be here only if IRA is
used. */
if ((flag_ira && optimize && r < 0)
|| REGNO_REG_SET_P (&spilled_pseudos, reg)
|| spilled + spilled_nregs <= r || r + nregs <= spilled)
return;
SET_REGNO_REG_SET (&spilled_pseudos, reg);
spill_add_cost[r] -= REG_FREQ (reg);
spill_add_cost[r] -= freq;
while (nregs-- > 0)
spill_cost[r + nregs] -= REG_FREQ (reg);
{
hard_regno_to_pseudo_regno[r + nregs] = -1;
spill_cost[r + nregs] -= freq;
}
}
/* Find reload register to use for reload number ORDER. */
@ -1769,11 +1833,13 @@ find_reg (struct insn_chain *chain, int order)
struct reload *rl = rld + rnum;
int best_cost = INT_MAX;
int best_reg = -1;
unsigned int i, j;
unsigned int i, j, n;
int k;
HARD_REG_SET not_usable;
HARD_REG_SET used_by_other_reload;
reg_set_iterator rsi;
static int regno_pseudo_regs[FIRST_PSEUDO_REGISTER];
static int best_regno_pseudo_regs[FIRST_PSEUDO_REGISTER];
COPY_HARD_REG_SET (not_usable, bad_spill_regs);
IOR_HARD_REG_SET (not_usable, bad_spill_regs_global);
@ -1791,7 +1857,11 @@ find_reg (struct insn_chain *chain, int order)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
#ifdef REG_ALLOC_ORDER
unsigned int regno = reg_alloc_order[i];
#else
unsigned int regno = i;
#endif
if (! TEST_HARD_REG_BIT (not_usable, regno)
&& ! TEST_HARD_REG_BIT (used_by_other_reload, regno)
@ -1810,6 +1880,38 @@ find_reg (struct insn_chain *chain, int order)
}
if (! ok)
continue;
if (flag_ira && optimize)
{
/* Ask IRA to find a better pseudo-register for
spilling. */
for (n = j = 0; j < this_nregs; j++)
{
int r = hard_regno_to_pseudo_regno[regno + j];
if (r < 0)
continue;
if (n == 0 || regno_pseudo_regs[n - 1] != r)
regno_pseudo_regs[n++] = r;
}
regno_pseudo_regs[n++] = -1;
if (best_reg < 0
|| ira_better_spill_reload_regno_p (regno_pseudo_regs,
best_regno_pseudo_regs,
rl->in, rl->out,
chain->insn))
{
best_reg = regno;
for (j = 0;; j++)
{
best_regno_pseudo_regs[j] = regno_pseudo_regs[j];
if (regno_pseudo_regs[j] < 0)
break;
}
}
continue;
}
if (rl->in && REG_P (rl->in) && REGNO (rl->in) == regno)
this_cost--;
if (rl->out && REG_P (rl->out) && REGNO (rl->out) == regno)
@ -1857,6 +1959,7 @@ find_reg (struct insn_chain *chain, int order)
{
gcc_assert (spill_cost[best_reg + i] == 0);
gcc_assert (spill_add_cost[best_reg + i] == 0);
gcc_assert (hard_regno_to_pseudo_regno[best_reg + i] == -1);
SET_HARD_REG_BIT (used_spill_regs_local, best_reg + i);
}
return 1;
@ -2026,7 +2129,7 @@ delete_dead_insn (rtx insn)
can share one stack slot. */
static void
alter_reg (int i, int from_reg)
alter_reg (int i, int from_reg, bool dont_share_p)
{
/* When outputting an inline function, this can happen
for a reg that isn't actually used. */
@ -2059,7 +2162,15 @@ alter_reg (int i, int from_reg)
unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]);
unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT;
int adjust = 0;
bool shared_p = false;
if (flag_ira && optimize)
/* Mark the spill for IRA. */
SET_REGNO_REG_SET (&spilled_pseudos, i);
x = (dont_share_p || ! flag_ira || ! optimize
? NULL_RTX : ira_reuse_stack_slot (i, inherent_size, total_size));
if (x)
shared_p = true;
/* Each pseudo reg has an inherent size which comes from its own mode,
and a total size which provides room for paradoxical subregs
which refer to the pseudo reg in wider modes.
@ -2068,7 +2179,7 @@ alter_reg (int i, int from_reg)
enough inherent space and enough total space.
Otherwise, we allocate a new slot, making sure that it has no less
inherent space, and no less total space, then the previous slot. */
if (from_reg == -1)
else if (from_reg == -1 || (! dont_share_p && flag_ira && optimize))
{
alias_set_type alias_set = new_alias_set ();
@ -2086,6 +2197,10 @@ alter_reg (int i, int from_reg)
/* Nothing can alias this slot except this pseudo. */
set_mem_alias_set (x, alias_set);
dse_record_singleton_alias_set (alias_set, mode);
if (! dont_share_p && flag_ira && optimize)
/* Inform IRA about allocation a new stack slot. */
ira_mark_new_stack_slot (x, i, total_size);
}
/* Reuse a stack slot if possible. */
@ -2164,8 +2279,13 @@ alter_reg (int i, int from_reg)
/* If we have a decl for the original register, set it for the
memory. If this is a shared MEM, make a copy. */
if (REG_EXPR (regno_reg_rtx[i])
&& DECL_P (REG_EXPR (regno_reg_rtx[i])))
if (shared_p)
{
x = copy_rtx (x);
set_mem_attrs_from_reg (x, regno_reg_rtx[i]);
}
else if (REG_EXPR (regno_reg_rtx[i])
&& DECL_P (REG_EXPR (regno_reg_rtx[i])))
{
rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i]));
@ -2441,7 +2561,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
/* There exists at least one use of REGNO that cannot be
eliminated. Prevent the defining insn from being deleted. */
reg_equiv_init[regno] = NULL_RTX;
alter_reg (regno, -1);
alter_reg (regno, -1, true);
}
return x;
@ -3817,18 +3937,22 @@ finish_spills (int global)
spill_reg_order[i] = -1;
EXECUTE_IF_SET_IN_REG_SET (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, rsi)
{
/* Record the current hard register the pseudo is allocated to in
pseudo_previous_regs so we avoid reallocating it to the same
hard reg in a later pass. */
gcc_assert (reg_renumber[i] >= 0);
SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
/* Mark it as no longer having a hard register home. */
reg_renumber[i] = -1;
/* We will need to scan everything again. */
something_changed = 1;
}
if (! flag_ira || ! optimize || reg_renumber[i] >= 0)
{
/* Record the current hard register the pseudo is allocated to
in pseudo_previous_regs so we avoid reallocating it to the
same hard reg in a later pass. */
gcc_assert (reg_renumber[i] >= 0);
SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
/* Mark it as no longer having a hard register home. */
reg_renumber[i] = -1;
if (flag_ira && optimize)
/* Inform IRA about the change. */
ira_mark_allocation_change (i);
/* We will need to scan everything again. */
something_changed = 1;
}
/* Retry global register allocation if possible. */
if (global)
@ -3853,24 +3977,50 @@ finish_spills (int global)
}
}
/* Retry allocating the spilled pseudos. For each reg, merge the
various reg sets that indicate which hard regs can't be used,
and call retry_global_alloc.
We change spill_pseudos here to only contain pseudos that did not
get a new hard register. */
for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
if (reg_old_renumber[i] != reg_renumber[i])
{
HARD_REG_SET forbidden;
COPY_HARD_REG_SET (forbidden, bad_spill_regs_global);
IOR_HARD_REG_SET (forbidden, pseudo_forbidden_regs[i]);
IOR_HARD_REG_SET (forbidden, pseudo_previous_regs[i]);
retry_global_alloc (i, forbidden);
if (reg_renumber[i] >= 0)
CLEAR_REGNO_REG_SET (&spilled_pseudos, i);
}
}
if (! flag_ira || ! optimize)
{
/* Retry allocating the spilled pseudos. For each reg,
merge the various reg sets that indicate which hard regs
can't be used, and call retry_global_alloc. We change
spill_pseudos here to only contain pseudos that did not
get a new hard register. */
for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
if (reg_old_renumber[i] != reg_renumber[i])
{
HARD_REG_SET forbidden;
COPY_HARD_REG_SET (forbidden, bad_spill_regs_global);
IOR_HARD_REG_SET (forbidden, pseudo_forbidden_regs[i]);
IOR_HARD_REG_SET (forbidden, pseudo_previous_regs[i]);
retry_global_alloc (i, forbidden);
if (reg_renumber[i] >= 0)
CLEAR_REGNO_REG_SET (&spilled_pseudos, i);
}
}
else
{
/* Retry allocating the pseudos spilled in IRA and the
reload. For each reg, merge the various reg sets that
indicate which hard regs can't be used, and call
ira_reassign_pseudos. */
unsigned int n;
for (n = 0, i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++)
if (reg_old_renumber[i] != reg_renumber[i])
{
if (reg_renumber[i] < 0)
temp_pseudo_reg_arr[n++] = i;
else
CLEAR_REGNO_REG_SET (&spilled_pseudos, i);
}
if (ira_reassign_pseudos (temp_pseudo_reg_arr, n,
bad_spill_regs_global,
pseudo_forbidden_regs, pseudo_previous_regs,
&spilled_pseudos))
something_changed = 1;
}
}
/* Fix up the register information in the insn chain.
This involves deleting those of the spilled pseudos which did not get
a new hard register home from the live_{before,after} sets. */
@ -3879,9 +4029,14 @@ finish_spills (int global)
HARD_REG_SET used_by_pseudos;
HARD_REG_SET used_by_pseudos2;
AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos);
AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos);
if (! flag_ira || ! optimize)
{
/* Don't do it for IRA because IRA and the reload still can
assign hard registers to the spilled pseudos on next
reload iterations. */
AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos);
AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos);
}
/* Mark any unallocated hard regs as available for spills. That
makes inheritance work somewhat better. */
if (chain->need_reload)
@ -3890,20 +4045,18 @@ finish_spills (int global)
REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
/* Save the old value for the sanity test below. */
COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout);
compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set);
/* Value of chain->used_spill_regs from previous iteration
may be not included in the value calculated here because
of possible removing caller-saves insns (see function
delete_caller_save_insns. */
COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
/* Make sure we only enlarge the set. */
gcc_assert (hard_reg_set_subset_p (used_by_pseudos2,
chain->used_spill_regs));
}
}
CLEAR_REG_SET (&changed_allocation_pseudos);
/* Let alter_reg modify the reg rtx's for the modified pseudos. */
for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
{
@ -3911,7 +4064,9 @@ finish_spills (int global)
if (reg_old_renumber[i] == regno)
continue;
alter_reg (i, reg_old_renumber[i]);
SET_REGNO_REG_SET (&changed_allocation_pseudos, i);
alter_reg (i, reg_old_renumber[i], false);
reg_old_renumber[i] = regno;
if (dump_file)
{
@ -4295,8 +4450,8 @@ reload_as_needed (int live_known)
be partially clobbered by the call. */
else if (CALL_P (insn))
{
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
}
}
@ -4967,6 +5122,126 @@ reloads_unique_chain_p (int r1, int r2)
return true;
}
/* The recursive function change all occurrences of WHAT in *WHERE
onto REPL. */
static void
substitute (rtx *where, const_rtx what, rtx repl)
{
const char *fmt;
int i;
enum rtx_code code;
if (*where == 0)
return;
if (*where == what || rtx_equal_p (*where, what))
{
*where = repl;
return;
}
code = GET_CODE (*where);
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
int j;
for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
substitute (&XVECEXP (*where, i, j), what, repl);
}
else if (fmt[i] == 'e')
substitute (&XEXP (*where, i), what, repl);
}
}
/* The function returns TRUE if chain of reload R1 and R2 (in any
order) can be evaluated without usage of intermediate register for
the reload containing another reload. It is important to see
gen_reload to understand what the function is trying to do. As an
example, let us have reload chain
r2: const
r1: <something> + const
and reload R2 got reload reg HR. The function returns true if
there is a correct insn HR = HR + <something>. Otherwise,
gen_reload will use intermediate register (and this is the reload
reg for R1) to reload <something>.
We need this function to find a conflict for chain reloads. In our
example, if HR = HR + <something> is incorrect insn, then we cannot
use HR as a reload register for R2. If we do use it then we get a
wrong code:
HR = const
HR = <something>
HR = HR + HR
*/
static bool
gen_reload_chain_without_interm_reg_p (int r1, int r2)
{
bool result;
int regno, n, code;
rtx out, in, tem, insn;
rtx last = get_last_insn ();
/* Make r2 a component of r1. */
if (reg_mentioned_p (rld[r1].in, rld[r2].in))
{
n = r1;
r1 = r2;
r2 = n;
}
gcc_assert (reg_mentioned_p (rld[r2].in, rld[r1].in));
regno = rld[r1].regno >= 0 ? rld[r1].regno : rld[r2].regno;
gcc_assert (regno >= 0);
out = gen_rtx_REG (rld[r1].mode, regno);
in = copy_rtx (rld[r1].in);
substitute (&in, rld[r2].in, gen_rtx_REG (rld[r2].mode, regno));
/* If IN is a paradoxical SUBREG, remove it and try to put the
opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */
if (GET_CODE (in) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (in))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
&& (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
in = SUBREG_REG (in), out = tem;
if (GET_CODE (in) == PLUS
&& (REG_P (XEXP (in, 0))
|| GET_CODE (XEXP (in, 0)) == SUBREG
|| MEM_P (XEXP (in, 0)))
&& (REG_P (XEXP (in, 1))
|| GET_CODE (XEXP (in, 1)) == SUBREG
|| CONSTANT_P (XEXP (in, 1))
|| MEM_P (XEXP (in, 1))))
{
insn = emit_insn (gen_rtx_SET (VOIDmode, out, in));
code = recog_memoized (insn);
result = false;
if (code >= 0)
{
extract_insn (insn);
/* We want constrain operands to treat this insn strictly in
its validity determination, i.e., the way it would after
reload has completed. */
result = constrain_operands (1);
}
delete_insns_since (last);
return result;
}
/* It looks like other cases in gen_reload are not possible for
chain reloads or do need an intermediate hard registers. */
return true;
}
/* Return 1 if the reloads denoted by R1 and R2 cannot share a register.
Return 0 otherwise.
@ -5016,7 +5291,8 @@ reloads_conflict (int r1, int r2)
case RELOAD_FOR_OPERAND_ADDRESS:
return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
|| (r2_type == RELOAD_FOR_OPERAND_ADDRESS
&& !reloads_unique_chain_p (r1, r2)));
&& (!reloads_unique_chain_p (r1, r2)
|| !gen_reload_chain_without_interm_reg_p (r1, r2))));
case RELOAD_FOR_OPADDR_ADDR:
return (r2_type == RELOAD_FOR_INPUT
@ -6724,7 +7000,10 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
&& REG_N_SETS (REGNO (old)) == 1)
{
reg_renumber[REGNO (old)] = REGNO (reloadreg);
alter_reg (REGNO (old), -1);
if (flag_ira && optimize)
/* Inform IRA about the change. */
ira_mark_allocation_change (REGNO (old));
alter_reg (REGNO (old), -1, false);
}
special = 1;
}
@ -8161,7 +8440,7 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg)
n_occurrences += count_occurrences (PATTERN (insn),
eliminate_regs (substed, 0,
NULL_RTX), 0);
for (i1 = reg_equiv_alt_mem_list [REGNO (reg)]; i1; i1 = XEXP (i1, 1))
for (i1 = reg_equiv_alt_mem_list[REGNO (reg)]; i1; i1 = XEXP (i1, 1))
{
gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed));
n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0);
@ -8262,7 +8541,10 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg)
/* For the debugging info, say the pseudo lives in this reload reg. */
reg_renumber[REGNO (reg)] = REGNO (new_reload_reg);
alter_reg (REGNO (reg), -1);
if (flag_ira && optimize)
/* Inform IRA about the change. */
ira_mark_allocation_change (REGNO (reg));
alter_reg (REGNO (reg), -1, false);
}
else
{

View File

@ -1805,6 +1805,12 @@ rtx remove_list_elem (rtx, rtx *);
/* regclass.c */
/* 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);
/* Free up register info memory. */
extern void free_reg_info (void);
@ -1815,6 +1821,7 @@ 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 void split_all_insns (void);
extern unsigned int split_all_insns_noflow (void);
@ -2183,12 +2190,16 @@ extern bool can_copy_p (enum machine_mode);
extern rtx fis_get_condition (rtx);
/* In global.c */
#ifdef HARD_CONST
extern HARD_REG_SET eliminable_regset;
#endif
extern void mark_elimination (int, int);
extern void dump_global_regs (FILE *);
#ifdef HARD_CONST
/* Yes, this ifdef is silly, but HARD_REG_SET is not always defined. */
extern void retry_global_alloc (int, HARD_REG_SET);
#endif
extern void build_insn_chain (void);
/* In regclass.c */
extern int reg_classes_intersect_p (enum reg_class, enum reg_class);
@ -2214,6 +2225,7 @@ extern void dbr_schedule (rtx);
/* In local-alloc.c */
extern void dump_local_alloc (FILE *);
extern int update_equiv_regs (void);
/* In reload1.c */
extern int function_invariant_p (const_rtx);

View File

@ -0,0 +1,28 @@
/* { dg-do compile { target "sh-*-*" } } */
/* { dg-options "-O0 -m4 -ml -fira" } */
/* { dg-final { scan-assembler-not "add\tr0,r0" } } */
/* This test checks that chain reloads conflict. I they don't
conflict, the same hard register R0 is used for the both reloads
but in this case the second reload needs an intermediate register
(which is the reload register). As the result we have the
following code
mov #4,r0 -- first reload
mov r14,r0 -- second reload
add r0,r0 -- second reload
The right code should be
mov #4,r0 -- first reload
mov r14,r1 -- second reload
add r0,r1 -- second reload
*/
_Complex float foo_float ();
void bar_float ()
{
__real foo_float ();
}

View File

@ -179,6 +179,8 @@ DEFTIMEVAR (TV_SMS , "sms modulo scheduling")
DEFTIMEVAR (TV_SCHED , "scheduling")
DEFTIMEVAR (TV_LOCAL_ALLOC , "local alloc")
DEFTIMEVAR (TV_GLOBAL_ALLOC , "global alloc")
DEFTIMEVAR (TV_IRA , "integrated RA")
DEFTIMEVAR (TV_RELOAD , "reload")
DEFTIMEVAR (TV_RELOAD_CSE_REGS , "reload CSE regs")
DEFTIMEVAR (TV_SEQABSTR , "sequence abstraction")
DEFTIMEVAR (TV_GCSE_AFTER_RELOAD , "load CSE after reload")

View File

@ -66,6 +66,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "params.h"
#include "reload.h"
#include "ira.h"
#include "dwarf2asm.h"
#include "integrate.h"
#include "real.h"
@ -270,6 +271,14 @@ int flag_next_runtime = 0;
enum tls_model flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
/* Set the default algorithm for the integrated register allocator. */
enum ira_algorithm flag_ira_algorithm = IRA_ALGORITHM_MIXED;
/* Set the default value for -fira-verbose. */
unsigned int flag_ira_verbose = 5;
/* Nonzero means change certain warnings into errors.
Usually these are warnings about failure to conform to some standard. */
@ -2009,6 +2018,7 @@ backend_init (void)
save_register_info ();
/* Initialize the target-specific back end pieces. */
ira_init_once ();
backend_init_target ();
}
@ -2029,9 +2039,10 @@ lang_dependent_init_target (void)
/* Do the target-specific parts of expr initialization. */
init_expr_target ();
/* Although the actions of init_set_costs are language-independent,
it uses optabs, so we cannot call it from backend_init. */
/* Although the actions of these functions are language-independent,
they use optabs, so we cannot call them from backend_init. */
init_set_costs ();
ira_init ();
expand_dummy_function_end ();
}
@ -2132,6 +2143,8 @@ finalize (void)
statistics_fini ();
finish_optimization_passes ();
ira_finish_once ();
if (mem_report)
dump_memory_report (true);

View File

@ -139,6 +139,11 @@ extern int flag_unroll_all_loops;
extern int flag_unswitch_loops;
extern int flag_cprop_registers;
extern int time_report;
extern int flag_ira;
extern int flag_ira_coalesce;
extern int flag_ira_move_spills;
extern int flag_ira_share_save_slots;
extern int flag_ira_share_spill_slots;
/* Things to do with target switches. */
extern void print_version (FILE *, const char *);

View File

@ -469,6 +469,7 @@ extern struct rtl_opt_pass pass_sms;
extern struct rtl_opt_pass pass_sched;
extern struct rtl_opt_pass pass_local_alloc;
extern struct rtl_opt_pass pass_global_alloc;
extern struct rtl_opt_pass pass_ira;
extern struct rtl_opt_pass pass_postreload;
extern struct rtl_opt_pass pass_clean_state;
extern struct rtl_opt_pass pass_branch_prob;