From e6477eaa4d5524e7d05975188e27e7b1a148df3b Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 17 Apr 2008 12:27:31 +0000 Subject: [PATCH] re PR target/35907 (64-bit power6 glibc miscompilation) 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. From-SVN: r134387 --- gcc/ChangeLog | 8 +++ gcc/config/rs6000/rs6000.c | 101 ++++++++++++++++++++++++++++++++----- 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 + + 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 * 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; -- 2.30.2