OSDN Git Service

* config/rs6000/rs6000.c (rs6000_make_savres_rtx): Delete unneeded
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index a94a4f6..353e040 100644 (file)
@@ -899,8 +899,6 @@ static const char *rs6000_mangle_type (const_tree);
 static void rs6000_set_default_type_attributes (tree);
 static rtx rs6000_savres_routine_sym (rs6000_stack_t *, bool, bool, 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);
 static tree rs6000_builtin_vectorized_libmass (tree, tree, tree);
 static tree rs6000_builtin_vectorized_function (tree, tree, tree);
@@ -988,7 +986,6 @@ static tree rs6000_builtin_mask_for_load (void);
 static tree rs6000_builtin_mul_widen_even (tree);
 static tree rs6000_builtin_mul_widen_odd (tree);
 static tree rs6000_builtin_conversion (unsigned int, tree, tree);
-static tree rs6000_builtin_vec_perm (tree, tree *);
 static bool rs6000_builtin_support_vector_misalignment (enum
                                                        machine_mode,
                                                        const_tree,
@@ -1407,8 +1404,6 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD rs6000_builtin_mul_widen_odd
 #undef TARGET_VECTORIZE_BUILTIN_CONVERSION
 #define TARGET_VECTORIZE_BUILTIN_CONVERSION rs6000_builtin_conversion
-#undef TARGET_VECTORIZE_BUILTIN_VEC_PERM
-#define TARGET_VECTORIZE_BUILTIN_VEC_PERM rs6000_builtin_vec_perm
 #undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT
 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT           \
   rs6000_builtin_support_vector_misalignment
@@ -3475,65 +3470,6 @@ rs6000_builtin_support_vector_misalignment (enum machine_mode mode,
   return false;
 }
 
-/* Implement targetm.vectorize.builtin_vec_perm.  */
-tree
-rs6000_builtin_vec_perm (tree type, tree *mask_element_type)
-{
-  tree inner_type = TREE_TYPE (type);
-  bool uns_p = TYPE_UNSIGNED (inner_type);
-  tree d;
-
-  *mask_element_type = unsigned_char_type_node;
-
-  switch (TYPE_MODE (type))
-    {
-    case V16QImode:
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_16QI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_16QI]);
-      break;
-
-    case V8HImode:
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_8HI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_8HI]);
-      break;
-
-    case V4SImode:
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SI]);
-      break;
-
-    case V4SFmode:
-      d = rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SF];
-      break;
-
-    case V2DFmode:
-      if (!TARGET_ALLOW_DF_PERMUTE)
-       return NULL_TREE;
-
-      d = rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DF];
-      break;
-
-    case V2DImode:
-      if (!TARGET_ALLOW_DF_PERMUTE)
-       return NULL_TREE;
-
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DI]);
-      break;
-
-    default:
-      return NULL_TREE;
-    }
-
-  gcc_assert (d);
-  return d;
-}
-
-
 /* Implement targetm.vectorize.builtin_vectorization_cost.  */
 static int
 rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
@@ -3739,7 +3675,7 @@ rs6000_builtin_vectorized_libmass (tree fndecl, tree type_out, tree type_in)
        case BUILT_IN_SQRT:
        case BUILT_IN_TAN:
        case BUILT_IN_TANH:
-         bdecl = implicit_built_in_decls[fn];
+         bdecl = builtin_decl_implicit (fn);
          suffix = "d2";                                /* pow -> powd2 */
          if (el_mode != DFmode
              || n != 2)
@@ -3776,7 +3712,7 @@ rs6000_builtin_vectorized_libmass (tree fndecl, tree type_out, tree type_in)
        case BUILT_IN_SQRTF:
        case BUILT_IN_TANF:
        case BUILT_IN_TANHF:
-         bdecl = implicit_built_in_decls[fn];
+         bdecl = builtin_decl_implicit (fn);
          suffix = "4";                                 /* powf -> powf4 */
          if (el_mode != SFmode
              || n != 4)
@@ -4503,7 +4439,9 @@ paired_expand_vector_init (rtx target, rtx vals)
   for (i = 0; i < n_elts; ++i)
     {
       x = XVECEXP (vals, 0, i);
-      if (!CONSTANT_P (x))
+      if (!(CONST_INT_P (x)
+           || GET_CODE (x) == CONST_DOUBLE
+           || GET_CODE (x) == CONST_FIXED))
        ++n_var;
     }
   if (n_var == 0)
