we've been building the FPR routines for ages (for compatibility with system tools).. This implements their use and also the GPRs - the latter makes an appreciable reduction in code size, the former is neutral for non-fp intensive code but, for example, makes an appreciable reduction to the size of gnat1.

this has been around my local tree for quite a few bootstrap/regtest cycles (incl. Ada and Java).
OK for trunk?
Iain

gcc:

* config/rs6000/t-darwin (LIB2FUNCS_STATIC_EXTRA): Move darwin- fpsave.asm from here to ... LIB2FUNCS_EXTRA. (LIB2FUNCS_EXTRA): Add darwin- gpsave.asm.
        (TARGET_LIBGCC2_CFLAGS): Ensure that fPIC and -pipe are inherited from
        config/t-darwin.
        * config/rs6000/darwin.h (FP_SAVE_INLINE): Adjust to enable.
        (GP_SAVE_INLINE): Likewise.
(SAVE_FP_PREFIX, SAVE_FP_SUFFIX, RESTORE_FP_PREFIX, RESTORE_FP_SUFFIX):
        Set to empty strings.
* config/rs6000/rs6000.c (rs6000_savres_strategy): Implement for Darwin.
        (debug_stack_info): Print savres_strategy.
        (rs6000_savres_routine_name): Implement for Darwin.
        (rs6000_make_savres_rtx): Adjust used register for Darwin.
        (rs6000_emit_prologue): Implement out-of-line saves for Darwin.
(rs6000_output_function_prologue): Do not emit .extern for Mach-O targets.
        (rs6000_emit_epilogue): Implement out-of-line saves for Darwin.
        * config/rs6000/darwin-gpsave.asm: New file.

Index: gcc/config/rs6000/t-darwin
===================================================================
--- gcc/config/rs6000/t-darwin  (revision 179962)
+++ gcc/config/rs6000/t-darwin  (working copy)
@@ -19,21 +19,21 @@
 
 LIB2FUNCS_EXTRA = $(srcdir)/config/rs6000/darwin-tramp.asm \
        $(srcdir)/config/darwin-64.c \
+       $(srcdir)/config/rs6000/darwin-fpsave.asm  \
+       $(srcdir)/config/rs6000/darwin-gpsave.asm  \
        $(srcdir)/config/rs6000/darwin-world.asm
 
 LIB2FUNCS_STATIC_EXTRA = \
-       $(srcdir)/config/rs6000/darwin-fpsave.asm  \
        $(srcdir)/config/rs6000/darwin-vecsave.asm
 
-# The .asm files above are designed to run on all processors,
-# even though they use AltiVec instructions.  -Wa is used because
-# -force_cpusubtype_ALL doesn't work with -dynamiclib.
-#
-# -pipe because there's an assembler bug, 4077127, which causes
-# it to not properly process the first # directive, causing temporary
-# file names to appear in stabs, causing the bootstrap to fail.  Using -pipe
-# works around this by not having any temporary file names.
-TARGET_LIBGCC2_CFLAGS = -Wa,-force_cpusubtype_ALL -pipe 
-mmacosx-version-min=10.4
+# The .asm files above are designed to run on all processors, even though
+# they use AltiVec instructions.
+# -Wa is used because -force_cpusubtype_ALL doesn't work with -dynamiclib.
+# -mmacosx-version-min=10.4 is used to provide compatibility for code from
+# earlier OSX versions.
 
+TARGET_LIBGCC2_CFLAGS += -Wa,-force_cpusubtype_ALL -mmacosx-version-min=10.4
+
 darwin-fpsave.o:       $(srcdir)/config/rs6000/darwin-asm.h
+darwin-gpsave.o:       $(srcdir)/config/rs6000/darwin-asm.h
 darwin-tramp.o:                $(srcdir)/config/rs6000/darwin-asm.h
Index: gcc/config/rs6000/darwin.h
===================================================================
--- gcc/config/rs6000/darwin.h  (revision 179962)
+++ gcc/config/rs6000/darwin.h  (working copy)
@@ -173,18 +173,27 @@ extern int darwin_emit_branch_islands;
   (RS6000_ALIGN (crtl->outgoing_args_size, 16)         \
    + (STACK_POINTER_OFFSET))
 
