]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
rs6000.c (rs6000_emit_stack_reset): Return generated insn if it is changing sp.
authorJakub Jelinek <jakub@redhat.com>
Wed, 3 Jun 2009 17:28:00 +0000 (19:28 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 3 Jun 2009 17:28:00 +0000 (19:28 +0200)
* config/rs6000/rs6000.c (rs6000_emit_stack_reset): Return generated
insn if it is changing sp.  Use gen_add3_insn instead of
conditionally gen_addsi3 and gen_adddi3.
(offset_below_red_zone_p): New static inline function.
(rs6000_emit_epilogue): Emit needed epilogue unwind info.
Use gen_add3_insn instead of conditionally gen_addsi3 and gen_adddi3.
* config/rs6000/ppc-asm.h: Include auto-host.h.
(CFI_STARTPROC, CFI_ENDPROC, CFI_DEF_CFA_REGISTER, CFI_OFFSET,
CFI_RESTORE): Define.
* config/rs6000/crtresxgpr.asm: Add unwind info.
* config/rs6000/crtresxfpr.asm: Likewise.
* config/rs6000/crtresgpr.asm: Likewise.
* config/rs6000/crtresfpr.asm: Likewise.
* config/rs6000/crtsavgpr.asm: Likewise.
* config/rs6000/crtsavfpr.asm: Likewise.

From-SVN: r148138

gcc/ChangeLog
gcc/config/rs6000/crtresfpr.asm
gcc/config/rs6000/crtresgpr.asm
gcc/config/rs6000/crtresxfpr.asm
gcc/config/rs6000/crtresxgpr.asm
gcc/config/rs6000/crtsavfpr.asm
gcc/config/rs6000/crtsavgpr.asm
gcc/config/rs6000/ppc-asm.h
gcc/config/rs6000/rs6000.c

index 100249c41fb414d816e097627892baa6f58ac0b9..e28fd41818e12195de5088be4394913e7beb0269 100644 (file)
@@ -1,5 +1,21 @@
 2009-06-03  Jakub Jelinek  <jakub@redhat.com>
 
+       * config/rs6000/rs6000.c (rs6000_emit_stack_reset): Return generated
+       insn if it is changing sp.  Use gen_add3_insn instead of
+       conditionally gen_addsi3 and gen_adddi3.
+       (offset_below_red_zone_p): New static inline function.
+       (rs6000_emit_epilogue): Emit needed epilogue unwind info.
+       Use gen_add3_insn instead of conditionally gen_addsi3 and gen_adddi3.
+       * config/rs6000/ppc-asm.h: Include auto-host.h.
+       (CFI_STARTPROC, CFI_ENDPROC, CFI_DEF_CFA_REGISTER, CFI_OFFSET,
+       CFI_RESTORE): Define.
+       * config/rs6000/crtresxgpr.asm: Add unwind info.
+       * config/rs6000/crtresxfpr.asm: Likewise.
+       * config/rs6000/crtresgpr.asm: Likewise.
+       * config/rs6000/crtresfpr.asm: Likewise.
+       * config/rs6000/crtsavgpr.asm: Likewise.
+       * config/rs6000/crtsavfpr.asm: Likewise.
+
        * dwarf2out.c (output_cfi_directive): Pass 1 instead of
        0 to second argument of DWARF2_FRAME_REG_OUT macros.
 
index 7adc9c1e7574166cb55f2f927b22564e5e579464..9fb228cf4581dc0e04f3e6b3708c98e1cf56ee2d 100644 (file)
@@ -38,6 +38,7 @@
 /* Called with r11 pointing to the stack header word of the caller of the */
 /* function, just beyond the end of the floating point save area.  */
 
+CFI_STARTPROC
 HIDDEN_FUNC(_restfpr_14)       lfd     14,-144(11)     /* restore fp registers */
 HIDDEN_FUNC(_restfpr_15)       lfd     15,-136(11)
 HIDDEN_FUNC(_restfpr_16)       lfd     16,-128(11)
@@ -75,5 +76,6 @@ FUNC_END(_restfpr_17)
 FUNC_END(_restfpr_16)
 FUNC_END(_restfpr_15)
 FUNC_END(_restfpr_14)
+CFI_ENDPROC
 
 #endif
index 4ed3d8e21c57f4616f18293ef9fb15a60003dfd2..9f9cec9f9cae4e911797330dbff897e1ca8e49d3 100644 (file)
@@ -38,6 +38,7 @@
 /* Called with r11 pointing to the stack header word of the caller of the */
 /* function, just beyond the end of the integer restore area.  */
 
+CFI_STARTPROC
 HIDDEN_FUNC(_restgpr_14)       lwz     14,-72(11)      /* restore gp registers */
 HIDDEN_FUNC(_restgpr_15)       lwz     15,-68(11)
 HIDDEN_FUNC(_restgpr_16)       lwz     16,-64(11)
@@ -75,5 +76,6 @@ FUNC_END(_restgpr_17)
 FUNC_END(_restgpr_16)
 FUNC_END(_restgpr_15)
 FUNC_END(_restgpr_14)
+CFI_ENDPROC
 
 #endif
index 5a87a98052f6b7fff75e324361c71bcd8e17d282..633f2db61f07b5b9a2f09c31c750af94e5a56fc9 100644 (file)
 /* In addition to restoring the fp registers, it will return to the caller's */
 /* caller */
 
+CFI_STARTPROC
+CFI_DEF_CFA_REGISTER (11)
+CFI_OFFSET (65, 4)
+CFI_OFFSET (46, -144)
+CFI_OFFSET (47, -136)
+CFI_OFFSET (48, -128)
+CFI_OFFSET (49, -120)
+CFI_OFFSET (50, -112)
+CFI_OFFSET (51, -104)
+CFI_OFFSET (52, -96)
+CFI_OFFSET (53, -88)
+CFI_OFFSET (54, -80)
+CFI_OFFSET (55, -72)
+CFI_OFFSET (56, -64)
+CFI_OFFSET (57, -56)
+CFI_OFFSET (58, -48)
+CFI_OFFSET (59, -40)
+CFI_OFFSET (60, -32)
+CFI_OFFSET (61, -24)
+CFI_OFFSET (62, -16)
+CFI_OFFSET (63, -8)
 HIDDEN_FUNC(_restfpr_14_x)     lfd     14,-144(11)     /* restore fp registers */
+CFI_RESTORE (46)
 HIDDEN_FUNC(_restfpr_15_x)     lfd     15,-136(11)
+CFI_RESTORE (47)
 HIDDEN_FUNC(_restfpr_16_x)     lfd     16,-128(11)
+CFI_RESTORE (48)
 HIDDEN_FUNC(_restfpr_17_x)     lfd     17,-120(11)
+CFI_RESTORE (49)
 HIDDEN_FUNC(_restfpr_18_x)     lfd     18,-112(11)
+CFI_RESTORE (50)
 HIDDEN_FUNC(_restfpr_19_x)     lfd     19,-104(11)
+CFI_RESTORE (51)
 HIDDEN_FUNC(_restfpr_20_x)     lfd     20,-96(11)
+CFI_RESTORE (52)
 HIDDEN_FUNC(_restfpr_21_x)     lfd     21,-88(11)
+CFI_RESTORE (53)
 HIDDEN_FUNC(_restfpr_22_x)     lfd     22,-80(11)
+CFI_RESTORE (54)
 HIDDEN_FUNC(_restfpr_23_x)     lfd     23,-72(11)
+CFI_RESTORE (55)
 HIDDEN_FUNC(_restfpr_24_x)     lfd     24,-64(11)
+CFI_RESTORE (56)
 HIDDEN_FUNC(_restfpr_25_x)     lfd     25,-56(11)
+CFI_RESTORE (57)
 HIDDEN_FUNC(_restfpr_26_x)     lfd     26,-48(11)
+CFI_RESTORE (58)
 HIDDEN_FUNC(_restfpr_27_x)     lfd     27,-40(11)
+CFI_RESTORE (59)
 HIDDEN_FUNC(_restfpr_28_x)     lfd     28,-32(11)
+CFI_RESTORE (60)
 HIDDEN_FUNC(_restfpr_29_x)     lfd     29,-24(11)
+CFI_RESTORE (61)
 HIDDEN_FUNC(_restfpr_30_x)     lfd     30,-16(11)
+CFI_RESTORE (62)
 HIDDEN_FUNC(_restfpr_31_x)     lwz     0,4(11)
                                lfd     31,-8(11)
+CFI_RESTORE (63)
                                mtlr    0
+CFI_RESTORE (65)
                                mr      1,11
+CFI_DEF_CFA_REGISTER (1)
                                blr
 FUNC_END(_restfpr_31_x)
 FUNC_END(_restfpr_30_x)
@@ -80,5 +121,6 @@ FUNC_END(_restfpr_17_x)
 FUNC_END(_restfpr_16_x)
 FUNC_END(_restfpr_15_x)
 FUNC_END(_restfpr_14_x)
+CFI_ENDPROC
 
 #endif
index 9317131c8ce1bd8deb1061dee0e48a770eedab3c..451b2b69d1efbd8b8c190dbaebd1f5e3dec19ee2 100644 (file)
 /* Called with r11 pointing to the stack header word of the caller of the */
 /* function, just beyond the end of the integer restore area.  */
 
+CFI_STARTPROC
+CFI_DEF_CFA_REGISTER (11)
+CFI_OFFSET (65, 4)
+CFI_OFFSET (14, -72)
+CFI_OFFSET (15, -68)
+CFI_OFFSET (16, -64)
+CFI_OFFSET (17, -60)
+CFI_OFFSET (18, -56)
+CFI_OFFSET (19, -52)
+CFI_OFFSET (20, -48)
+CFI_OFFSET (21, -44)
+CFI_OFFSET (22, -40)
+CFI_OFFSET (23, -36)
+CFI_OFFSET (24, -32)
+CFI_OFFSET (25, -28)
+CFI_OFFSET (26, -24)
+CFI_OFFSET (27, -20)
+CFI_OFFSET (28, -16)
+CFI_OFFSET (29, -12)
+CFI_OFFSET (30, -8)
+CFI_OFFSET (31, -4)
 HIDDEN_FUNC(_restgpr_14_x)     lwz     14,-72(11)      /* restore gp registers */
+CFI_RESTORE (14)
 HIDDEN_FUNC(_restgpr_15_x)     lwz     15,-68(11)
+CFI_RESTORE (15)
 HIDDEN_FUNC(_restgpr_16_x)     lwz     16,-64(11)
+CFI_RESTORE (16)
 HIDDEN_FUNC(_restgpr_17_x)     lwz     17,-60(11)
+CFI_RESTORE (17)
 HIDDEN_FUNC(_restgpr_18_x)     lwz     18,-56(11)
+CFI_RESTORE (18)
 HIDDEN_FUNC(_restgpr_19_x)     lwz     19,-52(11)
+CFI_RESTORE (19)
 HIDDEN_FUNC(_restgpr_20_x)     lwz     20,-48(11)
+CFI_RESTORE (20)
 HIDDEN_FUNC(_restgpr_21_x)     lwz     21,-44(11)
+CFI_RESTORE (21)
 HIDDEN_FUNC(_restgpr_22_x)     lwz     22,-40(11)
+CFI_RESTORE (22)
 HIDDEN_FUNC(_restgpr_23_x)     lwz     23,-36(11)
+CFI_RESTORE (23)
 HIDDEN_FUNC(_restgpr_24_x)     lwz     24,-32(11)
+CFI_RESTORE (24)
 HIDDEN_FUNC(_restgpr_25_x)     lwz     25,-28(11)
+CFI_RESTORE (25)
 HIDDEN_FUNC(_restgpr_26_x)     lwz     26,-24(11)
+CFI_RESTORE (26)
 HIDDEN_FUNC(_restgpr_27_x)     lwz     27,-20(11)
+CFI_RESTORE (27)
 HIDDEN_FUNC(_restgpr_28_x)     lwz     28,-16(11)
+CFI_RESTORE (28)
 HIDDEN_FUNC(_restgpr_29_x)     lwz     29,-12(11)
+CFI_RESTORE (29)
 HIDDEN_FUNC(_restgpr_30_x)     lwz     30,-8(11)
+CFI_RESTORE (30)
 HIDDEN_FUNC(_restgpr_31_x)     lwz     0,4(11)
                                lwz     31,-4(11)
+CFI_RESTORE (31)
                                mtlr    0
+CFI_RESTORE (65)
                                mr      1,11
+CFI_DEF_CFA_REGISTER (1)
                                blr
 FUNC_END(_restgpr_31_x)
 FUNC_END(_restgpr_30_x)
@@ -78,5 +119,6 @@ FUNC_END(_restgpr_17_x)
 FUNC_END(_restgpr_16_x)
 FUNC_END(_restgpr_15_x)
 FUNC_END(_restgpr_14_x)
+CFI_ENDPROC
 
 #endif
index fe40a9e13d006af59767a9c9944d277faec6efa3..3cdb25033cae4a711bfdc74cdd4e6d33635527ce 100644 (file)
@@ -38,6 +38,7 @@
 /* Called with r11 pointing to the stack header word of the caller of the */
 /* function, just beyond the end of the floating point save area.  */
 
+CFI_STARTPROC
 HIDDEN_FUNC(_savefpr_14)       stfd    14,-144(11)     /* save fp registers */
 HIDDEN_FUNC(_savefpr_15)       stfd    15,-136(11)
 HIDDEN_FUNC(_savefpr_16)       stfd    16,-128(11)
@@ -75,5 +76,6 @@ FUNC_END(_savefpr_17)
 FUNC_END(_savefpr_16)
 FUNC_END(_savefpr_15)
 FUNC_END(_savefpr_14)
+CFI_ENDPROC
 
 #endif
index 6c5f6720934d3a7a29b61bd9035e5b5d2ad96291..6d473963bad7be4deccbf9d3771918bc149e6c4c 100644 (file)
@@ -38,6 +38,7 @@
 /* Called with r11 pointing to the stack header word of the caller of the */
 /* function, just beyond the end of the integer save area.  */
 
+CFI_STARTPROC
 HIDDEN_FUNC(_savegpr_14)       stw     14,-72(11)      /* save gp registers */
 HIDDEN_FUNC(_savegpr_15)       stw     15,-68(11)
 HIDDEN_FUNC(_savegpr_16)       stw     16,-64(11)
@@ -75,5 +76,6 @@ FUNC_END(_savegpr_17)
 FUNC_END(_savegpr_16)
 FUNC_END(_savegpr_15)
 FUNC_END(_savegpr_14)
+CFI_ENDPROC
 
 #endif
index 3a70a137b55b8ff5d74c1812ee4c094c7cd4b520..575187c32653a2e75c959b20b8bc4c415f183303 100644 (file)
@@ -1,6 +1,6 @@
 /* PowerPC asm definitions for GNU C.
 
-Copyright (C) 2002, 2003, 2008 Free Software Foundation, Inc.
+Copyright (C) 2002, 2003, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -196,6 +196,23 @@ GLUE(.L,name): \
        .size FUNC_NAME(name),GLUE(.L,name)-FUNC_NAME(name)
 #endif
 
+/* For HAVE_GAS_CFI_DIRECTIVE.  */
+#include "auto-host.h"
+
+#ifdef HAVE_GAS_CFI_DIRECTIVE
+# define CFI_STARTPROC                 .cfi_startproc
+# define CFI_ENDPROC                   .cfi_endproc
+# define CFI_OFFSET(reg, off)          .cfi_offset reg, off
+# define CFI_DEF_CFA_REGISTER(reg)     .cfi_def_cfa_register reg
+# define CFI_RESTORE(reg)              .cfi_restore reg
+#else
+# define CFI_STARTPROC
+# define CFI_ENDPROC
+# define CFI_OFFSET(reg, off)
+# define CFI_DEF_CFA_REGISTER(reg)
+# define CFI_RESTORE(reg)
+#endif
+
 #if defined __linux__ && !defined __powerpc64__
        .section .note.GNU-stack
        .previous
index be2eca084b1f9d4eb6e7b80893a50f408767c876..579d22485abecb5cd7ad2e6738349e0bd39faa8e 100644 (file)
@@ -778,7 +778,7 @@ static const char *rs6000_mangle_type (const_tree);
 extern const struct attribute_spec rs6000_attribute_table[];
 static void rs6000_set_default_type_attributes (tree);
 static rtx rs6000_savres_routine_sym (rs6000_stack_t *, bool, bool, bool);
-static void rs6000_emit_stack_reset (rs6000_stack_t *, rtx, rtx, int, bool);
+static rtx rs6000_emit_stack_reset (rs6000_stack_t *, rtx, rtx, int, bool);
 static rtx rs6000_make_savres_rtx (rs6000_stack_t *, rtx, int,
                                   enum machine_mode, bool, bool, bool);
 static bool rs6000_reg_live_or_pic_offset_p (int);
@@ -15892,7 +15892,7 @@ rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep, bool gpr, bool exit
    stack pointer, but move the base of the frame into r11 for use by
    out-of-line register restore routines.  */
 
-static void
+static rtx
 rs6000_emit_stack_reset (rs6000_stack_t *info,
                         rtx sp_reg_rtx, rtx frame_reg_rtx,
                         int sp_offset, bool savres)
@@ -15908,10 +15908,10 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
   if (frame_reg_rtx != sp_reg_rtx)
     {
       if (sp_offset != 0)
-       emit_insn (gen_addsi3 (sp_reg_rtx, frame_reg_rtx,
-                              GEN_INT (sp_offset)));
+       return emit_insn (gen_addsi3 (sp_reg_rtx, frame_reg_rtx,
+                                     GEN_INT (sp_offset)));
       else if (!savres)
-       emit_move_insn (sp_reg_rtx, frame_reg_rtx);
+       return emit_move_insn (sp_reg_rtx, frame_reg_rtx);
     }
   else if (sp_offset != 0)
     {
@@ -15923,12 +15923,12 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
                      ? gen_rtx_REG (Pmode, 11)
                      : sp_reg_rtx);
 
-      emit_insn (TARGET_32BIT
-                ? gen_addsi3 (dest_reg, sp_reg_rtx,
-                              GEN_INT (sp_offset))
-                : gen_adddi3 (dest_reg, sp_reg_rtx,
-                              GEN_INT (sp_offset)));
+      rtx insn = emit_insn (gen_add3_insn (dest_reg, sp_reg_rtx,
+                                          GEN_INT (sp_offset)));
+      if (!savres)
+       return insn;
     }