@@ -4655,7 +4593,9 @@ rs6000_expand_vector_init (rtx target, rtx vals)
   for (i = 0; i < n_elts; ++i)
     {
       x = XVECEXP (vals, 0, i);
-      if (!CONSTANT_P (x))
+      if (!(CONST_INT_P (x)
+           || GET_CODE (x) == CONST_DOUBLE
+           || GET_CODE (x) == CONST_FIXED))
        ++n_var, one_var = i;
       else if (x != CONST0_RTX (inner_mode))
        all_const_zero = false;
@@ -4754,7 +4694,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
 
   /* Store value to stack temp.  Load vector element.  Splat.  However, splat
      of 64-bit items is not supported on Altivec.  */
-  if (all_same && GET_MODE_SIZE (mode) <= 4)
+  if (all_same && GET_MODE_SIZE (inner_mode) <= 4)
     {
       mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
       emit_move_insn (adjust_address_nv (mem, inner_mode, 0),
@@ -9396,7 +9336,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
       tree tmp = create_tmp_var (type, "va_arg_tmp");
       tree dest_addr = build_fold_addr_expr (tmp);
 
-      tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY],
+      tree copy = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMCPY),
                                   3, dest_addr, addr, size_int (rsize * 4));
 
       gimplify_and_add (copy, pre_p);
@@ -12209,8 +12149,8 @@ rs6000_init_builtins (void)
 
 #if TARGET_XCOFF
   /* AIX libm provides clog as __clog.  */
-  if (built_in_decls [BUILT_IN_CLOG])
-    set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog");
+  if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE)
+    set_user_assembler_name (tdecl, "__clog");
 #endif
 
 #ifdef SUBTARGET_INIT_BUILTINS
@@ -17941,7 +17881,7 @@ compute_save_world_info (rs6000_stack_t *info_ptr)
   info_ptr->world_save_p
     = (WORLD_SAVE_P (info_ptr)
        && DEFAULT_ABI == ABI_DARWIN
-       && ! (cfun->calls_setjmp && flag_exceptions)
+       && !cfun->has_nonlocal_label
        && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
        && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
        && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
@@ -19299,7 +19239,8 @@ output_probe_stack_range (rtx reg1, rtx reg2)
   output_asm_insn ("{cal %0,%1(%0)|addi %0,%0,%1}", xops);
 
   /* Probe at TEST_ADDR and branch.  */
-  output_asm_insn ("{st|stw} 0,0(%0)", xops);
+  xops[1] = gen_rtx_REG (Pmode, 0);
+  output_asm_insn ("{st|stw} %1,0(%0)", xops);
   fprintf (asm_out_file, "\tb ");
   assemble_name_raw (asm_out_file, loop_lab);
   fputc ('\n', asm_out_file);
@@ -19700,8 +19641,10 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
       if (sp_offset != 0)
        {
          rtx dest_reg = savres ? gen_rtx_REG (Pmode, 11) : sp_reg_rtx;
-         return emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx,
-                                          GEN_INT (sp_offset)));
+         rtx insn = emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx,
+                                              GEN_INT (sp_offset)));
+         if (!savres)
+           return insn;
        }
       else if (!savres)
        return emit_move_insn (sp_reg_rtx, frame_reg_rtx);
@@ -19725,10 +19668,11 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
 }
 
 /* Construct a parallel rtx describing the effect of a call to an
-   out-of-line register save/restore routine.  */
+   out-of-line register save/restore routine, and emit the insn
+   or jump_insn as appropriate.  */
 
 static rtx
-rs6000_make_savres_rtx (rs6000_stack_t *info,
+rs6000_emit_savres_rtx (rs6000_stack_t *info,
                        rtx frame_reg_rtx, int save_area_offset,
                        enum machine_mode reg_mode,
                        bool savep, bool gpr, bool lr)
@@ -19738,6 +19682,7 @@ rs6000_make_savres_rtx (rs6000_stack_t *info,
   int reg_size = GET_MODE_SIZE (reg_mode);
   rtx sym;
   rtvec p;
+  rtx par, insn;
 
   offset = 0;
   start_reg = (gpr
@@ -19751,7 +19696,7 @@ rs6000_make_savres_rtx (rs6000_stack_t *info,
     RTVEC_ELT (p, offset++) = ret_rtx;
 
   RTVEC_ELT (p, offset++)
-    = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 65));
+    = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
 
   sym = rs6000_savres_routine_sym (info, savep, gpr, lr);
   RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym);
@@ -19784,7 +19729,16 @@ rs6000_make_savres_rtx (rs6000_stack_t *info,
       RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, mem, reg);
     }
 