-/* Define cutoff for using external functions to save floating point.
-   Currently on Darwin, always use inline stores.  */
+/* Define cutoff for using out-of-line functions to save registers.
+   Currently on Darwin, we implement FP and GPR out-of-line-saves plus the
+   special routine for 'save everything'.  */
 
-#undef FP_SAVE_INLINE
-#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 64)
+#undef FP_SAVE_INLINE
+#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) > 60 && (FIRST_REG) < 64)
+
 #undef GP_SAVE_INLINE
-#define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32)
+#define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) > 29 && (FIRST_REG) < 32)
 
 /* Darwin uses a function call if everything needs to be saved/restored.  */
+
 #undef WORLD_SAVE_P
 #define WORLD_SAVE_P(INFO) ((INFO)->world_save_p)
 
+/* We don't use these on Darwin, they are just place-holders.  */
+#define SAVE_FP_PREFIX ""
+#define SAVE_FP_SUFFIX ""
+#define RESTORE_FP_PREFIX ""
+#define RESTORE_FP_SUFFIX ""
+
 /* The assembler wants the alternate register names, but without
    leading percent sign.  */
 #undef REGISTER_NAMES
@@ -234,12 +243,6 @@ extern int darwin_emit_branch_islands;
 #undef ASM_COMMENT_START
 #define ASM_COMMENT_START ";"
 
-/* FP save and restore routines.  */
-#define        SAVE_FP_PREFIX "._savef"
-#define SAVE_FP_SUFFIX ""
-#define        RESTORE_FP_PREFIX "._restf"
-#define RESTORE_FP_SUFFIX ""
-
 /* This is how to output an assembler line that says to advance
    the location counter to a multiple of 2**LOG bytes using the
    "nop" instruction as padding.  */
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 179962)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -18047,9 +18047,11 @@ rs6000_savres_strategy (rs6000_stack_t *info,
 
   /* Don't bother to try to save things out-of-line if r11 is occupied
      by the static chain.  It would require too much fiddling and the
-     static chain is rarely used anyway.  */
+     static chain is rarely used anyway.  FPRs are saved w.r.t the stack
+     pointer on Darwin.  */
   if (using_static_chain_p)
-    strategy |= SAVE_INLINE_FPRS | SAVE_INLINE_GPRS;
+    strategy |= (DEFAULT_ABI == ABI_DARWIN ? 0 : SAVE_INLINE_FPRS)
+               | SAVE_INLINE_GPRS;
 
   /* If we are going to use store multiple, then don't even bother
      with the out-of-line routines, since the store-multiple
@@ -18097,6 +18099,9 @@ rs6000_savres_strategy (rs6000_stack_t *info,
   if (TARGET_AIX && !(strategy & REST_INLINE_FPRS))
     strategy |= REST_NOINLINE_FPRS_DOESNT_RESTORE_LR;
 #endif
+  if (TARGET_MACHO && !(strategy & SAVE_INLINE_FPRS))
+    strategy |= SAVE_NOINLINE_FPRS_SAVES_LR;
+
   return strategy;
 }
 
@@ -18692,6 +18697,8 @@ debug_stack_info (rs6000_stack_t *info)
   if (info->reg_size != 4)
     fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
 
+    fprintf (stderr, "\tsave-strategy       =  %04x\n", info->savres_strategy);
+
   fprintf (stderr, "\n");
 }
 
@@ -19637,10 +19644,25 @@ rs6000_savres_routine_name (rs6000_stack_t *info,
          suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
        }
     }
-  else if (DEFAULT_ABI == ABI_DARWIN)
-    sorry ("out-of-line save/restore routines not supported on Darwin");
 
-  sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
+   if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      /* The Darwin approach is (slightly) different, in order to be
+        compatible with code generated by the system toolchain.  There is a
+        single symbol for the start of save sequence, and the code here
+        embeds an offset into that code on the basis of the first register
+        to be saved.  */
+      prefix = savep ? "save" : "rest" ;
+      if (gpr)
+       sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31",
+              prefix, (lr ? "x" : ""), (regno == 13 ? "" : "+"),
+              (regno-13) * 4, prefix, regno);
+      else
+       sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31",
+              prefix, (regno == 14 ? "" : "+"),  (regno-14) * 4, prefix, 
regno);
+    }
+  else
+    sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
 
   return savres_routine_name;
 }