+  return NULL_RTX;
 }
 
 /* Construct a parallel rtx describing the effect of a call to an
@@ -16838,12 +16838,19 @@ rs6000_restore_saved_cr (rtx reg, int using_mfcr_multiple)
        }
 }
 
-/* Emit function epilogue as insns.
+/* Return true if OFFSET from stack pointer can be clobbered by signals.
+   V.4 doesn't have any stack cushion, AIX ABIs have 220 or 288 bytes
+   below stack pointer not cloberred by signals.  */
+
+static inline bool
+offset_below_red_zone_p (HOST_WIDE_INT offset)
+{
+  return offset < (DEFAULT_ABI == ABI_V4
+                  ? 0
+                  : TARGET_32BIT ? -220 : -288);
+}
 
-   At present, dwarf2out_frame_debug_expr doesn't understand
-   register restores, so we don't bother setting RTX_FRAME_RELATED_P
-   anywhere in the epilogue.  Most of the insns below would in any case
-   need special notes to explain where r11 is in relation to the stack.  */
+/* Emit function epilogue as insns.  */
 
 void
 rs6000_emit_epilogue (int sibcall)
@@ -16859,6 +16866,8 @@ rs6000_emit_epilogue (int sibcall)
   int sp_offset = 0;
   rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
   rtx frame_reg_rtx = sp_reg_rtx;
