summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4>2008-04-17 12:27:31 +0000
committeramodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4>2008-04-17 12:27:31 +0000
commit0dd5aca60d35e7f4ef0a7cd1b5869860e3947849 (patch)
tree37c1643662d5b851e6cdb077881cdd7a1320b4c9
parentb7676b65933e0c7b401042e21cbe4ad1be2927b9 (diff)
downloadgcc-0dd5aca60d35e7f4ef0a7cd1b5869860e3947849.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@134387 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/rs6000/rs6000.c101
2 files changed, 97 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4a3a4d0bd53..d1b9a4ca76a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2008-04-17 Alan Modra <amodra@bigpond.net.au>
+
+ 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.
+
2008-04-17 Richard Guenther <rguenther@suse.de>
* tree-vn.c (expressions_equal_p): Do not check type
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 0d868944218..024c140b274 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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;