-  return gen_rtx_PARALLEL (VOIDmode, p);
+  par = gen_rtx_PARALLEL (VOIDmode, p);
+
+  if (!savep && lr)
+    {
+      insn = emit_jump_insn (par);
+      JUMP_LABEL (insn) = ret_rtx;
+    }
+  else
+    insn = emit_insn (par);
+  return insn;
 }
 
 /* Determine whether the gp REG is really used.  */
@@ -20083,16 +20037,13 @@ rs6000_emit_prologue (void)
     }
   else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
     {
-      rtx par;
-
-      par = rs6000_make_savres_rtx (info, frame_reg_rtx,
-                                   info->fp_save_offset + sp_offset,
-                                   DFmode,
-                                   /*savep=*/true, /*gpr=*/false,
-                                   /*lr=*/(strategy
-                                           & SAVE_NOINLINE_FPRS_SAVES_LR)
-                                          != 0);
-      insn = emit_insn (par);
+      insn = rs6000_emit_savres_rtx (info, frame_reg_rtx,
+                                    info->fp_save_offset + sp_offset,
+                                    DFmode,
+                                    /*savep=*/true, /*gpr=*/false,
+                                    /*lr=*/((strategy
+                                             & SAVE_NOINLINE_FPRS_SAVES_LR)
+                                            != 0));
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
@@ -20182,13 +20133,10 @@ rs6000_emit_prologue (void)
        }
       else
        {
-         rtx par;
-
-         par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11),
-                                       0, reg_mode,
-                                       /*savep=*/true, /*gpr=*/true,
-                                       /*lr=*/false);
-         insn = emit_insn (par);
+         insn = rs6000_emit_savres_rtx (info, gen_rtx_REG (Pmode, 11),
+                                        0, reg_mode,
+                                        /*savep=*/true, /*gpr=*/true,
+                                        /*lr=*/false);
          rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                                NULL_RTX, NULL_RTX);
        }
@@ -20200,8 +20148,6 @@ rs6000_emit_prologue (void)
     }
   else if (!WORLD_SAVE_P (info) && !saving_GPRs_inline)
     {
-      rtx par;
-
       /* Need to adjust r11 (r12) if we saved any FPRs.  */
       if (info->first_fp_reg_save != 64)
         {
@@ -20212,14 +20158,13 @@ rs6000_emit_prologue (void)
          emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset));
         }
 
-      par = rs6000_make_savres_rtx (info, frame_reg_rtx,
-                                   info->gp_save_offset + sp_offset,
-                                   reg_mode,
-                                   /*savep=*/true, /*gpr=*/true,
-                                   /*lr=*/(strategy
-                                           & SAVE_NOINLINE_GPRS_SAVES_LR)
-                                          != 0);
-      insn = emit_insn (par);
+      insn = rs6000_emit_savres_rtx (info, frame_reg_rtx,
+                                    info->gp_save_offset + sp_offset,
+                                    reg_mode,
+                                    /*savep=*/true, /*gpr=*/true,
+                                    /*lr=*/((strategy
+                                             & SAVE_NOINLINE_GPRS_SAVES_LR)
+                                            != 0));
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
@@ -20668,6 +20613,20 @@ offset_below_red_zone_p (HOST_WIDE_INT offset)
                   : TARGET_32BIT ? -220 : -288);
 }
 
