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 | 139 ++++++++++++++++++++++++++++--------- 2 files changed, 116 insertions(+), 31 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,8 +16370,108 @@ 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)) + { + 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 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) + { + 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; + } + } + else if (info->push_p + && DEFAULT_ABI != ABI_V4 + && !current_function_calls_eh_return) + { + emit_insn (TARGET_32BIT + ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, + GEN_INT (info->total_size)) + : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, + GEN_INT (info->total_size))); + sp_offset = 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; @@ -16394,35 +16494,12 @@ rs6000_emit_epilogue (int sibcall) } } - /* 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); - - 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 - && !current_function_calls_eh_return) - { - emit_insn (TARGET_32BIT - ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, - GEN_INT (info->total_size)) - : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, - GEN_INT (info->total_size))); - sp_offset = 0; - } - - /* Restore VRSAVE if needed. */ - if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE - && info->vrsave_mask != 0) + /* 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;