diff options
author | amylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-30 23:55:46 +0000 |
---|---|---|
committer | amylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-30 23:55:46 +0000 |
commit | ad76158801a55764958612aa6114fe4b6e9cae14 (patch) | |
tree | 5c9f15cee17124d1c53762cc0c992f3ca37b151b /gcc/reload1.c | |
parent | 02c15cf3eeed878ff26307a175aef11b6feb183d (diff) | |
download | gcc-ad76158801a55764958612aa6114fe4b6e9cae14.tar.gz |
gcc:
PR other/58545
* reload1.c (update_eliminables_and_spill): New function, broken
out of reload.
(reload): Use it. Check for frame size change after frame
size alignment, and call update_eliminables_and_spill first
if continue-ing.
gcc/testsuite:
PR other/58545
* gcc.target/avr/pr58545.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204234 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r-- | gcc/reload1.c | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/gcc/reload1.c b/gcc/reload1.c index b62b047b070..204685da316 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -373,6 +373,7 @@ static void init_eliminable_invariants (rtx, bool); static void init_elim_table (void); static void free_reg_equiv (void); static void update_eliminables (HARD_REG_SET *); +static bool update_eliminables_and_spill (void); static void elimination_costs_in_insn (rtx); static void spill_hard_reg (unsigned int, int); static int finish_spills (int); @@ -913,9 +914,6 @@ reload (rtx first, int global) if (caller_save_needed) setup_save_areas (); - /* If we allocated another stack slot, redo elimination bookkeeping. */ - if (something_was_spilled || starting_frame_size != get_frame_size ()) - continue; if (starting_frame_size && crtl->stack_alignment_needed) { /* If we have a stack frame, we must align it now. The @@ -927,8 +925,12 @@ reload (rtx first, int global) STARTING_FRAME_OFFSET not be already aligned to STACK_BOUNDARY. */ assign_stack_local (BLKmode, 0, crtl->stack_alignment_needed); - if (starting_frame_size != get_frame_size ()) - continue; + } + /* If we allocated another stack slot, redo elimination bookkeeping. */ + if (something_was_spilled || starting_frame_size != get_frame_size ()) + { + update_eliminables_and_spill (); + continue; } if (caller_save_needed) @@ -962,30 +964,11 @@ reload (rtx first, int global) else if (!verify_initial_elim_offsets ()) something_changed = 1; - { - HARD_REG_SET to_spill; - CLEAR_HARD_REG_SET (to_spill); - update_eliminables (&to_spill); - AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill); - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (TEST_HARD_REG_BIT (to_spill, i)) - { - spill_hard_reg (i, 1); - did_spill = 1; - - /* Regardless of the state of spills, if we previously had - a register that we thought we could eliminate, but now can - not eliminate, we must run another pass. - - Consider pseudos which have an entry in reg_equiv_* which - reference an eliminable register. We must make another pass - to update reg_equiv_* so that we do not substitute in the - old value from when we thought the elimination could be - performed. */ - something_changed = 1; - } - } + if (update_eliminables_and_spill ()) + { + did_spill = 1; + something_changed = 1; + } select_reload_regs (); if (failure) @@ -4031,6 +4014,38 @@ update_eliminables (HARD_REG_SET *pset) SET_HARD_REG_BIT (*pset, HARD_FRAME_POINTER_REGNUM); } +/* Call update_eliminables an spill any registers we can't eliminate anymore. + Return true iff a register was spilled. */ + +static bool +update_eliminables_and_spill (void) +{ + int i; + bool did_spill = false; + HARD_REG_SET to_spill; + CLEAR_HARD_REG_SET (to_spill); + update_eliminables (&to_spill); + AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (TEST_HARD_REG_BIT (to_spill, i)) + { + spill_hard_reg (i, 1); + did_spill = true; + + /* Regardless of the state of spills, if we previously had + a register that we thought we could eliminate, but now can + not eliminate, we must run another pass. + + Consider pseudos which have an entry in reg_equiv_* which + reference an eliminable register. We must make another pass + to update reg_equiv_* so that we do not substitute in the + old value from when we thought the elimination could be + performed. */ + } + return did_spill; +} + /* Return true if X is used as the target register of an elimination. */ bool |