+/* Append CFA_RESTORES to any existing REG_NOTES on the last insn.  */
+
+static void
+emit_cfa_restores (rtx cfa_restores)
+{
+  rtx insn = get_last_insn ();
+  rtx *loc = &REG_NOTES (insn);
+
+  while (*loc)
+    loc = &XEXP (*loc, 1);
+  *loc = cfa_restores;
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
 /* Emit function epilogue as insns.  */
 
 void
@@ -20765,6 +20724,14 @@ rs6000_emit_epilogue (int sibcall)
        rtx mem = gen_frame_mem (reg_mode, addr);
 
        RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+
+       if (flag_shrink_wrap)
+         {
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                          gen_rtx_REG (Pmode, LR_REGNO),
+                                          cfa_restores);
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+         }
       }
 
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
@@ -20776,6 +20743,8 @@ rs6000_emit_epilogue (int sibcall)
          rtx mem = gen_frame_mem (reg_mode, addr);
 
          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         if (flag_shrink_wrap)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
        }
       for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
        {
@@ -20786,6 +20755,8 @@ rs6000_emit_epilogue (int sibcall)
          rtx mem = gen_frame_mem (V4SImode, addr);
 
          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         if (flag_shrink_wrap)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
        }
       for (i = 0; info->first_fp_reg_save + i <= 63; i++)
        {
@@ -20799,6 +20770,8 @@ rs6000_emit_epilogue (int sibcall)
                                     ? DFmode : SFmode), addr);
 
          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         if (flag_shrink_wrap)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
        }
       RTVEC_ELT (p, j++)
        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
@@ -20810,8 +20783,14 @@ rs6000_emit_epilogue (int sibcall)
        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
       RTVEC_ELT (p, j++)
        = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
-      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+      insn = emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
 
+      if (flag_shrink_wrap)
+       {
+         REG_NOTES (insn) = cfa_restores;
+         add_reg_note (insn, REG_CFA_DEF_CFA, sp_reg_rtx);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
       return;
     }
 
@@ -20856,9 +20835,10 @@ rs6000_emit_epilogue (int sibcall)
 
            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))
+           if (flag_shrink_wrap
+               || 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);
          }
@@ -20997,7 +20977,7 @@ rs6000_emit_epilogue (int sibcall)
 
            reg = gen_rtx_REG (V4SImode, i);
            emit_move_insn (reg, mem);
-           if (DEFAULT_ABI == ABI_V4)
+           if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
              cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
                                             cfa_restores);
          }
@@ -21047,8 +21027,7 @@ rs6000_emit_epilogue (int sibcall)
       emit_move_insn (cr_save_reg, mem);
     }
 
-  /* Set LR here to try to overlap restores below.  LR is always saved
-     above incoming stack, so it never needs REG_CFA_RESTORE.  */
+  /* Set LR here to try to overlap restores below.  */
   if (restore_lr && restoring_GPRs_inline)
     emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
                    gen_rtx_REG (Pmode, 0));
@@ -21086,7 +21065,7 @@ rs6000_emit_epilogue (int sibcall)
   /* Restore GPRs.  This is done as a PARALLEL if we are using
      the load-multiple instructions.  */
   if (TARGET_SPE_ABI
-      && info->spe_64bit_regs_used != 0
+      && info->spe_64bit_regs_used
       && info->first_gp_reg_save != 32)
     {
       /* Determine whether we can address all of the registers that need
@@ -21110,7 +21089,7 @@ rs6000_emit_epilogue (int sibcall)
          int ool_adjust = (restoring_GPRs_inline
                            ? 0
                            : (info->first_gp_reg_save
-                              - (FIRST_SAVRES_REGISTER+1))*8);
+                              - (FIRST_SAVRES_REGISTER + 1)) * 8);
 
          if (frame_reg_rtx == sp_reg_rtx)
            frame_reg_rtx = gen_rtx_REG (Pmode, 11);
@@ -21141,48 +21120,28 @@ rs6000_emit_epilogue (int sibcall)
                mem = gen_rtx_MEM (V2SImode, addr);
                reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
-               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);
-                 }
+               emit_move_insn (reg, mem);
              }
        }
       else
-       {
-         rtx par;
-
-         par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11),
-                                       0, reg_mode,
-                                       /*savep=*/false, /*gpr=*/true,
-                                       /*lr=*/true);
-         emit_jump_insn (par);
-         /* We don't want anybody else emitting things after we jumped
-            back.  */
-         return;
-       }
+       rs6000_emit_savres_rtx (info, gen_rtx_REG (Pmode, 11),
+                               0, reg_mode,
+                               /*savep=*/false, /*gpr=*/true,
+                               /*lr=*/true);
     }
   else if (!restoring_GPRs_inline)
     {
       /* We are jumping to an out-of-line function.  */
       bool can_use_exit = info->first_fp_reg_save == 64;
-      rtx par;
 
       /* Emit stack reset code if we need it.  */
       if (can_use_exit)
-       rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
-                                sp_offset, can_use_exit);
+       {
+         rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
+                                  sp_offset, can_use_exit);
+         if (info->cr_save_p)
+           rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
+       }
       else
        {
          emit_insn (gen_add3_insn (gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX
@@ -21193,45 +21152,10 @@ rs6000_emit_epilogue (int sibcall)
            sp_offset += info->fp_size;
        }
 
-      par = rs6000_make_savres_rtx (info, frame_reg_rtx,
-                                   info->gp_save_offset, reg_mode,
-                                   /*savep=*/false, /*gpr=*/true,
-                                   /*lr=*/can_use_exit);
-
-      if (can_use_exit)
-       {
-         if (info->cr_save_p)
-           {
-             rs6000_restore_saved_cr (cr_save_reg, 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);
-
-         /* We don't want anybody else emitting things after we jumped
-            back.  */
-         return;
-       }
-
-      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);
-       }
+      rs6000_emit_savres_rtx (info, frame_reg_rtx,
+                             info->gp_save_offset, reg_mode,
+                             /*savep=*/false, /*gpr=*/true,
+                             /*lr=*/can_use_exit);
     }
   else if (using_load_multiple)
     {
@@ -21247,17 +21171,8 @@ rs6000_emit_epilogue (int sibcall)
          rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
          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
     {
@@ -21271,24 +21186,70 @@ rs6000_emit_epilogue (int sibcall)
             rtx mem = gen_frame_mem (reg_mode, addr);
            rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
-           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);
-             }
+           emit_move_insn (reg, mem);
           }
     }
 