+  rtx cfa_restores = NULL_RTX;
+  rtx insn;
   enum machine_mode reg_mode = Pmode;
   int reg_size = TARGET_32BIT ? 4 : 8;
   int i;
@@ -16999,7 +17008,7 @@ rs6000_emit_epilogue (int sibcall)
       && info->altivec_size != 0
       && (ALWAYS_RESTORE_ALTIVEC_BEFORE_POP
          || (DEFAULT_ABI != ABI_V4
-             && info->altivec_save_offset < (TARGET_32BIT ? -220 : -288))))
+             && offset_below_red_zone_p (info->altivec_save_offset))))
     {
       int i;
 
@@ -17016,7 +17025,7 @@ rs6000_emit_epilogue (int sibcall)
       for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
        if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
          {
-           rtx addr, areg, mem;
+           rtx addr, areg, mem, reg;
 
            areg = gen_rtx_REG (Pmode, 0);
            emit_move_insn
@@ -17028,7 +17037,13 @@ rs6000_emit_epilogue (int sibcall)
            addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
            mem = gen_frame_mem (V4SImode, addr);
 
-           emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
+           reg = gen_rtx_REG (V4SImode, i);
+           emit_move_insn (reg, mem);
+           if (offset_below_red_zone_p (info->altivec_save_offset
+                                        + (i - info->first_altivec_reg_save)
+                                          * 16))
+             cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                            cfa_restores);
          }
     }
 
