This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RS6000] Fix PR35907, vmx regs trashed
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 16 Apr 2008 18:31:54 +0930
- Subject: [RS6000] Fix PR35907, vmx regs trashed
This patch cures an oversight in Eric's 2007-05-27 change that could
cause vmx registers to be restored from the wrong location if a
function called alloca, and reinstates a fixed version of Eric's code
to restore vrsave that I reverted 2007-10-20 for PR33812. The
reversion ignored the fact that vrsave can live outside the area of
stack valid below sp.
So, we now have vmx registers being restored either before or after
the frame pop, depending on their location in the frame. We could
always restore before the frame pop, but this can cost one extra
reg->reg move instruction when use_backchain_to_restore_sp. (It's
possible to restore vmx regs after the frame pop even when
use_backchain_to_restore_sp, if the vmx regs are within the area of
stack valid below sp. If we restore before the pop in this case then
we'll load the backchain into r11 then move to r1, whereas restoring
after the pop will load the backchain directly into r1.)
Bootstrapped and regression tested powerpc-linux and powerpc64-linux.
OK to apply both mainline and 4.3?
PR target/35907
* config/rs6000/rs6000.c (rs6000_emit_epilogue): Restore vr and vrsave
regs before frame pop when needed. If use_backchain_to_restore_sp
then load backchain into a temp reg to restore vr and vrsave. Add
code to restore vr after frame pop if possible.
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 134338)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -16370,11 +16370,23 @@ rs6000_emit_epilogue (int sibcall)
if (info->push_p)
sp_offset = info->total_size;
- /* Restore AltiVec registers if needed. */
- if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+ /* Restore AltiVec registers if we must do so before adjusting the
+ stack. */
+ if (TARGET_ALTIVEC_ABI
+ && info->altivec_size != 0
+ && DEFAULT_ABI != ABI_V4
+ && info->altivec_save_offset < (TARGET_32BIT ? -220 : -288))
{
int i;
+ if (use_backchain_to_restore_sp)
+ {
+ frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+ emit_move_insn (frame_reg_rtx,
+ gen_rtx_MEM (Pmode, sp_reg_rtx));
+ sp_offset = 0;
+ }
+
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
{
@@ -16394,19 +16406,54 @@ rs6000_emit_epilogue (int sibcall)
}
}
+ /* Restore VRSAVE if we must do so before adjusting the stack. */
+ if (TARGET_ALTIVEC
+ && TARGET_ALTIVEC_VRSAVE
+ && info->vrsave_mask != 0
+ && DEFAULT_ABI != ABI_V4
+ && info->vrsave_save_offset < (TARGET_32BIT ? -220 : -288))
+ {
+ rtx addr, mem, reg;
+
+ if (use_backchain_to_restore_sp
+ && frame_reg_rtx == sp_reg_rtx)
+ {
+ frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+ emit_move_insn (frame_reg_rtx,
+ gen_rtx_MEM (Pmode, sp_reg_rtx));
+ sp_offset = 0;
+ }
+
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->vrsave_save_offset + sp_offset));
+ mem = gen_frame_mem (SImode, addr);
+ reg = gen_rtx_REG (SImode, 12);
+ emit_move_insn (reg, mem);
+
+ emit_insn (generate_set_vrsave (reg, info, 1));
+ }
+
/* If we have a frame pointer, a call to alloca, or a large stack
frame, restore the old stack pointer using the backchain. Otherwise,
we know what size to update it with. */
if (use_backchain_to_restore_sp)
{
- /* Under V.4, don't reset the stack pointer until after we're done
- loading the saved registers. */
- if (DEFAULT_ABI == ABI_V4)
- frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+ if (frame_reg_rtx != sp_reg_rtx)
+ {
+ emit_move_insn (sp_reg_rtx, frame_reg_rtx);
+ frame_reg_rtx = sp_reg_rtx;
+ }
+ else
+ {
+ /* Under V.4, don't reset the stack pointer until after we're done
+ loading the saved registers. */
+ if (DEFAULT_ABI == ABI_V4)
+ frame_reg_rtx = gen_rtx_REG (Pmode, 11);
- emit_move_insn (frame_reg_rtx,
- gen_rtx_MEM (Pmode, sp_reg_rtx));
- sp_offset = 0;
+ emit_move_insn (frame_reg_rtx,
+ gen_rtx_MEM (Pmode, sp_reg_rtx));
+ sp_offset = 0;
+ }
}
else if (info->push_p
&& DEFAULT_ABI != ABI_V4
@@ -16420,9 +16467,39 @@ rs6000_emit_epilogue (int sibcall)
sp_offset = 0;
}
- /* Restore VRSAVE if needed. */
- if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
- && info->vrsave_mask != 0)
+ /* Restore AltiVec registers if we have not done so already. */
+ if (TARGET_ALTIVEC_ABI
+ && info->altivec_size != 0
+ && (DEFAULT_ABI == ABI_V4
+ || info->altivec_save_offset >= (TARGET_32BIT ? -220 : -288)))
+ {
+ int i;
+
+ for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+ if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+ {
+ rtx addr, areg, mem;
+
+ areg = gen_rtx_REG (Pmode, 0);
+ emit_move_insn
+ (areg, GEN_INT (info->altivec_save_offset
+ + sp_offset
+ + 16 * (i - info->first_altivec_reg_save)));
+
+ /* AltiVec addressing mode is [reg+reg]. */
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+ mem = gen_frame_mem (V4SImode, addr);
+
+ emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
+ }
+ }
+
+ /* Restore VRSAVE if we have not done so already. */
+ if (TARGET_ALTIVEC
+ && TARGET_ALTIVEC_VRSAVE
+ && info->vrsave_mask != 0
+ && (DEFAULT_ABI == ABI_V4
+ || info->vrsave_save_offset >= (TARGET_32BIT ? -220 : -288)))
{
rtx addr, mem, reg;
--
Alan Modra
Australia Development Lab, IBM