+  if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+    {
+      /* If the frame pointer was used then we can't delay emitting
+        a REG_CFA_DEF_CFA note.  This must happen on the insn that
+        restores the frame pointer, r31.  We may have already emitted
+        a REG_CFA_DEF_CFA note, but that's OK;  A duplicate is
+        discarded by dwarf2cfi.c/dwarf2out.c, and in any case would
+        be harmless if emitted.  */
+      if (frame_pointer_needed)
+       {
+         insn = get_last_insn ();
+         add_reg_note (insn, REG_CFA_DEF_CFA,
+                       plus_constant (frame_reg_rtx, sp_offset));
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+
+      /* Set up cfa_restores.  We always need these when
+        shrink-wrapping.  If not shrink-wrapping then we only need
+        the cfa_restore when the stack location is no longer valid.
+        The cfa_restores must be emitted on or before the insn that
+        invalidates the stack, and of course must not be emitted
+        before the insn that actually does the restore.  The latter
+        is why the LR cfa_restore condition below is a little
+        complicated.  It's also why it is a bad idea to emit the
+        cfa_restores as a group on the last instruction here that
+        actually does a restore: That insn may be reordered with
+        respect to others doing restores.  */
+      if (info->cr_save_p)
+       cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                      gen_rtx_REG (SImode, CR2_REGNO),
+                                      cfa_restores);
+      if (flag_shrink_wrap
+         && (restore_lr
+             || (info->lr_save_p
+                 && !restoring_GPRs_inline
+                 && info->first_fp_reg_save == 64)))
+       cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                      gen_rtx_REG (Pmode, LR_REGNO),
+                                      cfa_restores);
+
+      for (i = info->first_gp_reg_save; i < 32; i++)
+       if (!restoring_GPRs_inline
+           || using_load_multiple
+           || rs6000_reg_live_or_pic_offset_p (i))
+         {
+           rtx reg = gen_rtx_REG (reg_mode, i);
+
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+         }
+    }
+
+  if (!restoring_GPRs_inline
+      && info->first_fp_reg_save == 64)
+    {
+      /* We are jumping to an out-of-line function.  */
+      if (cfa_restores)
+       emit_cfa_restores (cfa_restores);
+      return;
+    }
+
   if (restore_lr && !restoring_GPRs_inline)
     {
       rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
@@ -21302,8 +21263,8 @@ rs6000_emit_epilogue (int sibcall)
   /* Restore fpr's if we need to do it without calling a function.  */
   if (restoring_FPRs_inline)
     for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-      if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
-          && ! call_used_regs[info->first_fp_reg_save+i]))
+      if ((df_regs_ever_live_p (info->first_fp_reg_save + i)
+          && !call_used_regs[info->first_fp_reg_save + i]))
        {
          rtx addr, mem, reg;
          addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
@@ -21317,20 +21278,13 @@ rs6000_emit_epilogue (int sibcall)
                             info->first_fp_reg_save + i);
 
          emit_move_insn (reg, mem);