@@ -17038,7 +17053,7 @@ rs6000_emit_epilogue (int sibcall)
       && info->vrsave_mask != 0
       && (ALWAYS_RESTORE_ALTIVEC_BEFORE_POP
          || (DEFAULT_ABI != ABI_V4
-             && info->vrsave_save_offset < (TARGET_32BIT ? -220 : -288))))
+             && offset_below_red_zone_p (info->vrsave_save_offset))))
     {
       rtx addr, mem, reg;
 
@@ -17064,6 +17079,7 @@ rs6000_emit_epilogue (int sibcall)
       emit_insn (generate_set_vrsave (reg, info, 1));
     }
 
+  insn = NULL_RTX;
   /* If we have a large stack frame, restore the old stack pointer
      using the backchain.  */
   if (use_backchain_to_restore_sp)
@@ -17075,8 +17091,8 @@ rs6000_emit_epilogue (int sibcall)
          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));
+         insn = emit_move_insn (frame_reg_rtx,
+                                gen_rtx_MEM (Pmode, sp_reg_rtx));
          sp_offset = 0;
        }
       else if (ALWAYS_RESTORE_ALTIVEC_BEFORE_POP
@@ -17085,7 +17101,7 @@ rs6000_emit_epilogue (int sibcall)
        ;
       else
        {
-         emit_move_insn (sp_reg_rtx, frame_reg_rtx);
+         insn = emit_move_insn (sp_reg_rtx, frame_reg_rtx);
          frame_reg_rtx = sp_reg_rtx;
        }
     }
