diff options
author | Nathan Froyd <froydnj@codesourcery.com> | 2007-06-05 19:46:23 +0000 |
---|---|---|
committer | Nathan Froyd <froydnj@gcc.gnu.org> | 2007-06-05 19:46:23 +0000 |
commit | 52ff33d0eb56df70238a99b7aa66140609f3abc3 (patch) | |
tree | ddb2aff474d2b21b69f98462040e6897f8ebc7ce | |
parent | b08f991d9127706927d639bb51173e4474b976df (diff) | |
download | gcc-52ff33d0eb56df70238a99b7aa66140609f3abc3.zip gcc-52ff33d0eb56df70238a99b7aa66140609f3abc3.tar.gz gcc-52ff33d0eb56df70238a99b7aa66140609f3abc3.tar.bz2 |
rs6000.h (FIXED_SCRATCH): Use r0 as a scratch register on SPE targets.
* config/rs6000/rs6000.h (FIXED_SCRATCH): Use r0 as a scratch
register on SPE targets. Change documentation to reflect
reality.
* config/rs6000/rs6000.c (rs6000_conditional_register_usage):
Change FIXED_SCRATCH to 14 and document why we're keeping r14
out of the register allocation pool.
(rs6000_reg_live_or_pic_offset_p): New function.
(rs6000_emit_prologue): Move the actual saving of LR up to free
r0 for holding r11. Split saving of SPE 64-bit registers into
its own case. Ensure that offsets will always be in-range for
'evstdd' by using r11 as a scratch register to point at the start
of the SPE save area. Save r11 if necessary, as it is the static
chain register.
(rs6000_emit_epilogue): Split restoring of SPE 64-bit registers
into its own case. Ensure that offsets will always be in-range
for 'evldd' by using r11 as a scratch register to point at the
start of the SPE save area. Also adjust r11 when restoring
the stack pointer to compensate for pre-loading r11.
From-SVN: r125340
-rw-r--r-- | gcc/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 272 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 16 |
3 files changed, 207 insertions, 102 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f43122a..bf664a8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2007-06-06 Nathan Froyd <froydnj@codesourcery.com> + + * config/rs6000/rs6000.h (FIXED_SCRATCH): Use r0 as a scratch + register on SPE targets. Change documentation to reflect + reality. + * config/rs6000/rs6000.c (rs6000_conditional_register_usage): + Change FIXED_SCRATCH to 14 and document why we're keeping r14 + out of the register allocation pool. + (rs6000_reg_live_or_pic_offset_p): New function. + (rs6000_emit_prologue): Move the actual saving of LR up to free + r0 for holding r11. Split saving of SPE 64-bit registers into + its own case. Ensure that offsets will always be in-range for + 'evstdd' by using r11 as a scratch register to point at the start + of the SPE save area. Save r11 if necessary, as it is the static + chain register. + (rs6000_emit_epilogue): Split restoring of SPE 64-bit registers + into its own case. Ensure that offsets will always be in-range + for 'evldd' by using r11 as a scratch register to point at the + start of the SPE save area. Also adjust r11 when restoring + the stack pointer to compensate for pre-loading r11. + 2007-06-05 Thomas Neumann <tneumann@users.sourceforge.net> * cfg.c (init_flow): Use type safe memory macros. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index f7d76ea..67b7c86 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -648,6 +648,7 @@ static void rs6000_eliminate_indexed_memrefs (rtx operands[2]); static const char *rs6000_mangle_fundamental_type (tree); extern const struct attribute_spec rs6000_attribute_table[]; static void rs6000_set_default_type_attributes (tree); +static bool rs6000_reg_live_or_pic_offset_p (int); static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT); static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT); static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, @@ -3991,9 +3992,15 @@ rs6000_conditional_register_usage (void) if (TARGET_SPE) { global_regs[SPEFSCR_REGNO] = 1; - fixed_regs[FIXED_SCRATCH] - = call_used_regs[FIXED_SCRATCH] - = call_really_used_regs[FIXED_SCRATCH] = 1; + /* We used to use r14 as FIXED_SCRATCH to address SPE 64-bit + registers in prologues and epilogues. We no longer use r14 + for FIXED_SCRATCH, but we're keeping r14 out of the allocation + pool for link-compatibility with older versions of GCC. Once + "old" code has died out, we can return r14 to the allocation + pool. */ + fixed_regs[14] + = call_used_regs[14] + = call_really_used_regs[14] = 1; } if (! TARGET_ALTIVEC) @@ -14629,6 +14636,20 @@ no_global_regs_above (int first_greg) #define TARGET_FIX_AND_CONTINUE 0 #endif +/* Determine whether the gp REG is really used. */ + +static bool +rs6000_reg_live_or_pic_offset_p (int reg) +{ + return ((regs_ever_live[reg] + && (!call_used_regs[reg] + || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM + && TARGET_TOC && TARGET_MINIMAL_TOC))) + || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM + && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0) + || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))); +} + /* Emit function prologue as insns. */ void @@ -14815,9 +14836,22 @@ rs6000_emit_prologue (void) /* If we use the link register, get it into r0. */ if (!WORLD_SAVE_P (info) && info->lr_save_p) { + rtx addr, reg, mem; + insn = emit_move_insn (gen_rtx_REG (Pmode, 0), gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)); RTX_FRAME_RELATED_P (insn) = 1; + + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->lr_save_offset + sp_offset)); + reg = gen_rtx_REG (Pmode, 0); + mem = gen_rtx_MEM (Pmode, addr); + /* This should not be of rs6000_sr_alias_set, because of + __builtin_return_address. */ + + insn = emit_move_insn (mem, reg); + rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, + NULL_RTX, NULL_RTX); } /* If we need to save CR, put it into r12. */ @@ -14910,59 +14944,99 @@ rs6000_emit_prologue (void) rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); } + else if (!WORLD_SAVE_P (info) + && TARGET_SPE_ABI + && info->spe_64bit_regs_used != 0 + && info->first_gp_reg_save != 32) + { + int i; + rtx spe_save_area_ptr; + int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE + && regs_ever_live[STATIC_CHAIN_REGNUM] + && !call_used_regs[STATIC_CHAIN_REGNUM]); + + /* Determine whether we can address all of the registers that need + to be saved with an offset from the stack pointer that fits in + the small const field for SPE memory instructions. */ + int spe_regs_addressable_via_sp + = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset + + (32 - info->first_gp_reg_save - 1) * reg_size); + int spe_offset; + + if (spe_regs_addressable_via_sp) + { + spe_save_area_ptr = sp_reg_rtx; + spe_offset = info->spe_gp_save_offset + sp_offset; + } + else + { + /* Make r11 point to the start of the SPE save area. We need + to be careful here if r11 is holding the static chain. If + it is, then temporarily save it in r0. We would use r0 as + our base register here, but using r0 as a base register in + loads and stores means something different from what we + would like. */ + if (using_static_chain_p) + { + rtx r0 = gen_rtx_REG (Pmode, 0); + + gcc_assert (info->first_gp_reg_save > 11); + + emit_move_insn (r0, gen_rtx_REG (Pmode, 11)); + } + + spe_save_area_ptr = gen_rtx_REG (Pmode, 11); + emit_insn (gen_addsi3 (spe_save_area_ptr, sp_reg_rtx, + GEN_INT (info->spe_gp_save_offset + sp_offset))); + + spe_offset = 0; + } + + for (i = 0; i < 32 - info->first_gp_reg_save; i++) + if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) + { + rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); + rtx offset, addr, mem; + + /* We're doing all this to ensure that the offset fits into + the immediate offset of 'evstdd'. */ + gcc_assert (SPE_CONST_OFFSET_OK (reg_size * i + spe_offset)); + + offset = GEN_INT (reg_size * i + spe_offset); + addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset); + mem = gen_rtx_MEM (V2SImode, addr); + + insn = emit_move_insn (mem, reg); + + rs6000_frame_related (insn, spe_save_area_ptr, + info->spe_gp_save_offset + + sp_offset + reg_size * i, + offset, const0_rtx); + } + + /* Move the static chain pointer back. */ + if (using_static_chain_p && !spe_regs_addressable_via_sp) + emit_move_insn (gen_rtx_REG (Pmode, 11), gen_rtx_REG (Pmode, 0)); + } else if (!WORLD_SAVE_P (info)) { int i; for (i = 0; i < 32 - info->first_gp_reg_save; i++) - if ((regs_ever_live[info->first_gp_reg_save + i] - && (!call_used_regs[info->first_gp_reg_save + i] - || (i + info->first_gp_reg_save - == RS6000_PIC_OFFSET_TABLE_REGNUM - && TARGET_TOC && TARGET_MINIMAL_TOC))) - || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM - && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0) - || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))) - { - rtx addr, reg, mem; - reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); + if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) + { + rtx addr, reg, mem; + reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); - if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0) - { - int offset = info->spe_gp_save_offset + sp_offset + 8 * i; - rtx b; + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->gp_save_offset + + sp_offset + + reg_size * i)); + mem = gen_frame_mem (reg_mode, addr); - if (!SPE_CONST_OFFSET_OK (offset)) - { - b = gen_rtx_REG (Pmode, FIXED_SCRATCH); - emit_move_insn (b, GEN_INT (offset)); - } - else - b = GEN_INT (offset); - - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b); - mem = gen_frame_mem (V2SImode, addr); - insn = emit_move_insn (mem, reg); - - if (GET_CODE (b) == CONST_INT) - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - NULL_RTX, NULL_RTX); - else - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - b, GEN_INT (offset)); - } - else - { - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->gp_save_offset - + sp_offset - + reg_size * i)); - mem = gen_frame_mem (reg_mode, addr); - - insn = emit_move_insn (mem, reg); - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - NULL_RTX, NULL_RTX); - } - } + insn = emit_move_insn (mem, reg); + rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, + NULL_RTX, NULL_RTX); + } } /* ??? There's no need to emit actual instructions here, but it's the @@ -15000,21 +15074,6 @@ rs6000_emit_prologue (void) } } - /* Save lr if we used it. */ - if (!WORLD_SAVE_P (info) && info->lr_save_p) - { - rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->lr_save_offset + sp_offset)); - rtx reg = gen_rtx_REG (Pmode, 0); - rtx mem = gen_rtx_MEM (Pmode, addr); - /* This should not be of frame_alias_set, because of - __builtin_return_address. */ - - insn = emit_move_insn (mem, reg); - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - NULL_RTX, NULL_RTX); - } - /* Save CR if we use any that must be preserved. */ if (!WORLD_SAVE_P (info) && info->cr_save_p) { @@ -15548,15 +15607,58 @@ rs6000_emit_epilogue (int sibcall) } emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); } + else if (TARGET_SPE_ABI + && info->spe_64bit_regs_used != 0 + && info->first_gp_reg_save != 32) + { + rtx spe_save_area_ptr; + /* Determine whether we can address all of the registers that need + to be saved with an offset from the stack pointer that fits in + the small const field for SPE memory instructions. */ + int spe_regs_addressable_via_sp + = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset + + (32 - info->first_gp_reg_save - 1) * reg_size); + int spe_offset; + + if (spe_regs_addressable_via_sp) + { + spe_save_area_ptr = frame_reg_rtx; + spe_offset = info->spe_gp_save_offset + sp_offset; + } + else + { + /* Make r11 point to the start of the SPE save area. We worried about + not clobbering it when we were saving registers in the prolgoue. + There's no need to worry here because the static chain is passed + anew to every function. */ + spe_save_area_ptr = gen_rtx_REG (Pmode, 11); + + emit_insn (gen_addsi3 (spe_save_area_ptr, frame_reg_rtx, + GEN_INT (info->spe_gp_save_offset + sp_offset))); + + spe_offset = 0; + } + + for (i = 0; i < 32 - info->first_gp_reg_save; i++) + if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) + { + rtx offset, addr, mem; + + /* We're doing all this to ensure that the immediate offset + fits into the immediate field of 'evldd'. */ + gcc_assert (SPE_CONST_OFFSET_OK (spe_offset + reg_size * i)); + + offset = GEN_INT (spe_offset + reg_size * i); + addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset); + mem = gen_rtx_MEM (V2SImode, addr); + + emit_move_insn (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i), + mem); + } + } else for (i = 0; i < 32 - info->first_gp_reg_save; i++) - if ((regs_ever_live[info->first_gp_reg_save + i] - && (!call_used_regs[info->first_gp_reg_save + i] - || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM - && TARGET_TOC && TARGET_MINIMAL_TOC))) - || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM - && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0) - || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))) + if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->gp_save_offset @@ -15564,24 +15666,6 @@ rs6000_emit_epilogue (int sibcall) + reg_size * i)); rtx mem = gen_frame_mem (reg_mode, addr); - /* Restore 64-bit quantities for SPE. */ - if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0) - { - int offset = info->spe_gp_save_offset + sp_offset + 8 * i; - rtx b; - - if (!SPE_CONST_OFFSET_OK (offset)) - { - b = gen_rtx_REG (Pmode, FIXED_SCRATCH); - emit_move_insn (b, GEN_INT (offset)); - } - else - b = GEN_INT (offset); - - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b); - mem = gen_frame_mem (V2SImode, addr); - } - emit_move_insn (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i), mem); } @@ -15657,7 +15741,13 @@ rs6000_emit_epilogue (int sibcall) /* This blockage is needed so that sched doesn't decide to move the sp change before the register restores. */ rs6000_emit_stack_tie (); - emit_move_insn (sp_reg_rtx, frame_reg_rtx); + if (TARGET_SPE_ABI + && info->spe_64bit_regs_used != 0 + && info->first_gp_reg_save != 32) + emit_insn (gen_addsi3 (sp_reg_rtx, gen_rtx_REG (Pmode, 11), + GEN_INT (-(info->spe_gp_save_offset + sp_offset)))); + else + emit_move_insn (sp_reg_rtx, frame_reg_rtx); } else if (sp_offset != 0) emit_insn (TARGET_32BIT diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 57cd68d..509cd6e 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -913,18 +913,12 @@ extern enum rs6000_nop_insertion rs6000_sched_insert_nops; #define LOGICAL_OP_NON_SHORT_CIRCUIT 0 -/* A fixed register used at prologue and epilogue generation to fix - addressing modes. The SPE needs heavy addressing fixes at the last - minute, and it's best to save a register for it. +/* A fixed register used at epilogue generation to address SPE registers + with negative offsets. The 64-bit load/store instructions on the SPE + only take positive offsets (and small ones at that), so we need to + reserve a register for consing up negative offsets. */ - AltiVec also needs fixes, but we've gotten around using r11, which - is actually wrong because when use_backchain_to_restore_sp is true, - we end up clobbering r11. - - The AltiVec case needs to be fixed. Dunno if we should break ABI - compatibility and reserve a register for it as well.. */ - -#define FIXED_SCRATCH (TARGET_SPE ? 14 : 11) +#define FIXED_SCRATCH 0 /* Define this macro to change register usage conditional on target flags. */ |