-         if (DEFAULT_ABI == ABI_V4)
-           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                          cfa_restores);
+         if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+           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 (cr_save_reg, using_mtcr_multiple);
-      if (DEFAULT_ABI == ABI_V4)
-       cfa_restores
-         = alloc_reg_note (REG_CFA_RESTORE, gen_rtx_REG (SImode, CR2_REGNO),
-                           cfa_restores);
-    }
+    rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
 
   /* If this is V.4, unwind the stack pointer after all of the loads
      have been done.  */
@@ -21358,15 +21312,40 @@ rs6000_emit_epilogue (int sibcall)
       rtvec p;
       bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
       if (! restoring_FPRs_inline)
-       p = rtvec_alloc (4 + 64 - info->first_fp_reg_save);
+       {
+         p = rtvec_alloc (4 + 64 - info->first_fp_reg_save);
+         RTVEC_ELT (p, 0) = ret_rtx;
+       }
       else
-       p = rtvec_alloc (2);
+       {
+         if (cfa_restores)
+           {
+             /* We can't hang the cfa_restores off a simple return,
+                since the shrink-wrap code sometimes uses an existing
+                return.  This means there might be a path from
+                pre-prologue code to this return, and dwarf2cfi code
+                wants the eh_frame unwinder state to be the same on
+                all paths to any point.  So we need to emit the
+                cfa_restores before the return.  For -m64 we really
+                don't need epilogue cfa_restores at all, except for
+                this irritating dwarf2cfi with shrink-wrap
+                requirement;  The stack red-zone means eh_frame info
+                from the prologue telling the unwinder to restore
+                from the stack is perfectly good right to the end of
+                the function.  */
+             emit_insn (gen_blockage ());
+             emit_cfa_restores (cfa_restores);
+             cfa_restores = NULL_RTX;
+           }
+         p = rtvec_alloc (2);
+         RTVEC_ELT (p, 0) = simple_return_rtx;
+       }
 
-      RTVEC_ELT (p, 0) = ret_rtx;
       RTVEC_ELT (p, 1) = ((restoring_FPRs_inline || !lr)
-                         ? gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 65))
+                         ? gen_rtx_USE (VOIDmode,
+                                        gen_rtx_REG (Pmode, LR_REGNO))
                          : gen_rtx_CLOBBER (VOIDmode,
-                                            gen_rtx_REG (Pmode, 65)));
+                                            gen_rtx_REG (Pmode, LR_REGNO)));
 
       /* If we have to restore more than two FP registers, branch to the
         restore function.  It will return to our caller.  */
@@ -21375,6 +21354,12 @@ rs6000_emit_epilogue (int sibcall)
          int i;
          rtx sym;
 
+         if ((DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+             && lr)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                          gen_rtx_REG (Pmode, LR_REGNO),
+                                          cfa_restores);
+
          sym = rs6000_savres_routine_sym (info,
                                           /*savep=*/false,
                                           /*gpr=*/false,
@@ -21386,20 +21371,32 @@ rs6000_emit_epilogue (int sibcall)
                                                       ? 1 : 11));
          for (i = 0; i < 64 - info->first_fp_reg_save; i++)
            {
-             rtx addr, mem;
+             rtx addr, mem, reg;
+
              addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
-                                  GEN_INT (info->fp_save_offset + 8*i));
+                                  GEN_INT (info->fp_save_offset + 8 * i));
              mem = gen_frame_mem (DFmode, addr);
+             reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
 
-             RTVEC_ELT (p, i+4) =
-               gen_rtx_SET (VOIDmode,
-                            gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
-                            mem);
+             RTVEC_ELT (p, i + 4) = gen_rtx_SET (VOIDmode, reg, mem);
+             if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+               cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                              cfa_restores);
            }
        }
 
       emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
     }
+
+  if (cfa_restores)
+    {
+      if (sibcall)
+       /* Ensure the cfa_restores are hung off an insn that won't
+          be reordered above other restores.  */
+       emit_insn (gen_blockage ());
+
+      emit_cfa_restores (cfa_restores);
+    }
 }
 
 /* Write function epilogue.  */
@@ -21764,7 +21761,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                        gen_rtx_USE (VOIDmode,
                                     gen_rtx_REG (SImode,
                                                  LR_REGNO)),
-                       ret_rtx)));
+                       simple_return_rtx)));
   SIBLING_CALL_P (insn) = 1;
   emit_barrier ();