@@ -17097,38 +17113,42 @@ rs6000_emit_epilogue (int sibcall)
       if (DEFAULT_ABI == ABI_V4)
        frame_reg_rtx = gen_rtx_REG (Pmode, 11);
 
-      emit_insn (TARGET_32BIT
-                ? gen_addsi3 (frame_reg_rtx, hard_frame_pointer_rtx,
-                              GEN_INT (info->total_size))
-                : gen_adddi3 (frame_reg_rtx, hard_frame_pointer_rtx,
-                              GEN_INT (info->total_size)));
+      insn = emit_insn (gen_add3_insn (frame_reg_rtx, hard_frame_pointer_rtx,
+                                      GEN_INT (info->total_size)));
       sp_offset = 0;
     }
   else if (info->push_p
           && DEFAULT_ABI != ABI_V4
           && !crtl->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)));
+      insn = emit_insn (gen_add3_insn (sp_reg_rtx, sp_reg_rtx,
+                                      GEN_INT (info->total_size)));
       sp_offset = 0;
     }
+  if (insn && frame_reg_rtx == sp_reg_rtx)
+    {
+      if (cfa_restores)
+       {
+         REG_NOTES (insn) = cfa_restores;
+         cfa_restores = NULL_RTX;
+       }
+      add_reg_note (insn, REG_CFA_DEF_CFA, sp_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
 
   /* Restore AltiVec registers if we have not done so already.  */
   if (!ALWAYS_RESTORE_ALTIVEC_BEFORE_POP
       && TARGET_ALTIVEC_ABI
       && info->altivec_size != 0
       && (DEFAULT_ABI == ABI_V4
-         || info->altivec_save_offset >= (TARGET_32BIT ? -220 : -288)))
+         || !offset_below_red_zone_p (info->altivec_save_offset)))
     {
       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;
+           rtx addr, areg, mem, reg;
 
            areg = gen_rtx_REG (Pmode, 0);
            emit_move_insn
@@ -17140,7 +17160,11 @@ rs6000_emit_epilogue (int sibcall)
            addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
            mem = gen_frame_mem (V4SImode, addr);
 
-           emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
+           reg = gen_rtx_REG (V4SImode, i);
+           emit_move_insn (reg, mem);
+           if (DEFAULT_ABI == ABI_V4)
+             cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                            cfa_restores);
          }
     }
 
