aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Froyd <froydnj@codesourcery.com>2007-06-05 19:46:23 +0000
committerNathan Froyd <froydnj@gcc.gnu.org>2007-06-05 19:46:23 +0000
commit52ff33d0eb56df70238a99b7aa66140609f3abc3 (patch)
treeddb2aff474d2b21b69f98462040e6897f8ebc7ce
parentb08f991d9127706927d639bb51173e4474b976df (diff)
downloadgcc-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/ChangeLog21
-rw-r--r--gcc/config/rs6000/rs6000.c272
-rw-r--r--gcc/config/rs6000/rs6000.h16
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. */