@@ -19739,7 +19761,7 @@ rs6000_make_savres_rtx (rs6000_stack_t *info,
                        bool savep, bool gpr, bool lr)
 {
   int i;
-  int offset, start_reg, end_reg, n_regs;
+  int offset, start_reg, end_reg, n_regs, use_reg;
   int reg_size = GET_MODE_SIZE (reg_mode);
   rtx sym;
   rtvec p;
@@ -19760,11 +19782,12 @@ rs6000_make_savres_rtx (rs6000_stack_t *info,
 
   sym = rs6000_savres_routine_sym (info, savep, gpr, lr);
   RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym);
+  use_reg = DEFAULT_ABI == ABI_AIX ? (gpr && !lr ? 12 : 1)
+                                  : DEFAULT_ABI == ABI_DARWIN && !gpr ? 1
+                                                                      : 11;
   RTVEC_ELT (p, offset++)
     = gen_rtx_USE (VOIDmode,
-                  gen_rtx_REG (Pmode, DEFAULT_ABI != ABI_AIX ? 11
-                                      : gpr && !lr ? 12
-                                      : 1));
+                  gen_rtx_REG (Pmode, use_reg));
 
   for (i = 0; i < end_reg - start_reg; i++)
     {
@@ -20207,8 +20230,21 @@ rs6000_emit_prologue (void)
     {
       rtx par;
 
+      if (DEFAULT_ABI == ABI_DARWIN)
+       {
+         rtx dest_reg = gen_rtx_REG (reg_mode, 11);
+         if (info->first_fp_reg_save == 64)
+           /* we only need a copy, no fprs were saved.  */
+           emit_move_insn (dest_reg, frame_reg_rtx);
+         else
+           {
+             rtx offset = GEN_INT (sp_offset
+                                   + (-8 * (64-info->first_fp_reg_save)));
+             emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset));
+           }
+       }
       /* Need to adjust r11 (r12) if we saved any FPRs.  */