@@ -17150,7 +17174,7 @@ rs6000_emit_epilogue (int sibcall)
       && TARGET_ALTIVEC_VRSAVE
       && info->vrsave_mask != 0
       && (DEFAULT_ABI == ABI_V4
-         || info->vrsave_save_offset >= (TARGET_32BIT ? -220 : -288)))
+         || !offset_below_red_zone_p (info->vrsave_save_offset)))
     {
       rtx addr, mem, reg;
 
@@ -17183,7 +17207,8 @@ rs6000_emit_epilogue (int sibcall)
       emit_move_insn (gen_rtx_REG (SImode, 12), mem);
     }
 
-  /* Set LR here to try to overlap restores below.  */
+  /* Set LR here to try to overlap restores below.  LR is always saved
+     above incoming stack, so it never needs REG_CFA_RESTORE.  */
   if (restore_lr)
     emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
                    gen_rtx_REG (Pmode, 0));
@@ -17265,7 +17290,7 @@ rs6000_emit_epilogue (int sibcall)
          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;
+               rtx offset, addr, mem, reg;
 
                /* We're doing all this to ensure that the immediate offset
                   fits into the immediate field of 'evldd'.  */
@@ -17274,9 +17299,24 @@ rs6000_emit_epilogue (int sibcall)
                offset = GEN_INT (spe_offset + reg_size * i);
                addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, offset);
                mem = gen_rtx_MEM (V2SImode, addr);
