2
0
mirror of git://gcc.gnu.org/git/gcc.git synced 2025-04-24 20:42:10 +08:00

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
This commit is contained in:
Nathan Froyd 2007-06-05 19:46:23 +00:00 committed by Nathan Froyd
parent b08f991d91
commit 52ff33d0eb
3 changed files with 207 additions and 102 deletions

@ -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.

@ -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

@ -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. */