-      if (info->first_fp_reg_save != 64)
+      else if (info->first_fp_reg_save != 64)
         {
          rtx dest_reg = gen_rtx_REG (reg_mode, DEFAULT_ABI == ABI_AIX
                                      ? 12 : 11);
@@ -20575,7 +20611,8 @@ rs6000_output_function_prologue (FILE *file,
 
   /* Write .extern for any function we will call to save and restore
      fp values.  */
-  if (info->first_fp_reg_save < 64)
+  if (info->first_fp_reg_save < 64
+      && !TARGET_MACHO)
     {
       char *name;
       int regno = info->first_fp_reg_save - 32;
@@ -21186,8 +21223,13 @@ rs6000_emit_epilogue (int sibcall)
 
       /* Emit stack reset code if we need it.  */
       if (can_use_exit)
-       rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
+       {
+         rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
                                 sp_offset, can_use_exit);
+         if (DEFAULT_ABI == ABI_DARWIN)
+           /* we only need a copy, no fprs were saved.  */
+           emit_move_insn (gen_rtx_REG (reg_mode, 11), frame_reg_rtx);
+       }
       else
        {
          emit_insn (gen_add3_insn (gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX
Index: gcc/config/rs6000/darwin-gpsave.asm
===================================================================
--- gcc/config/rs6000/darwin-gpsave.asm (revision 0)
+++ gcc/config/rs6000/darwin-gpsave.asm (revision 0)
@@ -0,0 +1,118 @@
+/*  This file contains the GPR save and restore routines for Darwin.
+ *
+ *   Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Under Section 7 of GPL version 3, you are granted additional
+ * permissions described in the GCC Runtime Library Exception, version
+ * 3.1, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License and
+ * a copy of the GCC Runtime Library Exception along with this program;
+ * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/* Contributed by Iain Sandoe  <ia...@gcc.gnu.org> */
+
+/* Like their FP and VEC counterparts, these routines have only one externally
+   visible entry point.  Calls have to be constructed as offsets from this.
+   (I.E. callers have to jump to "saveGPR+((x-13)*4" to save registers x..31).
+
+   Each save/load instruction is 4 bytes long (for both m32 and m64 builds).
+
+   The save/restores here are done w.r.t r11.
+
+   restGPRx restores the link reg from the stack and returns to the saved
+   address.
+
+   */
+
+#include "darwin-asm.h"
+
+       .text
+       .align 2
+
+       .private_extern saveGPR
+saveGPR:
+       stg r13,(-19 * GPR_BYTES)(r11)
+       stg r14,(-18 * GPR_BYTES)(r11)
+       stg r15,(-17 * GPR_BYTES)(r11)
+       stg r16,(-16 * GPR_BYTES)(r11)
+       stg r17,(-15 * GPR_BYTES)(r11)
+       stg r18,(-14 * GPR_BYTES)(r11)
+       stg r19,(-13 * GPR_BYTES)(r11)
+       stg r20,(-12 * GPR_BYTES)(r11)
+       stg r21,(-11 * GPR_BYTES)(r11)
+       stg r22,(-10 * GPR_BYTES)(r11)
+       stg r23,( -9 * GPR_BYTES)(r11)
+       stg r24,( -8 * GPR_BYTES)(r11)
+       stg r25,( -7 * GPR_BYTES)(r11)
+       stg r26,( -6 * GPR_BYTES)(r11)
+       stg r27,( -5 * GPR_BYTES)(r11)
+       stg r28,( -4 * GPR_BYTES)(r11)
+       stg r29,( -3 * GPR_BYTES)(r11)
+       stg r30,( -2 * GPR_BYTES)(r11)
+       stg r31,( -1 * GPR_BYTES)(r11)
+       blr
+
+/* */
+
+       .private_extern restGPR
+restGPR:
+       lg r13,(-19 * GPR_BYTES)(r11)
+       lg r14,(-18 * GPR_BYTES)(r11)
+       lg r15,(-17 * GPR_BYTES)(r11)
+       lg r16,(-16 * GPR_BYTES)(r11)
+       lg r17,(-15 * GPR_BYTES)(r11)
+       lg r18,(-14 * GPR_BYTES)(r11)
+       lg r19,(-13 * GPR_BYTES)(r11)
+       lg r20,(-12 * GPR_BYTES)(r11)
+       lg r21,(-11 * GPR_BYTES)(r11)
+       lg r22,(-10 * GPR_BYTES)(r11)
+       lg r23,( -9 * GPR_BYTES)(r11)
+       lg r24,( -8 * GPR_BYTES)(r11)
+       lg r25,( -7 * GPR_BYTES)(r11)
+       lg r26,( -6 * GPR_BYTES)(r11)
+       lg r27,( -5 * GPR_BYTES)(r11)
+       lg r28,( -4 * GPR_BYTES)(r11)
+       lg r29,( -3 * GPR_BYTES)(r11)
+       lg r30,( -2 * GPR_BYTES)(r11)
+       lg r31,( -1 * GPR_BYTES)(r11)
+       blr
+
+       .private_extern restGPRx
+restGPRx:
+       lg r13,(-19 * GPR_BYTES)(r11)
+       lg r14,(-18 * GPR_BYTES)(r11)
+       lg r15,(-17 * GPR_BYTES)(r11)
+       lg r16,(-16 * GPR_BYTES)(r11)
+       lg r17,(-15 * GPR_BYTES)(r11)
+       lg r18,(-14 * GPR_BYTES)(r11)
+       lg r19,(-13 * GPR_BYTES)(r11)
+       lg r20,(-12 * GPR_BYTES)(r11)
+       lg r21,(-11 * GPR_BYTES)(r11)
+       lg r22,(-10 * GPR_BYTES)(r11)
+       lg r23,( -9 * GPR_BYTES)(r11)
+       lg r24,( -8 * GPR_BYTES)(r11)
+       lg r25,( -7 * GPR_BYTES)(r11)
+       lg r26,( -6 * GPR_BYTES)(r11)
+       lg r27,( -5 * GPR_BYTES)(r11)
+       lg r28,( -4 * GPR_BYTES)(r11)
+       lg r29,( -3 * GPR_BYTES)(r11)
+       /* Like the FP restore, we start from the offset for r30
+          thus a restore of only r31 is not going to work.  */
+       lg r0,SAVED_LR_OFFSET(r1)
+       lg r30,( -2 * GPR_BYTES)(r11)
+       mtlr r0
+       lg r31,( -1 * GPR_BYTES)(r11)
+       blr



Reply via email to