+               reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
-               emit_move_insn (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
-                               mem);
+               insn = emit_move_insn (reg, mem);
+               if (DEFAULT_ABI == ABI_V4)
+                 {
+                   if (frame_pointer_needed
+                       && info->first_gp_reg_save + i
+                          == HARD_FRAME_POINTER_REGNUM)
+                     {
+                       add_reg_note (insn, REG_CFA_DEF_CFA,
+                                     plus_constant (frame_reg_rtx,
+                                                    sp_offset));
+                       RTX_FRAME_RELATED_P (insn) = 1;
+                     }
+
+                   cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                                  cfa_restores);
+                 }
              }
        }
       else
@@ -17288,7 +17328,6 @@ rs6000_emit_epilogue (int sibcall)
                                        /*savep=*/false, /*gpr=*/true,
                                        /*exitp=*/true);
          emit_jump_insn (par);
-
          /* We don't want anybody else emitting things after we jumped
             back.  */
          return;
@@ -17317,8 +17356,15 @@ rs6000_emit_epilogue (int sibcall)
       if (can_use_exit)
        {
          if (info->cr_save_p)
-           rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12),
-                                    using_mtcr_multiple);
+           {
+             rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12),
+                                      using_mtcr_multiple);
+             if (DEFAULT_ABI == ABI_V4)
+               cfa_restores
+                 = alloc_reg_note (REG_CFA_RESTORE,
+                                   gen_rtx_REG (SImode, CR2_REGNO),
+                                   cfa_restores);
+           }
 
          emit_jump_insn (par);
 
@@ -17326,8 +17372,22 @@ rs6000_emit_epilogue (int sibcall)
             back.  */
          return;
        }
-      else
-       emit_insn (par);
+
+      insn = emit_insn (par);
+      if (DEFAULT_ABI == ABI_V4)
+       {
+         if (frame_pointer_needed)
+           {
+             add_reg_note (insn, REG_CFA_DEF_CFA,
+                           plus_constant (frame_reg_rtx, sp_offset));
+             RTX_FRAME_RELATED_P (insn) = 1;
+           }
+
+         for (i = info->first_gp_reg_save; i < 32; i++)
+           cfa_restores
+             = alloc_reg_note (REG_CFA_RESTORE,
+                               gen_rtx_REG (reg_mode, i), cfa_restores);
+       }
     }
   else if (using_load_multiple)
     {
@@ -17340,13 +17400,20 @@ rs6000_emit_epilogue (int sibcall)
                                            + sp_offset
                                            + reg_size * i));
          rtx mem = gen_frame_mem (reg_mode, addr);
+         rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
-         RTVEC_ELT (p, i) =
-           gen_rtx_SET (VOIDmode,
-                        gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
-                        mem);
+         RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, reg, mem);
+         if (DEFAULT_ABI == ABI_V4)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                          cfa_restores);
+       }
+      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
+      if (DEFAULT_ABI == ABI_V4 && frame_pointer_needed)
+       {
+         add_reg_note (insn, REG_CFA_DEF_CFA,
+                       plus_constant (frame_reg_rtx, sp_offset));
+         RTX_FRAME_RELATED_P (insn) = 1;
        }
-      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
     }
   else
     {
@@ -17358,9 +17425,23 @@ rs6000_emit_epilogue (int sibcall)
                                               + sp_offset
                                               + reg_size * i));
             rtx mem = gen_frame_mem (reg_mode, addr);
+           rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
-            emit_move_insn (gen_rtx_REG (reg_mode,
-                                         info->first_gp_reg_save + i), mem);
+           insn = emit_move_insn (reg, mem);
+           if (DEFAULT_ABI == ABI_V4)
+             {
+               if (frame_pointer_needed
+                   && info->first_gp_reg_save + i
+                      == HARD_FRAME_POINTER_REGNUM)
+                 {
+                   add_reg_note (insn, REG_CFA_DEF_CFA,
+                                 plus_constant (frame_reg_rtx, sp_offset));
+                   RTX_FRAME_RELATED_P (insn) = 1;
+                 }
+
+               cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                              cfa_restores);
+             }
           }
     }
 
@@ -17370,36 +17451,52 @@ rs6000_emit_epilogue (int sibcall)
       if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
           && ! call_used_regs[info->first_fp_reg_save+i]))
        {
-         rtx addr, mem;
+         rtx addr, mem, reg;
          addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                               GEN_INT (info->fp_save_offset
                                        + sp_offset
                                        + 8 * i));
          mem = gen_frame_mem (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
                                 ? DFmode : SFmode), addr);
+         reg = gen_rtx_REG (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
+                              ? DFmode : SFmode),
+                            info->first_fp_reg_save + i);
 
-         emit_move_insn (gen_rtx_REG (((TARGET_HARD_FLOAT 
-                                        && TARGET_DOUBLE_FLOAT)
-                                       ? DFmode : SFmode),
-                                      info->first_fp_reg_save + i),
-                         mem);
+         emit_move_insn (reg, mem);
+         if (DEFAULT_ABI == ABI_V4)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                          cfa_restores);
        }
 
   /* If we saved cr, restore it here.  Just those that were used.  */
   if (info->cr_save_p)
-    rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12), using_mtcr_multiple);
+    {
+      rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12), using_mtcr_multiple);
+      if (DEFAULT_ABI == ABI_V4)
+       cfa_restores
+         = alloc_reg_note (REG_CFA_RESTORE, gen_rtx_REG (SImode, CR2_REGNO),
+                           cfa_restores);
+    }
 
   /* If this is V.4, unwind the stack pointer after all of the loads
      have been done.  */
-  rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
-                          sp_offset, !restoring_FPRs_inline);
+  insn = rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
+                                 sp_offset, !restoring_FPRs_inline);
+  if (insn)
+    {
+      if (cfa_restores)
+       {
+         REG_NOTES (insn) = cfa_restores;
+         cfa_restores = NULL_RTX;
+       }
+      add_reg_note (insn, REG_CFA_DEF_CFA, sp_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
 
   if (crtl->calls_eh_return)
     {
       rtx sa = EH_RETURN_STACKADJ_RTX;
-      emit_insn (TARGET_32BIT
-                ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
-                : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
+      emit_insn (gen_add3_insn (sp_reg_rtx, sp_reg_rtx, sa));
     }
 
   if (!sibcall)