V.4 support.
authorMichael Meissner <meissner@gcc.gnu.org>
Fri, 21 Jul 1995 18:15:38 +0000 (18:15 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Fri, 21 Jul 1995 18:15:38 +0000 (18:15 +0000)
From-SVN: r10152

13 files changed:
gcc/config/rs6000/aix3newas.h
gcc/config/rs6000/eabi.asm
gcc/config/rs6000/eabi.h
gcc/config/rs6000/eabiaix.h [new file with mode: 0644]
gcc/config/rs6000/eabile.h
gcc/config/rs6000/milli.exp [new file with mode: 0644]
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md
gcc/config/rs6000/sysv4.h
gcc/config/rs6000/sysv4le.h
gcc/config/rs6000/t-ppcgas
gcc/config/rs6000/t-rs6000

index 100d4da..31c0fd3 100644 (file)
@@ -47,6 +47,29 @@ Boston, MA 02111-1307, USA.  */
 %{mcpu=603: -mppc} \
 %{mcpu=604: -mppc}"
 
+/* Define the options for the binder: Start text at 512, align all segments
+   to 512 bytes, and warn if there is text relocation.
+
+   The -bhalt:4 option supposedly changes the level at which ld will abort,
+   but it also suppresses warnings about multiply defined symbols and is
+   used by the AIX cc command.  So we use it here.
+
+   -bnodelcsect undoes a poor choice of default relating to multiply-defined
+   csects.  See AIX documentation for more information about this.
+
+   -bM:SRE tells the linker that the output file is Shared REusable.  Note
+   that to actually build a shared library you will also need to specify an
+   export list with the -Wl,-bE option.
+
+   If -mcpu=common, export the architecture dependent multiply/divide routines
+   as per README.RS6000.  */
+
+#undef LINK_SPEC
+#define LINK_SPEC "-T512 -H512 %{!r:-btextro} -bhalt:4 -bnodelcsect\
+   %{static:-bnso -bI:/lib/syscalls.exp} \
+   %{mcpu=common: milli.exp%s} \
+   %{!shared:%{g*:-bexport:/usr/lib/libg.exp}} %{shared:-bM:SRE}"
+
 /* These are not necessary when we pass -u to the assembler, and undefining
    them saves a great deal of space in object files.  */
 
index a26c730..d775a21 100644 (file)
 .Lgot2e = .-.LCTOC1
        .long   _GOT2_END_                      # -mrelocatable GOT pointers end
 
+.Lfixups = .-.LCTOC1
+       .long   _FIXUP_START_                   # start of .fixup section
+
+.Lfixupe = .-.LCTOC1
+       .long   _FIXUP_END_                     # end of .fixup section
+
        .text
 .Lptr:
        .long   .LCTOC1-.Laddr                  # PC relative pointer to .got2
@@ -64,16 +70,36 @@ __eabi:     mflr    0
        add     4,12,4
 
        cmpw    1,3,4                           # any pointers to adjust
-       bc      12,6,.Ldone
+       bc      12,6,.Lfix
 
 .Lloop:
-       lwz     11,0(3)                         # next pointer
-       add     11,11,12                        # adjust
-       stw     11,0(3)
+       lwz     5,0(3)                          # next pointer
+       add     5,5,12                          # adjust
+       stw     5,0(3)
        addi    3,3,4                           # bump to next word
        cmpw    1,3,4                           # more pointers to adjust?
        bc      4,6,.Lloop
 
+# Fixup any user initialized pointers now (the compiler drops pointers to
+# each of the relocs that it does in the .fixup section).  Note, the pointers
+# themselves have already been fixed up by the previous loop.
+
+.Lfix:
+       lwz     3,.Lfixups(11)                  # fixup pointers start
+       lwz     4,.Lfixupe(11)                  # fixup pointers end
+
+       cmpw    1,3,4                           # any user pointers to adjust
+       bc      12,6,.Ldone
+
+.Lfloop:
+       lwz     5,0(3)                          # next pointer
+       lwz     6,0(5)                          # get the pointer it points to
+       add     6,6,12                          # adjust
+       stw     6,0(5)
+       addi    3,3,4                           # bump to next word
+       cmpw    1,3,4                           # more pointers to adjust?
+       bc      4,6,.Lfloop
+
 # Done adjusting pointers, return
 
 .Ldone:
index 88a9b5d..829a180 100644 (file)
@@ -50,6 +50,11 @@ Boston, MA 02111-1307, USA.  */
 #define MINIMAL_TOC_SECTION_ASM_OP \
   ((TARGET_RELOCATABLE) ? "\t.section\t\".got2\",\"aw\"" : "\t.section\t\".got1\",\"aw\"")
 
+/* Put relocatable data in .data, not .rodata so initialized pointers can be updated */
+#undef CONST_SECTION_ASM_OP
+#define CONST_SECTION_ASM_OP \
+  ((TARGET_RELOCATABLE) ? "\t.section\t\".data\"\t# .rodata" : "\t.section\t\".rodata\"")
+
 /* Invoke an initializer function to set up the GOT */
 #define NAME__MAIN "__eabi"
 #define INVOKE__main 1
@@ -74,3 +79,43 @@ Boston, MA 02111-1307, USA.  */
 #undef ENDFILE_SPEC
 #define        ENDFILE_SPEC ""
 
+/* This is how to output an assembler line defining an `int' constant.
+   For -mrelocatable, we mark all addresses that need to be fixed up
+   in the .fixup section.  */
+#undef ASM_OUTPUT_INT
+#define ASM_OUTPUT_INT(FILE,VALUE)                                     \
+do {                                                                   \
+  static int recurse = 0;                                              \
+  if (TARGET_RELOCATABLE                                               \
+      && in_section != in_toc                                          \
+      && in_section != in_text                                         \
+      && in_section != in_ctors                                                \
+      && in_section != in_dtors                                                \
+      && !recurse                                                      \
+      && GET_CODE (VALUE) != CONST_INT                                 \
+      && GET_CODE (VALUE) != CONST_DOUBLE)                             \
+    {                                                                  \
+      static int labelno = 0;                                          \
+      char buf[256], *p;                                               \
+                                                                       \
+      recurse = 1;                                                     \
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", labelno++);             \
+      STRIP_NAME_ENCODING (p, buf);                                    \
+      fprintf (FILE, "%s:\n", p);                                      \
+      fprintf (FILE, "\t.long (");                                     \
+      output_addr_const (FILE, (VALUE));                               \
+      fprintf (FILE, ")@fixup\n");                                     \
+      fprintf (FILE, "\t.section\t\".fixup\",\"aw\"\n");               \
+      ASM_OUTPUT_ALIGN (FILE, 2);                                      \
+      fprintf (FILE, "\t.long\t%s\n", p);                              \
+      fprintf (FILE, "\t.previous\n");                                 \
+      recurse = 0;                                                     \
+    }                                                                  \
+  else                                                                 \
+    {                                                                  \
+      fprintf (FILE, "\t.long ");                                      \
+      output_addr_const (FILE, (VALUE));                               \
+      fprintf (FILE, "\n");                                            \
+    }                                                                  \
+} while (0)
+
diff --git a/gcc/config/rs6000/eabiaix.h b/gcc/config/rs6000/eabiaix.h
new file mode 100644 (file)
index 0000000..6e92d17
--- /dev/null
@@ -0,0 +1,53 @@
+/* Embedded ELF system support, using old AIX based calling sequence.
+   Copyright (C) 1995 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC 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 2, or (at your option)
+any later version.
+
+GNU CC 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.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "rs6000/eabi.h"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_AIX_CALLS)
+
+#undef CPP_SPEC
+#define CPP_SPEC "\
+%{posix: -D_POSIX_SOURCE} \
+%{mrelocatable: -D_RELOCATABLE} \
+%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_AIX}} \
+%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
+%{mlittle: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
+%{mlittle-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
+%{!mlittle: %{!mlittle-endian: -D_BIG_ENDIAN -Amachine(bigendian)}} \
+%{!mcpu*: \
+  %{mpower: %{!mpower2: -D_ARCH_PWR}} \
+  %{mpower2: -D_ARCH_PWR2} \
+  %{mpowerpc*: -D_ARCH_PPC} \
+  %{mno-powerpc: %{!mpower: %{!mpower2: -D_ARCH_COM}}} \
+  %{!mno-powerpc: -D_ARCH_PPC}} \
+%{mcpu=common: -D_ARCH_COM} \
+%{mcpu=power: -D_ARCH_PWR} \
+%{mcpu=powerpc: -D_ARCH_PPC} \
+%{mcpu=rios: -D_ARCH_PWR} \
+%{mcpu=rios1: -D_ARCH_PWR} \
+%{mcpu=rios2: -D_ARCH_PWR2} \
+%{mcpu=rsc: -D_ARCH_PWR} \
+%{mcpu=rsc1: -D_ARCH_PWR} \
+%{mcpu=403: -D_ARCH_PPC} \
+%{mcpu=601: -D_ARCH_PPC -D_ARCH_PWR} \
+%{mcpu=603: -D_ARCH_PPC} \
+%{mcpu=604: -D_ARCH_PPC}"
index 79d043a..11ff65e 100644 (file)
@@ -29,6 +29,8 @@ Boston, MA 02111-1307, USA.  */
 #define CPP_SPEC "\
 %{posix: -D_POSIX_SOURCE} \
 %{mrelocatable: -D_RELOCATABLE} \
+%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_SYSV}} \
+%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
 %{mbig: -D_BIG_ENDIAN -Amachine(bigendian)} \
 %{mbig-endian: -D_BIG_ENDIAN -Amachine(bigendian)} \
 %{!mbig: %{!mbig-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)}} \
diff --git a/gcc/config/rs6000/milli.exp b/gcc/config/rs6000/milli.exp
new file mode 100644 (file)
index 0000000..ea3a2b7
--- /dev/null
@@ -0,0 +1,7 @@
+#!
+__mulh          0x3100
+__mull          0x3180
+__divss         0x3200
+__divus         0x3280
+__quoss         0x3300
+__quous         0x3380
index 47a005b..424b025 100644 (file)
@@ -70,6 +70,9 @@ int rs6000_compare_fp_p;
    get the address of the GOT section */
 int rs6000_pic_labelno;
 #endif
+
+/* Whether a System V.4 varargs area was created.  */
+int rs6000_sysv_varargs_p;
 \f
 /* Override command line options.  Mostly we process the processor
    type and sometimes adjust other TARGET_ options.  */
@@ -212,11 +215,18 @@ rs6000_immed_double_const (i0, i1, mode)
 int
 direct_return ()
 {
-  return (reload_completed
-         && first_reg_to_save () == 32
-         && first_fp_reg_to_save () == 64
-         && ! regs_ever_live[65]
-         && ! rs6000_pushes_stack ());
+  if (reload_completed)
+    {
+      rs6000_stack_t *info = rs6000_stack_info ();
+
+      if (info->first_gp_reg_save == 32
+         && info->first_fp_reg_save == 64
+         && !info->lr_save_p
+         && !info->push_p)
+       return 1;
+    }
+
+  return 0;
 }
 
 /* Returns 1 always.  */
@@ -622,6 +632,394 @@ input_operand (op, mode)
   return add_operand (op, mode);
 }
 \f
+/* Initialize a variable CUM of type CUMULATIVE_ARGS
+   for a call to a function whose data type is FNTYPE.
+   For a library call, FNTYPE is 0.
+
+   For incoming args we set the number of arguments in the prototype large
+   so we never return an EXPR_LIST.  */
+
+void
+init_cumulative_args (cum, fntype, libname, incoming)
+     CUMULATIVE_ARGS *cum;
+     tree fntype;
+     rtx libname;
+     int incoming;
+{
+  static CUMULATIVE_ARGS zero_cumulative;
+
+  *cum = zero_cumulative;
+  cum->words = 0;
+  cum->fregno = FP_ARG_MIN_REG;
+  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
+
+  if (incoming)
+    {
+      cum->nargs_prototype = 1000;             /* don't return an EXPR_LIST */
+#ifdef TARGET_V4_CALLS
+      if (TARGET_V4_CALLS)
+       cum->varargs_offset = RS6000_VARARGS_OFFSET;
+#endif
+    }
+
+  else if (cum->prototype)
+    cum->nargs_prototype = (list_length (TYPE_ARG_TYPES (fntype)) - 1
+                           + (TYPE_MODE (TREE_TYPE (fntype)) == BLKmode
+                              || RETURN_IN_MEMORY (TREE_TYPE (fntype))));
+
+  else
+    cum->nargs_prototype = 0;
+
+  cum->orig_nargs = cum->nargs_prototype;
+  if (TARGET_DEBUG_ARG)
+    {
+      fprintf (stderr, "\ninit_cumulative_args:");
+      if (fntype)
+       {
+         tree ret_type = TREE_TYPE (fntype);
+         fprintf (stderr, " ret code = %s,",
+                  tree_code_name[ (int)TREE_CODE (ret_type) ]);
+       }
+
+#ifdef TARGET_V4_CALLS
+      if (TARGET_V4_CALLS && incoming)
+       fprintf (stderr, " varargs = %d, ", cum->varargs_offset);
+#endif
+
+      fprintf (stderr, " proto = %d, nargs = %d\n",
+              cum->prototype, cum->nargs_prototype);
+    }
+}
+\f
+/* Update the data in CUM to advance over an argument
+   of mode MODE and data type TYPE.
+   (TYPE is null for libcalls where that information may not be available.)  */
+
+void
+function_arg_advance (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named;
+{
+  cum->nargs_prototype--;
+
+#ifdef TARGET_V4_CALLS
+  if (TARGET_V4_CALLS)
+    {
+      /* Long longs must not be split between registers and stack */
+      if ((GET_MODE_CLASS (mode) != MODE_FLOAT || TARGET_SOFT_FLOAT)
+         && type && !AGGREGATE_TYPE_P (type)
+         && cum->words < GP_ARG_NUM_REG
+         && cum->words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG)
+       {
+         cum->words = GP_ARG_NUM_REG;
+       }
+
+      /* Aggregates get passed as pointers */
+      if (type && AGGREGATE_TYPE_P (type))
+       cum->words++;
+
+      /* Floats go in registers, & don't occupy space in the GP registers
+        like they do for AIX unless software floating point.  */
+      else if (GET_MODE_CLASS (mode) == MODE_FLOAT
+              && TARGET_HARD_FLOAT
+              && cum->fregno <= FP_ARG_V4_MAX_REG)
+       cum->fregno++;
+
+      else
+       cum->words += RS6000_ARG_SIZE (mode, type, 1);
+    }
+  else
+#endif
+    if (named)
+      {
+       cum->words += RS6000_ARG_SIZE (mode, type, named);
+       if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)
+         cum->fregno++;
+      }
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr,
+            "function_adv: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d\n",
+            cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named);
+}
+\f
+/* Determine where to put an argument to a function.
+   Value is zero to push the argument on the stack,
+   or a hard register in which to store the argument.
+
+   MODE is the argument's machine mode.
+   TYPE is the data type of the argument (as a tree).
+    This is null for libcalls where that information may
+    not be available.
+   CUM is a variable of type CUMULATIVE_ARGS which gives info about
+    the preceding args and about the function being called.
+   NAMED is nonzero if this argument is a named parameter
+    (otherwise it is an extra parameter matching an ellipsis).
+
+   On RS/6000 the first eight words of non-FP are normally in registers
+   and the rest are pushed.  Under AIX, the first 13 FP args are in registers.
+   Under V.4, the first 8 FP args are in registers.
+
+   If this is floating-point and no prototype is specified, we use
+   both an FP and integer register (or possibly FP reg and stack).  Library
+   functions (when TYPE is zero) always have the proper types for args,
+   so we can pass the FP value just in one register.  emit_library_function
+   doesn't support EXPR_LIST anyway.  */
+
+struct rtx_def *
+function_arg (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named;
+{
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr,
+            "function_arg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d\n",
+            cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named);
+
+  /* Return a marker to indicate whether CR1 needs to set or clear the bit that V.4
+     uses to say fp args were passed in registers.  Assume that we don't need the
+     marker for software floating point, or compiler generated library calls.  */
+  if (mode == VOIDmode)
+    {
+#ifdef TARGET_V4_CALLS
+      if (TARGET_V4_CALLS && TARGET_HARD_FLOAT && cum->nargs_prototype < 0
+         && type && (cum->prototype || TARGET_NO_PROTOTYPE))
+       return GEN_INT ((cum->fregno == FP_ARG_MIN_REG) ? -1 : 1);
+#endif
+
+      return GEN_INT (0);
+    }
+
+  if (!named)
+    {
+#ifdef TARGET_V4_CALLS
+      if (!TARGET_V4_CALLS)
+#endif
+       return NULL_RTX;
+    }
+
+  if (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+    return NULL_RTX;
+
+  if (USE_FP_FOR_ARG_P (*cum, mode, type))
+    {
+      if ((cum->nargs_prototype > 0)
+#ifdef TARGET_V4_CALLS
+         || TARGET_V4_CALLS    /* V.4 never passes FP values in GP registers */
+#endif
+         || !type)
+       return gen_rtx (REG, mode, cum->fregno);
+
+      return gen_rtx (EXPR_LIST, VOIDmode,
+                     ((cum->words < GP_ARG_NUM_REG)
+                      ? gen_rtx (REG, mode, GP_ARG_MIN_REG + cum->words)
+                      : NULL_RTX),
+                     gen_rtx (REG, mode, cum->fregno));
+    }
+
+#ifdef TARGET_V4_CALLS
+  /* Long longs won't be split between register and stack */
+  else if (TARGET_V4_CALLS &&
+          cum->words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG)
+    {
+      return NULL_RTX;
+    }
+#endif
+
+  else if (cum->words < GP_ARG_NUM_REG)
+    return gen_rtx (REG, mode, GP_ARG_MIN_REG + cum->words);
+
+  return NULL_RTX;
+}
+\f
+/* For an arg passed partly in registers and partly in memory,
+   this is the number of registers used.
+   For args passed entirely in registers or entirely in memory, zero.  */
+
+int
+function_arg_partial_nregs (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named;
+{
+  if (! named)
+    return 0;
+
+#ifdef TARGET_V4_CALLS
+  if (TARGET_V4_CALLS)
+    return 0;
+#endif
+
+  if (USE_FP_FOR_ARG_P (*cum, mode, type))
+    {
+      if (cum->nargs_prototype >= 0)
+       return 0;
+    }
+
+  if (cum->words < GP_ARG_NUM_REG
+      && GP_ARG_NUM_REG < (cum->words + RS6000_ARG_SIZE (mode, type, named)))
+    {
+      int ret = GP_ARG_NUM_REG - cum->words;
+      if (ret && TARGET_DEBUG_ARG)
+       fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
+
+      return ret;
+    }
+
+  return 0;
+}
+\f
+/* A C expression that indicates when an argument must be passed by
+   reference.  If nonzero for an argument, a copy of that argument is
+   made in memory and a pointer to the argument is passed instead of
+   the argument itself.  The pointer is passed in whatever way is
+   appropriate for passing a pointer to that type.
+
+   Under V.4, structures and unions are passed by reference.  */
+
+int
+function_arg_pass_by_reference (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named;
+{
+#ifdef TARGET_V4_CALLS
+  if (TARGET_V4_CALLS && type && AGGREGATE_TYPE_P (type))
+    {
+      if (TARGET_DEBUG_ARG)
+       fprintf (stderr, "function_arg_pass_by_reference: aggregate\n");
+
+      return 1;
+    }
+#endif
+
+  return 0;
+}
+
+\f
+/* Perform any needed actions needed for a function that is receiving a
+   variable number of arguments. 
+
+   CUM is as above.
+
+   MODE and TYPE are the mode and type of the current parameter.
+
+   PRETEND_SIZE is a variable that should be set to the amount of stack
+   that must be pushed by the prolog to pretend that our caller pushed
+   it.
+
+   Normally, this macro will push all remaining incoming registers on the
+   stack and set PRETEND_SIZE to the length of the registers pushed.  */
+
+void
+setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int *pretend_size;
+     int no_rtl;
+
+{
+  rtx save_area = virtual_incoming_args_rtx;
+  int reg_size = (TARGET_64BIT) ? 8 : 4;
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr,
+            "setup_vararg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, no_rtl= %d\n",
+            cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), no_rtl);
+
+#ifdef TARGET_V4_CALLS
+  if (TARGET_V4_CALLS && !no_rtl)
+    {
+      rs6000_sysv_varargs_p = 1;
+      save_area = plus_constant (frame_pointer_rtx, RS6000_VARARGS_OFFSET);
+    }
+#endif
+
+  if (cum->words < 8)
+    {
+      int first_reg_offset = cum->words;
+
+      if (MUST_PASS_IN_STACK (mode, type))
+       first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);
+
+      if (first_reg_offset > GP_ARG_NUM_REG)
+       first_reg_offset = GP_ARG_NUM_REG;
+
+      if (!no_rtl && first_reg_offset != GP_ARG_NUM_REG)
+       move_block_from_reg
+         (GP_ARG_MIN_REG + first_reg_offset,
+          gen_rtx (MEM, BLKmode,
+                   plus_constant (save_area, first_reg_offset * reg_size)),
+          GP_ARG_NUM_REG - first_reg_offset,
+          (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
+
+      *pretend_size = (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD;
+    }
+
+#ifdef TARGET_V4_CALLS
+  /* Save FP registers if needed.  */
+  if (TARGET_V4_CALLS && TARGET_HARD_FLOAT && !no_rtl)
+    {
+      int fregno     = cum->fregno;
+      int num_fp_reg = FP_ARG_V4_MAX_REG + 1 - fregno;
+
+      if (num_fp_reg >= 0)
+       {
+         rtx cr1 = gen_rtx (REG, CCmode, 69);
+         rtx lab = gen_label_rtx ();
+         int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
+
+         emit_jump_insn (gen_rtx (SET, VOIDmode,
+                                  pc_rtx,
+                                  gen_rtx (IF_THEN_ELSE, VOIDmode,
+                                           gen_rtx (NE, VOIDmode, cr1, const0_rtx),
+                                           gen_rtx (LABEL_REF, VOIDmode, lab),
+                                           pc_rtx)));
+
+         while ( num_fp_reg-- >= 0)
+           {
+             emit_move_insn (gen_rtx (MEM, DFmode, plus_constant (save_area, off)),
+                             gen_rtx (REG, DFmode, fregno++));
+             off += 8;
+           }
+
+         emit_label (lab);
+       }
+    }
+#endif
+}
+\f
+/* If defined, is a C expression that produces the machine-specific
+   code for a call to `__builtin_saveregs'.  This code will be moved
+   to the very beginning of the function, before any parameter access
+   are made.  The return value of this function should be an RTX that
+   contains the value to use as the return of `__builtin_saveregs'.
+
+   The argument ARGS is a `tree_list' containing the arguments that
+   were passed to `__builtin_saveregs'.
+
+   If this macro is not defined, the compiler will output an ordinary
+   call to the library function `__builtin_saveregs'.
+   
+   On the Power/PowerPC return the address of the area on the stack
+   used to hold arguments.  Under AIX, this includes the 8 word register
+   save area.  Under V.4 this does not.  */
+
+struct rtx_def *
+expand_builtin_saveregs (args)
+     tree args;
+{
+  return virtual_incoming_args_rtx;
+}
+
+\f
 /* Expand a block move operation, and return 1 if successful.  Return 0
    if we should let the compiler generate normal code.
 
@@ -1205,7 +1603,7 @@ print_operand (file, x, code)
 
     case '*':
       /* Write the register number of the TOC register.  */
-      fputs (TARGET_MINIMAL_TOC ? "30" : "2", file);
+      fputs (TARGET_MINIMAL_TOC ? reg_names[30] : reg_names[2], file);
       return;
 
     case 'A':
@@ -1633,26 +2031,36 @@ print_operand_address (file, x)
      register rtx x;
 {
   if (GET_CODE (x) == REG)
-    fprintf (file, "0(%d)", REGNO (x));
+    fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
   else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
     {
       output_addr_const (file, x);
       /* When TARGET_MINIMAL_TOC, use the indirected toc table pointer instead
         of the toc pointer.  */
-      if (TARGET_MINIMAL_TOC)
-       fprintf (file, "(30)");
+#ifdef TARGET_NO_TOC
+      if (TARGET_NO_TOC)
+       ;
       else
-       fprintf (file, "(2)");
+#endif
+       fprintf (file, "(%s)", reg_names[ TARGET_MINIMAL_TOC ? 30 : 2 ]);
     }
   else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
     {
       if (REGNO (XEXP (x, 0)) == 0)
-       fprintf (file, "%d,%d", REGNO (XEXP (x, 1)), REGNO (XEXP (x, 0)));
+       fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
+                reg_names[ REGNO (XEXP (x, 0)) ]);
       else
-       fprintf (file, "%d,%d", REGNO (XEXP (x, 0)), REGNO (XEXP (x, 1)));
+       fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
+                reg_names[ REGNO (XEXP (x, 1)) ]);
     }
   else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
-    fprintf (file, "%d(%d)", INTVAL (XEXP (x, 1)), REGNO (XEXP (x, 0)));
+    fprintf (file, "%d(%s)", INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
+  else if (TARGET_ELF && !TARGET_64BIT && GET_CODE (x) == LO_SUM
+          && GET_CODE (XEXP (x, 0)) == REG && CONSTANT_P (XEXP (x, 1)))
+    {
+      output_addr_const (file, XEXP (x, 1));
+      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
+    }
   else
     abort ();
 }
@@ -1678,9 +2086,11 @@ first_reg_to_save ()
      to 23 to do this.  Don't use the frame pointer in reg 31.
 
      For now, save enough room for all of the parameter registers.  */
+#ifndef USING_SVR4_H
   if (profile_flag)
     if (first_reg > 23)
       first_reg = 23;
+#endif
 
   return first_reg;
 }
@@ -1700,31 +2110,6 @@ first_fp_reg_to_save ()
   return first_reg;
 }
 
-/* Return 1 if we need to save CR.  */
-
-int
-must_save_cr ()
-{
-  return regs_ever_live[70] || regs_ever_live[71] || regs_ever_live[72];
-}
-
-/* Compute the size of the save area in the stack, including the space for
-   the fixed area.  */
-
-int
-rs6000_sa_size ()
-{
-  int size;
-
-  /* We have the six fixed words, plus the size of the register save 
-     areas, rounded to a double-word.  */
-  size = 6 + (32 - first_reg_to_save ()) + (64 - first_fp_reg_to_save ()) * 2;
-  if (size & 1)
-    size++;
-
-  return size * 4;
-}
-
 /* Return non-zero if this function makes calls.  */
 
 int
@@ -1743,23 +2128,259 @@ rs6000_makes_calls ()
   return 0;
 }
 
-/* Return non-zero if this function needs to push space on the stack.  */
+\f
+/* Calculate the stack information for the current function.  This is
+   complicated by having two separate calling sequences, the AIX calling
+   sequence and the V.4 calling sequence.
+
+   AIX stack frames look like:
+
+       SP----> +---------------------------------------+
+               | back chain to caller                  | 0
+               +---------------------------------------+
+               | saved CR                              | 4
+               +---------------------------------------+
+               | saved LR                              | 8
+               +---------------------------------------+
+               | reserved for compilers                | 12
+               +---------------------------------------+
+               | reserved for binders                  | 16
+               +---------------------------------------+
+               | saved TOC pointer                     | 20
+               +---------------------------------------+
+               | Parameter save area (P)               | 24
+               +---------------------------------------+
+               | Alloca space (A)                      | 24+P
+               +---------------------------------------+
+               | Local variable space (L)              | 24+P+A
+               +---------------------------------------+
+               | Save area for GP registers (G)        | 24+P+A+L
+               +---------------------------------------+
+               | Save area for FP registers (F)        | 24+P+A+L+G
+               +---------------------------------------+
+       old SP->| back chain to caller's caller         |
+               +---------------------------------------+
+
+   V.4 stack frames look like:
+
+       SP----> +---------------------------------------+
+               | back chain to caller                  | 0
+               +---------------------------------------+
+               | saved LR                              | 4
+               +---------------------------------------+
+               | Parameter save area (P)               | 8
+               +---------------------------------------+
+               | Alloca space (A)                      | 8+P
+               +---------------------------------------+
+               | Varargs save area (V)                 | 8+P+A
+               +---------------------------------------+
+               | Local variable space (L)              | 8+P+A+V
+               +---------------------------------------+
+               | saved CR (C)                          | 8+P+A+V+L
+               +---------------------------------------+
+               | Save area for GP registers (G)        | 8+P+A+V+L+C
+               +---------------------------------------+
+               | Save area for FP registers (F)        | 8+P+A+V+L+C+G
+               +---------------------------------------+
+       old SP->| back chain to caller's caller         |
+               +---------------------------------------+
+*/
 
-int
-rs6000_pushes_stack ()
+rs6000_stack_t *
+rs6000_stack_info ()
 {
-  int total_size = (rs6000_sa_size () + get_frame_size ()
-                   + current_function_outgoing_args_size);
+  static rs6000_stack_t info, zero_info;
+  rs6000_stack_t *info_ptr = &info;
+  int reg_size = TARGET_64BIT ? 8 : 4;
+  int v4_call_p = 0;
+
+  /* Zero all fields portably */
+  info = zero_info;
+
+  /* Select which calling sequence */
+#ifdef TARGET_V4_CALLS
+  if (TARGET_V4_CALLS)
+    info_ptr->v4_call_p = v4_call_p = 1;
+#endif
+
+  /* Calculate which registers need to be saved & save area size */
+  info_ptr->first_gp_reg_save = first_reg_to_save ();
+  info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
+
+  info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
+  info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
 
-  /* We need to push the stack if a frame pointer is needed (because the
-     stack might be dynamically adjusted), if we are debugging, if the
-     total stack size is more than 220 bytes, or if we make calls.  */
+  /* Does this function call anything? */
+  info_ptr->calls_p = rs6000_makes_calls ();
 
-  return (frame_pointer_needed || write_symbols != NO_DEBUG
-         || total_size > 220
-         || rs6000_makes_calls ());
+  /* Determine if we need to save the link register */
+  if (regs_ever_live[65] || profile_flag
+#ifdef TARGET_RELOCATABLE
+      || (TARGET_RELOCATABLE && (get_pool_size () != 0))
+#endif
+      || (info_ptr->first_fp_reg_save != 64
+         && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
+      || (v4_call_p && current_function_calls_alloca)
+      || info_ptr->calls_p)
+    {
+      info_ptr->lr_save_p = 1;
+      regs_ever_live[65] = 1;
+    }
+
+  /* Determine if we need to save the condition code registers */
+  if (regs_ever_live[70] || regs_ever_live[71] || regs_ever_live[72])
+    {
+      info_ptr->cr_save_p = 1;
+      if (v4_call_p)
+       info_ptr->cr_size = reg_size;
+    }
+
+  /* Determine various sizes */
+  info_ptr->reg_size     = reg_size;
+  info_ptr->fixed_size   = RS6000_SAVE_AREA;
+  info_ptr->varargs_size = RS6000_VARARGS_AREA;
+  info_ptr->vars_size    = ALIGN (get_frame_size (), 8);
+  info_ptr->parm_size    = ALIGN (current_function_outgoing_args_size, 8);
+  info_ptr->save_size    = ALIGN (info_ptr->fp_size + info_ptr->gp_size + info_ptr->cr_size, 8);
+  info_ptr->total_size   = ALIGN (info_ptr->vars_size
+                                 + info_ptr->parm_size
+                                 + info_ptr->save_size
+                                 + info_ptr->varargs_size
+                                 + info_ptr->fixed_size, STACK_BOUNDARY / BITS_PER_UNIT);
+
+  /* Determine if we need to allocate any stack frame.
+     For AIX We need to push the stack if a frame pointer is needed (because
+     the stack might be dynamically adjusted), if we are debugging, if the
+     total stack size is more than 220 bytes, or if we make calls.
+
+     For V.4 we don't have the stack cushion that AIX uses, but assume that
+     the debugger can handle stackless frames.  */
+
+  if (info_ptr->calls_p)
+    info_ptr->push_p = 1;
+
+  else if (v4_call_p)
+    info_ptr->push_p = (info_ptr->total_size > info_ptr->fixed_size
+                       || info_ptr->lr_save_p);
+
+  else
+    info_ptr->push_p = (frame_pointer_needed
+                       || write_symbols != NO_DEBUG
+                       || info_ptr->total_size > 220);
+
+  /* Calculate the offsets */
+  info_ptr->fp_save_offset = - info_ptr->fp_size;
+  info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size;
+  if (v4_call_p)
+    {
+      info_ptr->cr_save_offset = info_ptr->gp_save_offset - reg_size;
+      info_ptr->lr_save_offset = - info_ptr->total_size + reg_size;
+    }
+  else
+    {
+      info_ptr->cr_save_offset = 4;
+      info_ptr->lr_save_offset = 8;
+    }
+
+  /* Zero offsets if we're not saving those registers */
+  if (!info_ptr->fp_size)
+    info_ptr->fp_save_offset = 0;
+
+  if (!info_ptr->gp_size)
+    info_ptr->gp_save_offset = 0;
+
+  if (!info_ptr->lr_save_p)
+    info_ptr->lr_save_offset = 0;
+
+  if (!info_ptr->cr_save_p)
+    info_ptr->cr_save_offset = 0;
+
+  return info_ptr;
 }
 
+void
+debug_stack_info (info)
+     rs6000_stack_t *info;
+{
+  if (!info)
+    info = rs6000_stack_info ();
+
+  fprintf (stderr, "\nStack information for function %s:\n",
+          ((current_function_decl && DECL_NAME (current_function_decl))
+           ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
+           : "<unknown>"));
+
+  if (info->first_gp_reg_save != 32)
+    fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
+
+  if (info->first_fp_reg_save != 64)
+    fprintf (stderr, "\tfirst_fp_reg_save   = %5d\n", info->first_fp_reg_save);
+
+  if (info->lr_save_p)
+    fprintf (stderr, "\tlr_save_p           = %5d\n", info->lr_save_p);
+
+  if (info->cr_save_p)
+    fprintf (stderr, "\tcr_save_p           = %5d\n", info->cr_save_p);
+
+  if (info->push_p)
+    fprintf (stderr, "\tpush_p              = %5d\n", info->push_p);
+
+  if (info->calls_p)
+    fprintf (stderr, "\tcalls_p             = %5d\n", info->calls_p);
+
+  if (info->v4_call_p)
+    fprintf (stderr, "\tv4_call_p           = %5d\n", info->v4_call_p);
+
+  if (info->gp_save_offset)
+    fprintf (stderr, "\tgp_save_offset      = %5d\n", info->gp_save_offset);
+
+  if (info->fp_save_offset)
+    fprintf (stderr, "\tfp_save_offset      = %5d\n", info->fp_save_offset);
+
+  if (info->lr_save_offset)
+    fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
+
+  if (info->cr_save_offset)
+    fprintf (stderr, "\tcr_save_offset      = %5d\n", info->cr_save_offset);
+
+  if (info->varargs_save_offset)
+    fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
+
+  if (info->total_size)
+    fprintf (stderr, "\ttotal_size          = %5d\n", info->total_size);
+
+  if (info->varargs_size)
+    fprintf (stderr, "\tvarargs_size        = %5d\n", info->varargs_size);
+
+  if (info->vars_size)
+    fprintf (stderr, "\tvars_size           = %5d\n", info->vars_size);
+
+  if (info->parm_size)
+    fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
+
+  if (info->fixed_size)
+    fprintf (stderr, "\tfixed_size          = %5d\n", info->fixed_size);
+
+  if (info->gp_size)
+    fprintf (stderr, "\tgp_size             = %5d\n", info->gp_size);
+
+  if (info->fp_size)
+    fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
+
+  if (info->cr_size)
+    fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
+
+  if (info->save_size)
+    fprintf (stderr, "\tsave_size           = %5d\n", info->save_size);
+
+  if (info->reg_size != 4)
+    fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
+
+  fprintf (stderr, "\n");
+}
+
+\f
+
 #ifdef USING_SVR4_H
 /* Write out a System V.4 style traceback table before the prologue
 
@@ -1781,77 +2402,62 @@ svr4_traceback (file, name, decl)
      FILE *file;
      tree name, decl;
 {
-
-  int first_reg                = first_reg_to_save ();
-  int first_fp_reg     = first_fp_reg_to_save ();
-  int pushes_stack     = rs6000_pushes_stack ();
+  rs6000_stack_t *info = rs6000_stack_info ();
   long tag;
-  long version         = 0;                    /* version number */
-  long tag_type                = 0;                    /* function type */
-  long extended_tag    = 0;                    /* additional tag words needed */
-  long spare           = 0;                    /* reserved for future use */
-  long alloca_reg;                             /* stack/frame register */
-  long fpr_max         = 64 - first_fp_reg;    /* # of floating point registers saved */
-  long gpr_max         = 32 - first_reg;       /* # of general purpose registers saved */
-  long sp_max;                                 /* 1 if the function acquires a stack frame */
-  long lr_max;                                 /* 1 if the function stores the link register */
-  long cr_max;                                 /* 1 if the function has a CR save word */
-  long fpscr_max       = 0;                    /* 1 if the function has a FPSCR save word */
+  long version         = 0;                            /* version number */
+  long tag_type                = 0;                            /* function type */
+  long extended_tag    = 0;                            /* additional tag words needed */
+  long spare           = 0;                            /* reserved for future use */
+  long fpscr_max       = 0;                            /* 1 if the function has a FPSCR save word */
+  long fpr_max         = 64 - info->first_fp_reg_save; /* # of floating point registers saved */
+  long gpr_max         = 32 - info->first_gp_reg_save; /* # of general purpose registers saved */
+  long alloca_reg;                                     /* stack/frame register */
 
   if (frame_pointer_needed)
     alloca_reg = 31;
 
-  else if (pushes_stack != 0)
+  else if (info->push_p != 0)
     alloca_reg = 1;
 
   else
     alloca_reg = 0;
 
-  lr_max = (regs_ever_live[65] || first_fp_reg < 62 || profile_flag);
-  cr_max = (must_save_cr () != 0);
-  sp_max = (pushes_stack != 0);
-
-  tag = (((version & 3) << 24)
-        | ((tag_type & 7) << 21)
-        | ((extended_tag & 1) << 20)
-        | ((spare & 1) << 19)
-        | ((alloca_reg & 0x1f) << 14)
-        | ((fpr_max & 0x1f) << 9)
-        | ((gpr_max & 0x1f) << 4)
-        | ((sp_max & 1) << 3)
-        | ((lr_max & 1) << 2)
-        | ((cr_max & 1) << 1)
-        | ((fpscr_max & 1) << 0));
+  tag = ((version << 24)
+        | (tag_type << 21)
+        | (extended_tag << 20)
+        | (spare << 19)
+        | (alloca_reg << 14)
+        | (fpr_max << 9)
+        | (gpr_max << 4)
+        | (info->push_p << 3)
+        | (info->lr_save_p << 2)
+        | (info->cr_save_p << 1)
+        | (fpscr_max << 0));
           
   fprintf (file, "\t.long 0x%lx\n", tag);
 }
 
 #endif /* USING_SVR4_H */
-
+\f
 /* Write function prologue.  */
-
 void
 output_prolog (file, size)
      FILE *file;
      int size;
 {
-  int first_reg = first_reg_to_save ();
-  int must_push = rs6000_pushes_stack ();
-  int first_fp_reg = first_fp_reg_to_save ();
-  int basic_size = rs6000_sa_size ();
-  int total_size = (basic_size + size + current_function_outgoing_args_size);
-  char buf[256];
+  rs6000_stack_t *info = rs6000_stack_info ();
+  char *store_reg = (TARGET_64BIT) ? "\tstd %s,%d(%s)" : "\t{st|stw} %s,%d(%s)\n";
 
-  /* Round size to multiple of 8 bytes.  */
-  total_size = (total_size + 7) & ~7;
+  if (TARGET_DEBUG_STACK)
+    debug_stack_info (info);
 
   /* Write .extern for any function we will call to save and restore fp
      values.  */
 #ifndef USING_SVR4_H
-  if (first_fp_reg < 62)
+  if (info->first_fp_reg_save < 62)
     fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
-            SAVE_FP_PREFIX, first_fp_reg - 32, SAVE_FP_SUFFIX,
-            RESTORE_FP_PREFIX, first_fp_reg - 32, RESTORE_FP_SUFFIX);
+            SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
+            RESTORE_FP_PREFIX, info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
 #endif
 
   /* Write .extern for truncation routines, if needed.  */
@@ -1861,6 +2467,7 @@ output_prolog (file, size)
               RS6000_ITRUNC, RS6000_UITRUNC);
       trunc_defined = 1;
     }
+
   /* Write .extern for AIX common mode routines, if needed.  */
   if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
     {
@@ -1873,100 +2480,79 @@ output_prolog (file, size)
       common_mode_defined = 1;
     }
 
-#ifdef USING_SVR4_H
-  /* If we have a relocatable GOT section, we need to save the LR. */
-  if (TARGET_RELOCATABLE && get_pool_size () != 0)
-    regs_ever_live[65] = 1;
-#endif
-
-  /* If we have to call a function to save fpr's, or if we are doing profiling,
-     then we will be using LR.  */
-  if (profile_flag)
-    regs_ever_live[65] = 1;
-
-#ifndef USING_SVR4_H
-  if (first_fp_reg < 62)
-    regs_ever_live[65] = 1;
-#endif
-
   /* If we use the link register, get it into r0.  */
-  if (regs_ever_live[65])
-    asm_fprintf (file, "\tmflr 0\n");
+  if (info->lr_save_p)
+    asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
 
   /* If we need to save CR, put it into r12.  */
-  if (must_save_cr ())
-    asm_fprintf (file, "\tmfcr 12\n");
+  if (info->cr_save_p)
+    asm_fprintf (file, "\tmfcr %s\n", reg_names[12]);
 
   /* Do any required saving of fpr's.  If only one or two to save, do it
      ourself.  Otherwise, call function.  Note that since they are statically
      linked, we do not need a nop following them.  */
-  if (first_fp_reg == 62)
-    asm_fprintf (file, "\tstfd 30,-16(1)\n\tstfd 31,-8(1)\n");
-  else if (first_fp_reg == 63)
-    asm_fprintf (file, "\tstfd 31,-8(1)\n");
-  else if (first_fp_reg != 64)
+  if (FP_SAVE_INLINE (info->first_fp_reg_save))
     {
-#ifndef USING_SVR4_H
-      asm_fprintf (file, "\tbl %s%d%s\n", SAVE_FP_PREFIX, first_fp_reg - 32, SAVE_FP_SUFFIX);
-#else
-      int regno, loc;
+      int regno = info->first_fp_reg_save;
+      int loc   = info->fp_save_offset;
 
-      for (regno = first_fp_reg,
-          loc = - (64 - first_fp_reg) * 8;
-          regno < 64;
-          regno++, loc += 8)
-       asm_fprintf (file, "\tstfd %d,%d(1)\n", regno - 32, loc);
-#endif
+      for ( ; regno < 64; regno++, loc += 8)
+       asm_fprintf (file, "\tstfd %s,%d(%s)\n", reg_names[regno], loc, reg_names[1]);
     }
+  else if (info->first_fp_reg_save != 64)
+    asm_fprintf (file, "\tbl %s%d%s\n", SAVE_FP_PREFIX,
+                info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
 
   /* Now save gpr's.  */
-  if (! TARGET_MULTIPLE || first_reg == 31)
+  if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT)
     {
-      int regno, loc;
+      int regno    = info->first_gp_reg_save;
+      int loc      = info->gp_save_offset;
+      int reg_size = (TARGET_64BIT) ? 8 : 4;
 
-      for (regno = first_reg,
-          loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8;
-          regno < 32;
-          regno++, loc += 4)
-       asm_fprintf (file, "\t{st|stw} %d,%d(1)\n", regno, loc);
+      for ( ; regno < 32; regno++, loc += reg_size)
+       asm_fprintf (file, store_reg, reg_names[regno], loc, reg_names[1]);
     }
 
-  else if (first_reg != 32)
-    asm_fprintf (file, "\t{stm|stmw} %d,%d(1)\n", first_reg,
-            - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
+  else if (info->first_gp_reg_save != 32)
+    asm_fprintf (file, "\t{stm|stmw} %s,%d(%s)\n",
+                reg_names[info->first_gp_reg_save],
+                info->gp_save_offset,
+                reg_names[1]);
 
   /* Save lr if we used it.  */
-  if (regs_ever_live[65])
-    asm_fprintf (file, "\t{st|stw} 0,8(1)\n");
+  if (info->lr_save_p)
+    asm_fprintf (file, store_reg, reg_names[0], info->lr_save_offset, reg_names[1]);
 
   /* Save CR if we use any that must be preserved.  */
-  if (must_save_cr ())
-    asm_fprintf (file, "\t{st|stw} 12,4(1)\n");
+  if (info->cr_save_p)
+    asm_fprintf (file, store_reg, reg_names[12], info->cr_save_offset, reg_names[1]);
 
   /* Update stack and set back pointer.  */
-  if (must_push)
+  if (info->push_p)
     {
-      if (total_size < 32767)
-       asm_fprintf (file, "\t{stu|stwu} 1,%d(1)\n", - total_size);
+      if (info->total_size < 32767)
+       asm_fprintf (file,
+                    (TARGET_64BIT) ? "\tstdu %s,%d(%s)\n" : "\t{stu|stwu} %s,%d(%s)\n",
+                    reg_names[1], - info->total_size, reg_names[1]);
       else
        {
-         asm_fprintf (file, "\t{liu|lis} 0,%d\n\t{oril|ori} 0,0,%d\n",
-                  (total_size >> 16) & 0xffff, total_size & 0xffff);
-         if (TARGET_POWERPC)
-           asm_fprintf (file, "\tsubf 12,0,1\n");
-         else
-           asm_fprintf (file, "\t{sf|subfc} 12,0,1\n");
-         asm_fprintf (file, "\t{st|stw} 1,0(12)\n\tmr 1,12\n");
+         asm_fprintf (file, "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
+                      reg_names[0], (info->total_size >> 16) & 0xffff,
+                      reg_names[0], reg_names[0], info->total_size & 0xffff);
+         asm_fprintf (file,
+                      (TARGET_64BIT) ? "\tstdux %s,%s,%s\n" : "\tstwux %s,%s,%s\n",
+                      reg_names[1], reg_names[1], reg_names[0]);
        }
     }
 
   /* Set frame pointer, if needed.  */
   if (frame_pointer_needed)
-    asm_fprintf (file, "\tmr 31,1\n");
+    asm_fprintf (file, "\tmr %s,%s\n", reg_names[31], reg_names[1]);
 
   /* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the
      TOC_TABLE address into register 30.  */
-  if (TARGET_MINIMAL_TOC && get_pool_size () != 0)
+  if (TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
     {
       char buf[256];
 
@@ -1979,43 +2565,54 @@ output_prolog (file, size)
          fprintf (file, "\n");
 
          ASM_OUTPUT_INTERNAL_LABEL (file, "LCF", rs6000_pic_labelno);
-         fprintf (file, "\tmflr 30\n");
+         fprintf (file, "\tmflr %s\n", reg_names[30]);
 
          if (TARGET_POWERPC64)
-           fprintf (file, "\tld 0,");
+           fprintf (file, "\tld");
          else if (TARGET_NEW_MNEMONICS)
-           fprintf (file, "\tlwz 0,");
+           fprintf (file, "\tlwz");
          else
-           fprintf (file, "\tl 0,");
+           fprintf (file, "\tl");
 
-         fprintf (file, "(");
+         fprintf (file, " %s,(", reg_names[0]);
          ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
          assemble_name (file, buf);
          fprintf (file, "-");
          ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
          assemble_name (file, buf);
-         fprintf (file, ")(30)\n");
-         asm_fprintf (file, "\t{cax|add} 30,0,30\n");
+         fprintf (file, ")(%s)\n", reg_names[30]);
+         asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
+                      reg_names[30], reg_names[0], reg_names[30]);
          rs6000_pic_labelno++;
        }
-      else if (TARGET_NO_TOC)
+      else if (!TARGET_64BIT)
        {
          ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
-         asm_fprintf (file, "\t{cau|addis} 30,0,");
+         asm_fprintf (file, "\t{cau|addis} %s,%s,", reg_names[30], reg_names[0]);
          assemble_name (file, buf);
          asm_fprintf (file, "@ha\n");
-         asm_fprintf (file, "\t{cal|addi} 30,30,");
-         assemble_name (file, buf);
-         asm_fprintf (file, "@l\n");
+         if (TARGET_NEW_MNEMONICS)
+           {
+             asm_fprintf (file, "\taddi %s,%s,", reg_names[30], reg_names[30]);
+             assemble_name (file, buf);
+             asm_fprintf (file, "@l\n");
+           }
+         else
+           {
+             asm_fprintf (file, "\tcal %s,", reg_names[30]);
+             assemble_name (file, buf);
+             asm_fprintf (file, "@l(%s)\n", reg_names[30]);
+           }
        }
       else
+       abort ();
+
+#else  /* !USING_SVR4_H */
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0);
+      asm_fprintf (file, "\t{l|lwz} %s,", reg_names[30]);
+      assemble_name (file, buf);
+      asm_fprintf (file, "(%s)\n", reg_names[2]);
 #endif /* USING_SVR4_H */
-       {
-         ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0);
-         asm_fprintf (file, "\t{l|lwz} 30,");
-         assemble_name (file, buf);
-         asm_fprintf (file, "(2)\n");
-       }
     }
 }
 
@@ -2026,16 +2623,10 @@ output_epilog (file, size)
      FILE *file;
      int size;
 {
-  int first_reg = first_reg_to_save ();
-  int must_push = rs6000_pushes_stack ();
-  int first_fp_reg = first_fp_reg_to_save ();
-  int basic_size = rs6000_sa_size ();
-  int total_size = (basic_size + size + current_function_outgoing_args_size);
+  rs6000_stack_t *info = rs6000_stack_info ();
+  char *load_reg = (TARGET_64BIT) ? "\tld %s,%d(%s)" : "\t{l|lwz} %s,%d(%s)\n";
   rtx insn = get_last_insn ();
 
-  /* Round size to multiple of 8 bytes.  */
-  total_size = (total_size + 7) & ~7;
-
   /* If the last insn was a BARRIER, we don't have to write anything except
      the trace table.  */
   if (GET_CODE (insn) == NOTE)
@@ -2046,71 +2637,68 @@ output_epilog (file, size)
         frame, restore the old stack pointer using the backchain.  Otherwise,
         we know what size to update it with.  */
       if (frame_pointer_needed || current_function_calls_alloca
-         || total_size > 32767)
-       asm_fprintf (file, "\t{l|lwz} 1,0(1)\n");
-      else if (must_push)
-       asm_fprintf (file, "\t{cal 1,%d(1)|addi 1,1,%d}\n", total_size);
+         || info->total_size > 32767)
+       asm_fprintf (file, load_reg, reg_names[1], 0, reg_names[1]);
+      else if (info->push_p)
+       {
+         if (TARGET_NEW_MNEMONICS)
+           asm_fprintf (file, "\taddi %s,%s,%d\n", reg_names[1], reg_names[1], info->total_size);
+         else
+           asm_fprintf (file, "\tcal %s,%d(%s)\n", reg_names[1], info->total_size, reg_names[1]);
+       }
 
       /* Get the old lr if we saved it.  */
-      if (regs_ever_live[65])
-       asm_fprintf (file, "\t{l|lwz} 0,8(1)\n");
+      if (info->lr_save_p)
+       asm_fprintf (file, load_reg, reg_names[0], info->lr_save_offset, reg_names[1]);
 
       /* Get the old cr if we saved it.  */
-      if (must_save_cr ())
-       asm_fprintf (file, "\t{l|lwz} 12,4(1)\n");
+      if (info->cr_save_p)
+       asm_fprintf (file, load_reg, reg_names[12], info->cr_save_offset, reg_names[1]);
 
       /* Set LR here to try to overlap restores below.  */
-      if (regs_ever_live[65])
-       asm_fprintf (file, "\tmtlr 0\n");
+      if (info->lr_save_p)
+       asm_fprintf (file, "\tmtlr %s\n", reg_names[0]);
 
       /* Restore gpr's.  */
-      if (! TARGET_MULTIPLE || first_reg == 31)
+      if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT)
        {
-         int regno, loc;
+         int regno    = info->first_gp_reg_save;
+         int loc      = info->gp_save_offset;
+         int reg_size = (TARGET_64BIT) ? 8 : 4;
 
-         for (regno = first_reg,
-              loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8;
-              regno < 32;
-              regno++, loc += 4)
-           asm_fprintf (file, "\t{l|lwz} %d,%d(1)\n", regno, loc);
+         for ( ; regno < 32; regno++, loc += reg_size)
+           asm_fprintf (file, load_reg, reg_names[regno], loc, reg_names[1]);
        }
 
-      else if (first_reg != 32)
-       asm_fprintf (file, "\t{lm|lmw} %d,%d(1)\n", first_reg,
-            - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8);
+      else if (info->first_gp_reg_save != 32)
+       asm_fprintf (file, "\t{lm|lmw} %s,%d(%s)\n",
+                    reg_names[info->first_gp_reg_save],
+                    info->gp_save_offset,
+                    reg_names[1]);
 
       /* Restore fpr's if we can do it without calling a function.  */
-      if (first_fp_reg == 62)
-       asm_fprintf (file, "\tlfd 30,-16(1)\n\tlfd 31,-8(1)\n");
-      else if (first_fp_reg == 63)
-       asm_fprintf (file, "\tlfd 31,-8(1)\n");
+      if (FP_SAVE_INLINE (info->first_fp_reg_save))
+       {
+         int regno = info->first_fp_reg_save;
+         int loc   = info->fp_save_offset;
+
+         for ( ; regno < 64; regno++, loc += 8)
+           asm_fprintf (file, "\tlfd %s,%d(%s)\n", reg_names[regno], loc, reg_names[1]);
+       }
 
       /* If we saved cr, restore it here.  Just those of cr2, cr3, and cr4
         that were used.  */
-      if (must_save_cr ())
-       asm_fprintf (file, "\tmtcrf %d,12\n",
+      if (info->cr_save_p)
+       asm_fprintf (file, "\tmtcrf %d,%s\n",
                     (regs_ever_live[70] != 0) * 0x20
                     + (regs_ever_live[71] != 0) * 0x10
-                    + (regs_ever_live[72] != 0) * 0x8);
+                    + (regs_ever_live[72] != 0) * 0x8, reg_names[12]);
 
       /* If we have to restore more than two FP registers, branch to the
         restore function.  It will return to our caller.  */
-      if (first_fp_reg < 62)
-       {
-#ifndef USING_SVR4_H
-         asm_fprintf (file, "\tb %s%d%s\n", RESTORE_FP_PREFIX, first_fp_reg - 32, RESTORE_FP_SUFFIX);
-#else
-         int regno, loc;
-
-         for (regno = first_fp_reg,
-              loc = - (64 - first_fp_reg) * 8;
-              regno < 64;
-              regno++, loc += 8)
-           asm_fprintf (file, "\tlfd %d,%d(1)\n", regno - 32, loc);
-
-         asm_fprintf (file, "\t{br|blr}\n");
-#endif
-       }
+      if (info->first_fp_reg_save != 64 && !FP_SAVE_INLINE (info->first_fp_reg_save))
+       asm_fprintf (file, "\tb %s%d%s\n", RESTORE_FP_PREFIX,
+                    info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
       else
        asm_fprintf (file, "\t{br|blr}\n");
     }
@@ -2184,7 +2772,7 @@ output_epilog (file, size)
         has controlled storage, function has no toc, function uses fp,
         function logs/aborts fp operations.  */
       /* Assume that fp operations are used if any fp reg must be saved.  */
-      fprintf (file, "%d,", (1 << 5) | ((first_fp_reg != 64) << 1));
+      fprintf (file, "%d,", (1 << 5) | ((info->first_fp_reg_save != 64) << 1));
 
       /* 6 bitfields: function is interrupt handler, name present in
         proc table, function calls alloca, on condition directives
@@ -2194,12 +2782,12 @@ output_epilog (file, size)
         set up as a frame pointer, even when there is no alloca call.  */
       fprintf (file, "%d,",
               ((1 << 6) | (frame_pointer_needed << 5)
-               | (must_save_cr () << 1) | (regs_ever_live[65])));
+               | (info->cr_save_p << 1) | (info->lr_save_p)));
 
       /* 3 bitfields: saves backchain, spare bit, number of fpr saved
         (6 bits).  */
       fprintf (file, "%d,",
-              (must_push << 7) | (64 - first_fp_reg_to_save ()));
+              (info->push_p << 7) | (64 - info->first_fp_reg_save));
 
       /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
       fprintf (file, "%d,", (32 - first_reg_to_save ()));
@@ -2308,6 +2896,9 @@ output_epilog (file, size)
        fprintf (file, "\t.byte 31\n");
     }
 #endif /* !USING_SVR4_H */
+
+  /* Reset varargs indicator */
+  rs6000_sysv_varargs_p = 0;
 }
 \f
 /* Output a TOC entry.  We derive the entry name from what is
@@ -2324,6 +2915,9 @@ output_toc (file, x, labelno)
   rtx base = x;
   int offset = 0;
 
+  if (TARGET_NO_TOC)
+    abort ();
+
 #ifdef USING_SVR4_H
   if (TARGET_MINIMAL_TOC)
     {
index 59f60a6..9bc64c3 100644 (file)
@@ -150,6 +150,10 @@ extern int target_flags;
 #define MASK_STRING            0x4000
 #define MASK_STRING_SET                0x8000
 
+/* Temporary debug switches */
+#define MASK_DEBUG_STACK       0x10000
+#define MASK_DEBUG_ARG         0x20000
+
 #define TARGET_POWER           (target_flags & MASK_POWER)
 #define TARGET_POWER2          (target_flags & MASK_POWER2)
 #define TARGET_POWERPC         (target_flags & MASK_POWERPC)
@@ -166,9 +170,23 @@ extern int target_flags;
 #define        TARGET_MULTIPLE_SET     (target_flags & MASK_MULTIPLE_SET)
 #define TARGET_STRING          (target_flags & MASK_STRING)
 #define TARGET_STRING_SET      (target_flags & MASK_STRING_SET)
+#define        TARGET_DEBUG_STACK      (target_flags & MASK_DEBUG_STACK)
+#define        TARGET_DEBUG_ARG        (target_flags & MASK_DEBUG_ARG)
 
 #define TARGET_HARD_FLOAT      (! TARGET_SOFT_FLOAT)
 
+/* Pseudo target to indicate whether the object format is ELF
+   (to get around not having conditional compilation in the md file)  */
+#ifndef        TARGET_ELF
+#define        TARGET_ELF              0
+#endif
+
+/* If this isn't V.4, don't support -mno-toc.  */
+#ifndef TARGET_NO_TOC
+#define TARGET_NO_TOC          0
+#define        TARGET_TOC              1
+#endif
+
 /* Run-time compilation parameters selecting different hardware subsets.
 
    Macro to define tables used to set the flags.
@@ -215,6 +233,8 @@ extern int target_flags;
   {"string",           MASK_STRING | MASK_STRING_SET},                 \
   {"no-string",                - MASK_STRING},                                 \
   {"no-string",                MASK_STRING_SET},                               \
+  {"debug-stack",      MASK_DEBUG_STACK},                              \
+  {"debug-arg",                MASK_DEBUG_ARG},                                \
   SUBTARGET_SWITCHES                                                   \
   {"",                 TARGET_DEFAULT}}
 
@@ -833,6 +853,32 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
 \f
 /* Stack layout; function entry, exit and calling.  */
 
+/* Structure used to define the rs6000 stack */
+typedef struct rs6000_stack {
+  int first_gp_reg_save;       /* first callee saved GP register used */
+  int first_fp_reg_save;       /* first callee saved FP register used */
+  int lr_save_p;               /* true if the link reg needs to be saved */
+  int cr_save_p;               /* true if the CR reg needs to be saved */
+  int push_p;                  /* true if we need to allocate stack space */
+  int calls_p;                 /* true if the function makes any calls */
+  int v4_call_p;               /* true if V.4 calling sequence used */
+  int gp_save_offset;          /* offset to save GP regs from inital SP */
+  int fp_save_offset;          /* offset to save FP regs from inital SP */
+  int lr_save_offset;          /* offset to save LR from initial SP */
+  int cr_save_offset;          /* offset to save CR from initial SP */
+  int varargs_save_offset;     /* offset to save the varargs registers */
+  int reg_size;                        /* register size (4 or 8) */
+  int varargs_size;            /* size to hold V.4 args passed in regs */
+  int vars_size;               /* variable save area size */
+  int parm_size;               /* outgoing parameter size */
+  int save_size;               /* save area size */
+  int fixed_size;              /* fixed size of stack frame */
+  int gp_size;                 /* size of saved GP registers */
+  int fp_size;                 /* size of saved FP registers */
+  int cr_size;                 /* size to hold CR if not in save_size */
+  int total_size;              /* total bytes allocated for stack */
+} rs6000_stack_t;
+
 /* Define this if pushing a word on the stack
    makes the stack pointer a smaller address.  */
 #define STACK_GROWS_DOWNWARD
@@ -846,6 +892,29 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
    arguments.  */
 /* #define FRAME_GROWS_DOWNWARD */
 
+/* Size of the outgoing register save area */
+#define RS6000_REG_SAVE (TARGET_64BIT ? 64 : 32)
+
+/* Size of the fixed area on the stack */
+#define RS6000_SAVE_AREA (TARGET_64BIT ? 48 : 24)
+
+/* Size of the V.4 varargs area if needed */
+#define RS6000_VARARGS_AREA 0
+
+/* Whether a V.4 varargs area is needed */
+extern int rs6000_sysv_varargs_p;
+
+/* Align an address */
+#define ALIGN(n,a) (((n) + (a) - 1) & ~((a) - 1))
+
+/* Size of V.4 varargs area in bytes */
+#define RS6000_VARARGS_SIZE \
+  ((GP_ARG_NUM_REG * (TARGET_64BIT ? 8 : 4)) + (FP_ARG_NUM_REG * 8) + 8)
+
+/* Offset of V.4 varargs area */
+#define RS6000_VARARGS_OFFSET \
+  (ALIGN (current_function_outgoing_args_size, 8) + RS6000_SAVE_AREA)
+
 /* Offset within stack frame to start allocating local variables at.
    If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
    first local allocated.  Otherwise, it is the offset to the BEGINNING
@@ -855,8 +924,9 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
    except for dynamic allocations.  So we start after the fixed area and
    outgoing parameter area.  */
 
-#define STARTING_FRAME_OFFSET (current_function_outgoing_args_size \
-                              + (TARGET_64BIT ? 48 : 24))
+#define STARTING_FRAME_OFFSET (ALIGN (current_function_outgoing_args_size, 8) \
+                              + RS6000_VARARGS_AREA \
+                              + RS6000_SAVE_AREA)
 
 /* If we generate an insn to push BYTES bytes,
    this says how many the stack pointer really advances by.
@@ -866,12 +936,12 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
 /* Offset of first parameter from the argument pointer register value.
    On the RS/6000, we define the argument pointer to the start of the fixed
    area.  */
-#define FIRST_PARM_OFFSET(FNDECL) (TARGET_64BIT ? 48 : 24)
+#define FIRST_PARM_OFFSET(FNDECL) RS6000_SAVE_AREA
 
 /* Define this if stack space is still allocated for a parameter passed
    in a register.  The value is the number of bytes allocated to this
    area.  */
-#define REG_PARM_STACK_SPACE(FNDECL)   (TARGET_64BIT ? 64 : 32)
+#define REG_PARM_STACK_SPACE(FNDECL)   RS6000_REG_SAVE
 
 /* Define this if the above stack space is to be considered part of the
    space allocated by the caller.  */
@@ -880,7 +950,7 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
 /* This is the difference between the logical top of stack and the actual sp.
 
    For the RS/6000, sp points past the fixed area. */
-#define STACK_POINTER_OFFSET (TARGET_64BIT ? 48 : 24)
+#define STACK_POINTER_OFFSET RS6000_SAVE_AREA
 
 /* Define this if the maximum size of all the outgoing args is to be
    accumulated and pushed during the prologue.  The amount can be
@@ -922,18 +992,35 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
 #define RETURN_IN_MEMORY(TYPE) \
   (TYPE_MODE (TYPE) == BLKmode)
 
+/* Minimum and maximum general purpose registers used to hold arguments.  */
+#define GP_ARG_MIN_REG 3
+#define GP_ARG_MAX_REG 10
+#define GP_ARG_NUM_REG (GP_ARG_MAX_REG - GP_ARG_MIN_REG + 1)
+
+/* Minimum and maximum floating point registers used to hold arguments.  */
+#define FP_ARG_MIN_REG 33
+#define FP_ARG_MAX_REG 45
+#define FP_ARG_NUM_REG (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1)
+
+/* Return registers */
+#define GP_ARG_RETURN GP_ARG_MIN_REG
+#define FP_ARG_RETURN FP_ARG_MIN_REG
+
+/* Define cutoff for using external functions to save floating point */
+#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == 62 || (FIRST_REG) == 63)
+
 /* 1 if N is a possible register number for a function value
    as seen by the caller.
 
    On RS/6000, this is r3 and fp1.  */
-
-#define FUNCTION_VALUE_REGNO_P(N)  ((N) == 3 || ((N) == 33))
+#define FUNCTION_VALUE_REGNO_P(N)  ((N) == GP_ARG_RETURN || ((N) == FP_ARG_RETURN))
 
 /* 1 if N is a possible register number for function argument passing.
    On RS/6000, these are r3-r10 and fp1-fp13.  */
+#define FUNCTION_ARG_REGNO_P(N)                                                \
+  (((unsigned)((N) - GP_ARG_MIN_REG) < (unsigned)(GP_ARG_NUM_REG))     \
+   || ((unsigned)((N) - FP_ARG_MIN_REG) < (unsigned)(FP_ARG_NUM_REG)))
 
-#define FUNCTION_ARG_REGNO_P(N)        \
-  (((N) <= 10 && (N) >= 3) || ((N) >= 33 && (N) <= 45))
 \f
 /* Define a data type for recording info about an argument list
    during the scan of that argument list.  This data type should
@@ -944,10 +1031,21 @@ enum reg_class { NO_REGS, BASE_REGS, GENERAL_REGS, FLOAT_REGS,
    On the RS/6000, this is a structure.  The first element is the number of
    total argument words, the second is used to store the next
    floating-point register number, and the third says how many more args we
-   have prototype types for.  */
-
-struct rs6000_args {int words, fregno, nargs_prototype; };
-#define CUMULATIVE_ARGS struct rs6000_args
+   have prototype types for.
+
+   The System V.4 varargs/stdarg support requires that this structure's size
+   be a multiple of sizeof(int), and that WORDS, FREGNO, NARGS_PROTOTYPE,
+   ORIG_NARGS, and VARARGS_OFFSET be the first five ints.  */
+
+typedef struct rs6000_args
+{
+  int words;                   /* # words uses for passing GP registers */
+  int fregno;                  /* next available FP register */
+  int nargs_prototype;         /* # args left in the current prototype */
+  int orig_nargs;              /* Original value of nargs_prototype */
+  int varargs_offset;          /* offset of the varargs save area */
+  int prototype;               /* Whether a prototype was defined */
+} CUMULATIVE_ARGS;
 
 /* Define intermediate macro to compute the size (in registers) of an argument
    for the RS/6000.  */
@@ -962,40 +1060,27 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is 0.  */
 
-#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME)       \
-  (CUM).words = 0,                             \
-  (CUM).fregno = 33,                           \
-  (CUM).nargs_prototype = (FNTYPE && TYPE_ARG_TYPES (FNTYPE)           \
-                          ? (list_length (TYPE_ARG_TYPES (FNTYPE)) - 1 \
-                             + (TYPE_MODE (TREE_TYPE (FNTYPE)) == BLKmode \
-                                || RETURN_IN_MEMORY (TREE_TYPE (FNTYPE)))) \
-                          : 0)
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) \
+  init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE)
 
 /* Similar, but when scanning the definition of a procedure.  We always
    set NARGS_PROTOTYPE large so we never return an EXPR_LIST.  */
 
-#define INIT_CUMULATIVE_INCOMING_ARGS(CUM,FNTYPE,IGNORE) \
-  (CUM).words = 0,                             \
-  (CUM).fregno = 33,                           \
-  (CUM).nargs_prototype = 1000
+#define INIT_CUMULATIVE_INCOMING_ARGS(CUM,FNTYPE,LIBNAME) \
+  init_cumulative_args (&CUM, FNTYPE, LIBNAME, TRUE)
 
 /* Update the data in CUM to advance over an argument
    of mode MODE and data type TYPE.
    (TYPE is null for libcalls where that information may not be available.)  */
 
 #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)   \
-{ (CUM).nargs_prototype--;                             \
-  if (NAMED)                                           \
-    {                                                  \
-      (CUM).words += RS6000_ARG_SIZE (MODE, TYPE, NAMED); \
-      if (GET_MODE_CLASS (MODE) == MODE_FLOAT)         \
-       (CUM).fregno++;                                 \
-    }                                                  \
-}
+  function_arg_advance (&CUM, MODE, TYPE, NAMED)
 
 /* Non-zero if we can use a floating-point register to pass this arg.  */
-#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)        \
-  (GET_MODE_CLASS (MODE) == MODE_FLOAT && (CUM).fregno < 46 && TARGET_HARD_FLOAT)
+#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \
+  (GET_MODE_CLASS (MODE) == MODE_FLOAT  \
+   && (CUM).fregno <= FP_ARG_MAX_REG    \
+   && TARGET_HARD_FLOAT)
 
 /* Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
@@ -1019,30 +1104,24 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
    so we can pass the FP value just in one register.  emit_library_function
    doesn't support EXPR_LIST anyway.  */
 
-#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED)                           \
-  (! (NAMED) ? 0                                                       \
-   : ((TYPE) != 0 && TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST) ? 0  \
-   : USE_FP_FOR_ARG_P (CUM, MODE, TYPE)                                        \
-   ? ((CUM).nargs_prototype > 0 || (TYPE) == 0                         \
-      ? gen_rtx (REG, MODE, (CUM).fregno)                              \
-      : ((CUM).words < 8                                               \
-        ? gen_rtx (EXPR_LIST, VOIDmode,                                \
-                   gen_rtx (REG, (MODE), 3 + (CUM).words),             \
-                   gen_rtx (REG, (MODE), (CUM).fregno))                \
-        : gen_rtx (EXPR_LIST, VOIDmode, 0,                             \
-                   gen_rtx (REG, (MODE), (CUM).fregno))))              \
-   : (CUM).words < 8 ? gen_rtx(REG, (MODE), 3 + (CUM).words) : 0)
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+  function_arg (&CUM, MODE, TYPE, NAMED)
 
 /* For an arg passed partly in registers and partly in memory,
    this is the number of registers used.
    For args passed entirely in registers or entirely in memory, zero.  */
 
-#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED)             \
-  (! (NAMED) ? 0                                                       \
-   : USE_FP_FOR_ARG_P (CUM, MODE, TYPE) && (CUM).nargs_prototype >= 0 ? 0 \
-   : (((CUM).words < 8                                                 \
-       && 8 < ((CUM).words + RS6000_ARG_SIZE (MODE, TYPE, NAMED)))     \
-      ? 8 - (CUM).words : 0))
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
+  function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)
+
+/* A C expression that indicates when an argument must be passed by
+   reference.  If nonzero for an argument, a copy of that argument is
+   made in memory and a pointer to the argument is passed instead of
+   the argument itself.  The pointer is passed in whatever way is
+   appropriate for passing a pointer to that type. */
+
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
+  function_arg_pass_by_reference(&CUM, MODE, TYPE, NAMED)
 
 /* Perform any needed actions needed for a function that is receiving a
    variable number of arguments. 
@@ -1058,27 +1137,23 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
    Normally, this macro will push all remaining incoming registers on the
    stack and set PRETEND_SIZE to the length of the registers pushed.  */
 
-#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL)      \
-{ if ((CUM).words < 8)                                                 \
-    {                                                                  \
-      int first_reg_offset = (CUM).words;                              \
-                                                                       \
-      if (MUST_PASS_IN_STACK (MODE, TYPE))                             \
-       first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (TYPE), TYPE, 1); \
-                                                                       \
-      if (first_reg_offset > 8)                                                \
-       first_reg_offset = 8;                                           \
-                                                                       \
-      if (! (NO_RTL) && first_reg_offset != 8)                         \
-       move_block_from_reg                                             \
-         (3 + first_reg_offset,                                        \
-          gen_rtx (MEM, BLKmode,                                       \
-                   plus_constant (virtual_incoming_args_rtx,           \
-                                  first_reg_offset * 4)),              \
-          8 - first_reg_offset, (8 - first_reg_offset) * UNITS_PER_WORD); \
-      PRETEND_SIZE = (8 - first_reg_offset) * UNITS_PER_WORD;          \
-    }                                                                  \
-}
+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
+  setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
+
+/* If defined, is a C expression that produces the machine-specific
+   code for a call to `__builtin_saveregs'.  This code will be moved
+   to the very beginning of the function, before any parameter access
+   are made.  The return value of this function should be an RTX that
+   contains the value to use as the return of `__builtin_saveregs'.
+
+   The argument ARGS is a `tree_list' containing the arguments that
+   were passed to `__builtin_saveregs'.
+
+   If this macro is not defined, the compiler will output an ordinary
+   call to the library function `__builtin_saveregs'.  */
+
+#define EXPAND_BUILTIN_SAVEREGS(ARGS) \
+  expand_builtin_saveregs (ARGS)
 
 /* This macro generates the assembly code for function entry.
    FILE is a stdio stream to output the code to.
@@ -1210,34 +1285,21 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
 #define CAN_ELIMINATE(FROM, TO)                                        \
  ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM \
   ? ! frame_pointer_needed                                     \
-  : (FROM) == 30 ? ! TARGET_MINIMAL_TOC || get_pool_size () == 0 \
+  : (FROM) == 30 ? ! TARGET_MINIMAL_TOC || TARGET_NO_TOC || get_pool_size () == 0 \
   : 1)
 
 /* Define the offset between two registers, one to be eliminated, and the other
    its replacement, at the start of a routine.  */
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)                   \
 {                                                                      \
-  int total_stack_size = (rs6000_sa_size () + get_frame_size ()                \
-                         + current_function_outgoing_args_size);       \
-                                                                       \
-  total_stack_size = (total_stack_size + 7) & ~7;                      \
+  rs6000_stack_t *info = rs6000_stack_info ();                         \
                                                                        \
  if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)   \
-    {                                                                  \
-      if (rs6000_pushes_stack ())                                      \
-       (OFFSET) = 0;                                                   \
-      else                                                             \
-       (OFFSET) = - total_stack_size;                                  \
-    }                                                                  \
-  else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \
-      (OFFSET) = total_stack_size;                                     \
-  else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
-    {                                                                  \
-      if (rs6000_pushes_stack ())                                      \
-       (OFFSET) = total_stack_size;                                    \
-      else                                                             \
-       (OFFSET) = 0;                                                   \
-    }                                                                  \
+   (OFFSET) = (info->push_p) ? 0 : - info->total_size;                 \
+ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM)        \
+   (OFFSET) = info->total_size;                                                \
+ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)        \
+   (OFFSET) = (info->push_p) ? info->total_size : 0;                   \
   else if ((FROM) == 30)                                               \
     (OFFSET) = 0;                                                      \
   else                                                                 \
@@ -1341,12 +1403,14 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
    we must ensure that both words are addressable.  */
 
 #define LEGITIMATE_CONSTANT_POOL_BASE_P(X)                             \
-  (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)           \
+  (TARGET_TOC && GET_CODE (X) == SYMBOL_REF                            \
+   && CONSTANT_POOL_ADDRESS_P (X)                                      \
    && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (X)))
 
 #define LEGITIMATE_CONSTANT_POOL_ADDRESS_P(X)                          \
   (LEGITIMATE_CONSTANT_POOL_BASE_P (X)                                 \
-   || (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS         \
+   || (TARGET_TOC                                                      \
+       && GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS      \
        && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT                        \
        && LEGITIMATE_CONSTANT_POOL_BASE_P (XEXP (XEXP (X, 0), 0))))
 
@@ -1374,6 +1438,16 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
 #define LEGITIMATE_INDIRECT_ADDRESS_P(X)       \
   (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X))
 
+#define LEGITIMATE_LO_SUM_ADDRESS_P(MODE, X)           \
+  (TARGET_ELF                                          \
+   && (MODE) != DImode                                 \
+   && (MODE) != TImode                                 \
+   && (TARGET_HARD_FLOAT || (MODE) != DFmode)          \
+   && GET_CODE (X) == LO_SUM                           \
+   && GET_CODE (XEXP (X, 0)) == REG                    \
+   && REG_OK_FOR_BASE_P (XEXP (X, 0))                  \
+   && CONSTANT_P (XEXP (X, 1)))
+
 #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)                \
 { if (LEGITIMATE_INDIRECT_ADDRESS_P (X))               \
     goto ADDR;                                         \
@@ -1391,6 +1465,8 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
       && (TARGET_HARD_FLOAT || (MODE) != DFmode)       \
       && LEGITIMATE_INDEXED_ADDRESS_P (X))             \
     goto ADDR;                                         \
+  if (LEGITIMATE_LO_SUM_ADDRESS_P (MODE, X))           \
+    goto ADDR;                                         \
 }
 \f
 /* Try machine-dependent ways of modifying an illegitimate address
@@ -1416,32 +1492,42 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
    Then check for the sum of a register and something not constant, try to
    load the other things into a register and return the sum.  */
 
-#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)                    \
-{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG    \
-    && GET_CODE (XEXP (X, 1)) == CONST_INT                     \
-    && (unsigned) (INTVAL (XEXP (X, 1)) + 0x8000) >= 0x10000)  \
-    { int high_int, low_int;                                   \
-      high_int = INTVAL (XEXP (X, 1)) >> 16;                   \
-      low_int = INTVAL (XEXP (X, 1)) & 0xffff;                 \
-      if (low_int & 0x8000)                                    \
-       high_int += 1, low_int |= 0xffff0000;                   \
-      (X) = gen_rtx (PLUS, SImode,                             \
-                    force_operand                              \
-                       (gen_rtx (PLUS, SImode, XEXP (X, 0), \
-                                 gen_rtx (CONST_INT, VOIDmode, \
-                                                     high_int << 16)), 0),\
-                    gen_rtx (CONST_INT, VOIDmode, low_int));   \
-      goto WIN;                                                        \
-    }                                                          \
-  else if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
-          && GET_CODE (XEXP (X, 1)) != CONST_INT               \
-          && (TARGET_HARD_FLOAT || (MODE) != DFmode)           \
-          && (MODE) != DImode && (MODE) != TImode)             \
-    {                                                          \
-      (X) = gen_rtx (PLUS, SImode, XEXP (X, 0),                        \
+#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)                            \
+{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG            \
+    && GET_CODE (XEXP (X, 1)) == CONST_INT                             \
+    && (unsigned) (INTVAL (XEXP (X, 1)) + 0x8000) >= 0x10000)          \
+    { int high_int, low_int;                                           \
+      high_int = INTVAL (XEXP (X, 1)) >> 16;                           \
+      low_int = INTVAL (XEXP (X, 1)) & 0xffff;                         \
+      if (low_int & 0x8000)                                            \
+       high_int += 1, low_int |= 0xffff0000;                           \
+      (X) = gen_rtx (PLUS, SImode,                                     \
+                    force_operand                                      \
+                       (gen_rtx (PLUS, SImode, XEXP (X, 0),            \
+                                 gen_rtx (CONST_INT, VOIDmode,         \
+                                                     high_int << 16)), 0), \
+                    gen_rtx (CONST_INT, VOIDmode, low_int));           \
+      goto WIN;                                                                \
+    }                                                                  \
+  else if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG       \
+          && GET_CODE (XEXP (X, 1)) != CONST_INT                       \
+          && (TARGET_HARD_FLOAT || (MODE) != DFmode)                   \
+          && (MODE) != DImode && (MODE) != TImode)                     \
+    {                                                                  \
+      (X) = gen_rtx (PLUS, SImode, XEXP (X, 0),                                \
                     force_reg (SImode, force_operand (XEXP (X, 1), 0))); \
-      goto WIN;                                                        \
-    }                                                          \
+      goto WIN;                                                                \
+    }                                                                  \
+  else if (TARGET_ELF && !TARGET_64BIT && TARGET_NO_TOC                        \
+          && GET_CODE (X) != CONST_INT                                 \
+          && GET_CODE (X) != CONST_DOUBLE && CONSTANT_P (X)            \
+          && (TARGET_HARD_FLOAT || (MODE) != DFmode)                   \
+          && (MODE) != DImode && (MODE) != TImode)                     \
+    {                                                                  \
+      rtx reg = gen_reg_rtx (Pmode);                                   \
+      emit_insn (gen_elf_high (reg, (X)));                             \
+      (X) = gen_rtx (LO_SUM, Pmode, reg, (X));                         \
+    }                                                                  \
 }
 
 /* Go to LABEL if ADDR (a legitimate address expression)
@@ -1462,6 +1548,8 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
     goto LABEL;                                                        \
   if (GET_CODE (ADDR) == PRE_DEC)                              \
     goto LABEL;                                                        \
+  if (GET_CODE (ADDR) == LO_SUM)                               \
+    goto LABEL;                                                        \
 }
 \f
 /* Define this if some processing needs to be done immediately before
@@ -1561,7 +1649,7 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
    The sle and sre instructions which allow SHIFT_COUNT_TRUNCATED
    have been dropped from the PowerPC architecture.  */
 
-#define SHIFT_COUNT_TRUNCATED TARGET_POWER ? 1 : 0
+#define SHIFT_COUNT_TRUNCATED (TARGET_POWER ? 1 : 0)
 
 /* Use atexit for static constructors/destructors, instead of defining
    our own exit function.  */
@@ -1575,12 +1663,13 @@ struct rs6000_args {int words, fregno, nargs_prototype; };
    On the RS/6000, if it is valid in the insn, it is free.  So this
    always returns 0.  */
 
-#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
+#define CONST_COSTS(RTX,CODE,OUTER_CODE)                       \
   case CONST_INT:                                              \
   case CONST:                                                  \
   case LABEL_REF:                                              \
   case SYMBOL_REF:                                             \
   case CONST_DOUBLE:                                           \
+  case HIGH:                                                   \
     return 0;
 
 /* Provide the costs of a rtl expression.  This is in the body of a
@@ -1894,7 +1983,7 @@ toc_section ()                                            \
   fprintf (FILE, "\t.long .");                                 \
   RS6000_OUTPUT_BASENAME (FILE, NAME);                         \
   fprintf (FILE, ", TOC[tc0], 0\n");                           \
-  fprintf (FILE, ".csect .text[PR]\n.");                               \
+  fprintf (FILE, ".csect .text[PR]\n.");                       \
   RS6000_OUTPUT_BASENAME (FILE, NAME);                         \
   fprintf (FILE, ":\n");                                       \
   if (write_symbols == XCOFF_DEBUG)                            \
@@ -1909,15 +1998,16 @@ toc_section ()                                          \
    we can't check that since not every file that uses
    GO_IF_LEGITIMATE_ADDRESS_P includes real.h.  */
 
-#define ASM_OUTPUT_SPECIAL_POOL_ENTRY_P(X)                     \
-  (GET_CODE (X) == SYMBOL_REF                                  \
-   || (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
-       && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF)      \
-   || GET_CODE (X) == LABEL_REF                                        \
-   || (! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)         \
-       && GET_CODE (X) == CONST_DOUBLE                         \
-       && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT          \
-       && BITS_PER_WORD == HOST_BITS_PER_INT))
+#define ASM_OUTPUT_SPECIAL_POOL_ENTRY_P(X)                             \
+  (TARGET_TOC                                                          \
+   && (GET_CODE (X) == SYMBOL_REF                                      \
+       || (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS     \
+          && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF)           \
+       || GET_CODE (X) == LABEL_REF                                    \
+       || (! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)             \
+          && GET_CODE (X) == CONST_DOUBLE                              \
+          && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT               \
+          && BITS_PER_WORD == HOST_BITS_PER_INT)))
 
 /* Select section for constant in constant pool.
 
@@ -2230,15 +2320,23 @@ toc_section ()                                          \
 /* This is how to output code to push a register on the stack.
    It need not be very fast code.  */
 
-#define ASM_OUTPUT_REG_PUSH(FILE,REGNO)  \
-  asm_fprintf (FILE, "\{tstu|stwu} %s,-4(r1)\n", reg_names[REGNO]);
+#define ASM_OUTPUT_REG_PUSH(FILE,REGNO)                                        \
+do {                                                                   \
+  extern char *reg_names[];                                            \
+  asm_fprintf (FILE, "\{tstu|stwu} %s,-4(%s)\n", reg_names[REGNO],     \
+              reg_names[1]);                                           \
+} while (0)
 
 /* This is how to output an insn to pop a register from the stack.
    It need not be very fast code.  */
 
-#define ASM_OUTPUT_REG_POP(FILE,REGNO)  \
-  asm_fprintf (FILE, "\t{l|lwz} %s,0(r1)\n\t{ai|addic} r1,r1,4\n",  \
-    reg_names[REGNO])
+#define ASM_OUTPUT_REG_POP(FILE,REGNO)                                 \
+do {                                                                   \
+  extern char *reg_names[];                                            \
+  asm_fprintf (FILE, "\t{l|lwz} %s,0(%s)\n\t{ai|addic} %s,%s,4\n",     \
+              reg_names[REGNO], reg_names[1], reg_names[1],            \
+              reg_names[1]);                                           \
+} while (0)
 
 /* This is how to output an element of a case-vector that is absolute. 
    (RS/6000 does not use such vectors, but we must define this macro
@@ -2396,6 +2494,13 @@ extern int lwa_operand ();
 extern int call_operand ();
 extern int current_file_function_operand ();
 extern int input_operand ();
+extern void init_cumulative_args ();
+extern void function_arg_advance ();
+extern struct rtx_def *function_arg ();
+extern int function_arg_partial_nregs ();
+extern int function_arg_pass_by_reference ();
+extern void setup_incoming_varargs ();
+extern struct rtx_def *expand_builtin_saveregs ();
 extern int expand_block_move ();
 extern int load_multiple_operation ();
 extern int store_multiple_operation ();
@@ -2411,10 +2516,8 @@ extern void print_operand ();
 extern void print_operand_address ();
 extern int first_reg_to_save ();
 extern int first_fp_reg_to_save ();
-extern int must_save_cr ();
-extern int rs6000_sa_size ();
 extern int rs6000_makes_calls ();
-extern int rs6000_pushes_stack ();
+extern rs6000_stack_t *rs6000_stack_info ();
 extern void svr4_traceback ();
 extern void output_prolog ();
 extern void output_epilog ();
index 2899ecb..06de488 100644 (file)
    (use (reg:DF 33))
    (parallel [(set (reg:SI 3)
                   (call (mem:SI (match_operand 2 "" "")) (const_int 0)))
+             (use (const_int 0))
              (clobber (scratch:SI))])
    (set (match_operand:SI 0 "gpc_reg_operand" "")
        (reg:SI 3))]
   [(set_attr "type" "delayed_compare")])
 \f
 ;; Now define ways of moving data around.
-;;
+
+;; Elf specific ways of loading addresses for non-PIC code.
+;; The output of this could be r0, but we limit it to base
+;; registers, since almost all uses of this will need it
+;; in a base register shortly.
+(define_insn "elf_high"
+  [(set (match_operand:SI 0 "register_operand" "=b")
+       (high:SI (match_operand 1 "" "")))]
+  "TARGET_ELF && !TARGET_64BIT"
+  "{cau|addis} %0,0,%1@ha")
+
+(define_insn "elf_low"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (lo_sum:SI (match_operand:SI 1 "register_operand" "b")
+                  (match_operand 2 "" "")))]
+   "TARGET_ELF && !TARGET_64BIT"
+   "{cal %0,%a2@l(%1)|addi %0,%1,%2@l}")
+
 ;; For SI, we special-case integers that can't be loaded in one insn.  We
 ;; do the load 16-bits at a time.  We could do this by loading from memory,
 ;; and this is even supposed to be faster, but it is simpler not to get
   if (GET_CODE (operands[1]) == CONST_DOUBLE)
     operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
 
-  if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT
+  if (TARGET_ELF && TARGET_NO_TOC && !TARGET_64BIT
+      && CONSTANT_P (operands[1])
+      && GET_CODE (operands[1]) != HIGH
+      && GET_CODE (operands[1]) != CONST_INT)
+    {
+      rtx target = (reload_completed || reload_in_progress)
+                       ? operands[0] : gen_reg_rtx (SImode);
+
+      emit_insn (gen_elf_high (target, operands[1]));
+      emit_insn (gen_elf_low (operands[0], target, operands[1]));
+      DONE;
+    }
+
+  if (CONSTANT_P (operands[1])
+      && GET_CODE (operands[1]) != CONST_INT
+      && GET_CODE (operands[1]) != HIGH
       && ! LEGITIMATE_CONSTANT_POOL_ADDRESS_P (operands[1]))
     {
       /* If we are to limit the number of things we put in the TOC and
   "lwaux %3,%0,%2"
   [(set_attr "type" "load")])
 
-(define_insn ""
+(define_insn "movdi_update"
   [(set (mem:DI (plus:DI (match_operand:DI 1 "gpc_reg_operand" "0,0")
                         (match_operand:DI 2 "reg_or_short_operand" "r,I")))
        (match_operand:DI 3 "gpc_reg_operand" "r,r"))
    {lu|lwzu} %3,%2(%0)"
   [(set_attr "type" "load")])
 
-(define_insn ""
+(define_insn "movsi_update"
   [(set (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
                         (match_operand:SI 2 "reg_or_short_operand" "r,I")))
        (match_operand:SI 3 "gpc_reg_operand" "r,r"))
        (minus:SI (reg:SI 1) (match_operand:SI 0 "reg_or_short_operand" "")))]
   ""
   "
-{ rtx chain = gen_reg_rtx (SImode);
+{ rtx chain = gen_reg_rtx (Pmode);
   rtx stack_bot = gen_rtx (MEM, Pmode, stack_pointer_rtx);
+  rtx neg_op0;
+  rtx lr_addr = NULL_RTX;
+  rtx lr = NULL_RTX;
 
   emit_move_insn (chain, stack_bot);
-  emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, operands[0]));
-  emit_move_insn (stack_bot, chain);
+
+#ifdef TARGET_V4_CALLS
+  if (TARGET_V4_CALLS)
+    {
+      lr = gen_reg_rtx (Pmode);
+      lr_addr = gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode,
+                                             stack_pointer_rtx,
+                                             GEN_INT (4)));
+      emit_move_insn (lr, lr_addr);
+    }
+#endif
+
+  if (GET_CODE (operands[0]) != CONST_INT
+      || INTVAL (operands[0]) < -32767
+      || INTVAL (operands[0]) > 32768)
+    {
+      neg_op0 = gen_reg_rtx (Pmode);
+      if (TARGET_POWERPC64)
+       emit_insn (gen_negdi2 (neg_op0, operands[0]));
+      else
+       emit_insn (gen_negsi2 (neg_op0, operands[0]));
+    }
+  else
+    neg_op0 = GEN_INT (- INTVAL (operands[0]));
+
+  if (TARGET_POWERPC64)
+    emit_insn (gen_movdi_update (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain));
+  else
+    emit_insn (gen_movsi_update (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain));
+
+#ifdef TARGET_V4_CALLS
+  if (TARGET_V4_CALLS)
+    emit_move_insn (lr_addr, lr);
+#endif
+
   DONE;
 }")
 
 (define_expand "call"
   [(parallel [(call (mem:SI (match_operand:SI 0 "address_operand" ""))
                    (match_operand 1 "" ""))
+             (use (match_operand 2 "" ""))
              (clobber (scratch:SI))])]
   ""
   "
   [(parallel [(set (match_operand 0 "" "")
                   (call (mem:SI (match_operand:SI 1 "address_operand" ""))
                         (match_operand 2 "" "")))
+             (use (match_operand 3 "" ""))
              (clobber (scratch:SI))])]
   ""
   "
 }")
 
 ;; Call to function in current module.  No TOC pointer reload needed.
+;; Operand2 is non-zero if we are using the V.4 calling sequence and
+;; either the function was not prototyped, or it was prototyped as a
+;; variable argument function.  It is > 0 if FP registers were passed
+;; and < 0 if they were not.
 
 (define_insn ""
-  [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s"))
-        (match_operand 1 "" "g"))
-   (clobber (match_scratch:SI 2 "=l"))]
+  [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
+        (match_operand 1 "" "g,g"))
+   (use (match_operand:SI 2 "immediate_operand" "O,n"))
+   (clobber (match_scratch:SI 3 "=l,l"))]
   ""
-  "bl %z0")
+  "*
+{
+  if (INTVAL (operands[2]) > 0)
+    return \"creqv 6,6,6\;bl %z0\";
+
+  else if (INTVAL (operands[2]) < 0)
+    return \"crxor 6,6,6\;bl %z0\";
+
+  return \"bl %z0\";
+}"
+  [(set_attr "length" "4,8")])
 
 ;; Call to function which may be in another module.  Restore the TOC
 ;; pointer (r2) after the call unless this is System V.
+;; Operand2 is non-zero if we are using the V.4 calling sequence and
+;; either the function was not prototyped, or it was prototyped as a
+;; variable argument function.  It is > 0 if FP registers were passed
+;; and < 0 if they were not.
 
 (define_insn ""
-  [(call (mem:SI (match_operand:SI 0 "call_operand" "l,s"))
-        (match_operand 1 "" "fg,fg"))
-   (clobber (match_scratch:SI 2 "=l,l"))]
+  [(call (mem:SI (match_operand:SI 0 "call_operand" "l,s,l,s"))
+        (match_operand 1 "" "fg,fg,fg,fg"))
+   (use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
+   (clobber (match_scratch:SI 3 "=l,l,l,l"))]
   ""
   "*
 {
+  if (INTVAL (operands[2]) > 0)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  else if (INTVAL (operands[2]) < 0)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
 #ifndef USING_SVR4_H
   if (GET_CODE (operands[0]) == REG)
     return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
   return \"bl %z0\";
 #endif
 }"
-  [(set_attr "length" "8")])
+  [(set_attr "length" "8,8,12,12")])
 
 (define_insn ""
-  [(set (match_operand 0 "" "=fg")
-       (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s"))
-             (match_operand 2 "" "g")))
-   (clobber (match_scratch:SI 3 "=l"))]
+  [(set (match_operand 0 "" "=fg,fg")
+       (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
+             (match_operand 2 "" "g,g")))
+   (use (match_operand:SI 3 "immediate_operand" "O,n"))
+   (clobber (match_scratch:SI 4 "=l,l"))]
   ""
-  "bl %z1")
+  "*
+{
+  if (INTVAL (operands[3]) > 0)
+    return \"creqv 6,6,6\;bl %z1\";
+
+  else if (INTVAL (operands[3]) < 0)
+    return \"crxor 6,6,6\;bl %z1\";
+
+  return \"bl %z1\";
+}"
+  [(set_attr "length" "4,8")])
 
 (define_insn ""
-  [(set (match_operand 0 "" "=fg,fg")
-       (call (mem:SI (match_operand:SI 1 "call_operand" "l,s"))
-             (match_operand 2 "" "fg,fg")))
-   (clobber (match_scratch:SI 3 "=l,l"))]
+  [(set (match_operand 0 "" "=fg,fg,fg,fg")
+       (call (mem:SI (match_operand:SI 1 "call_operand" "l,s,l,s"))
+             (match_operand 2 "" "fg,fg,fg,fg")))
+   (use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
+   (clobber (match_scratch:SI 4 "=l,l,l,l"))]
   ""
   "*
 {
+  if (INTVAL (operands[3]) > 0)
+    output_asm_insn (\"creqv 6,6,6\", operands);
+
+  else if (INTVAL (operands[3]) < 0)
+    output_asm_insn (\"crxor 6,6,6\", operands);
+
 #ifndef USING_SVR4_H
   if (GET_CODE (operands[1]) == REG)
     return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
   return \"bl %z1\";
 #endif
 }"
-  [(set_attr "length" "8")])
+  [(set_attr "length" "8,8,12,12")])
 
 ;; Call subroutine returning any type.
 
 {
   int i;
 
-  emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
+  emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx, const0_rtx));
 
   for (i = 0; i < XVECLEN (operands[2], 0); i++)
     {
   [(unspec_volatile [(const_int 0)] 0)]
   ""
   "")
+
+;; Sync instruction used for V.4 trampolines
+(define_insn "sync"
+  [(unspec [(match_operand 0 "" "")] 1)]
+  ""
+  "sync")
+
 \f
 ;; Compare insns are next.  Note that the RS/6000 has two types of compares,
 ;; signed & unsigned, and one type of branch.
index bf0cf34..d79cc94 100644 (file)
@@ -27,20 +27,35 @@ Boston, MA 02111-1307, USA.  */
 #define MASK_RELOCATABLE       0x10000000      /* GOT pointers are PC relative */
 #define        MASK_NO_TRACEBACK       0x08000000      /* eliminate traceback words */
 #define MASK_LITTLE_ENDIAN     0x04000000      /* target is little endian */
-#define MASK_NO_TOC            0x02000000      /* do not use TOC for loading addresses */
+#define MASK_AIX_CALLS         0x02000000      /* Use AIX calling sequence */
+#define MASK_PROTOTYPE         0x01000000      /* Only prototyped fcns pass variable args */
 
 #define        TARGET_NO_BITFIELD_TYPE (target_flags & MASK_NO_BITFIELD_TYPE)
 #define TARGET_STRICT_ALIGN    (target_flags & MASK_STRICT_ALIGN)
 #define TARGET_RELOCATABLE     (target_flags & MASK_RELOCATABLE)
 #define TARGET_NO_TRACEBACK    (target_flags & MASK_NO_TRACEBACK)
 #define TARGET_LITTLE_ENDIAN   (target_flags & MASK_LITTLE_ENDIAN)
-#define TARGET_NO_TOC          (target_flags & MASK_NO_TOC)
+#define TARGET_AIX_CALLS       (target_flags & MASK_AIX_CALLS)
+#define        TARGET_PROTOTYPE        (target_flags & MASK_PROTOTYPE)
+#define        TARGET_TOC              (target_flags & (MASK_64BIT             \
+                                                | MASK_RELOCATABLE     \
+                                                | MASK_MINIMAL_TOC))
 
 #define        TARGET_BITFIELD_TYPE    (! TARGET_NO_BITFIELD_TYPE)
 #define        TARGET_TRACEBACK        (! TARGET_NO_TRACEBACK)
 #define TARGET_BIG_ENDIAN      (! TARGET_LITTLE_ENDIAN)
-#define TARGET_TOC             (! TARGET_NO_TOC)
+#define TARGET_NO_AIX_CALLS    (! TARGET_AIX_CALLS)
+#define        TARGET_NO_PROTOTYPE     (! TARGET_PROTOTYPE)
+#define        TARGET_NO_TOC           (! TARGET_TOC)
 
+#define TARGET_V4_CALLS                TARGET_NO_AIX_CALLS
+
+/* Pseudo target to indicate whether the object format is ELF
+   (to get around not having conditional compilation in the md file)  */
+#define        TARGET_ELF              1
+
+/* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be just
+   the same as -mminimal-toc.  */
 #undef SUBTARGET_SWITCHES
 #define SUBTARGET_SWITCHES                                             \
   { "bit-align",       -MASK_NO_BITFIELD_TYPE },                       \
@@ -55,8 +70,13 @@ Boston, MA 02111-1307, USA.  */
   { "little",           MASK_LITTLE_ENDIAN },                          \
   { "big-endian",      -MASK_LITTLE_ENDIAN },                          \
   { "big",             -MASK_LITTLE_ENDIAN },                          \
-  { "no-toc",           MASK_NO_TOC | MASK_MINIMAL_TOC },              \
-  { "toc",             -MASK_NO_TOC },
+  { "no-toc",           0 },                                           \
+  { "toc",              MASK_MINIMAL_TOC },                            \
+  { "full-toc",                 MASK_MINIMAL_TOC },                            \
+  { "call-aix",                 MASK_AIX_CALLS },                              \
+  { "call-sysv",       -MASK_AIX_CALLS },                              \
+  { "prototype",        MASK_PROTOTYPE },                              \
+  { "no-prototype",    -MASK_PROTOTYPE },
 
 /* Sometimes certain combinations of command options do not make sense
    on a particular target machine.  You can define a macro
@@ -69,23 +89,11 @@ Boston, MA 02111-1307, USA.  */
 
 #define SUBTARGET_OVERRIDE_OPTIONS                                     \
 do {                                                                   \
-  if (TARGET_RELOCATABLE && TARGET_NO_TOC)                             \
-    {                                                                  \
-      target_flags &= ~ MASK_NO_TOC;                                   \
-      error ("-mrelocatable and -mno-toc are incompatible.");          \
-    }                                                                  \
-                                                                       \
   if (TARGET_RELOCATABLE && !TARGET_MINIMAL_TOC)                       \
     {                                                                  \
       target_flags |= MASK_MINIMAL_TOC;                                        \
       error ("-mrelocatable and -mno-minimal-toc are incompatible.");  \
     }                                                                  \
-                                                                       \
-  if (TARGET_NO_TOC && !TARGET_MINIMAL_TOC)                            \
-    {                                                                  \
-      target_flags |= MASK_MINIMAL_TOC;                                        \
-      error ("-mno-toc and -mno-minimal-toc are incompatible.");       \
-    }                                                                  \
 } while (0)
 
 #include "rs6000/powerpc.h"
@@ -96,12 +104,38 @@ do {                                                                       \
 #undef FIXED_R13
 #define FIXED_R13 1
 
+/* System V.4 passes the first 8 floating arguments in registers,
+   instead of the first 13 like AIX does.  */
+#undef FP_ARG_MAX_REG
+#define        FP_ARG_AIX_MAX_REG      45
+#define        FP_ARG_V4_MAX_REG       40
+#define        FP_ARG_MAX_REG ((TARGET_AIX_CALLS) ? FP_ARG_AIX_MAX_REG : FP_ARG_V4_MAX_REG)
+
+/* Size of the V.4 varargs area if needed */
+#undef RS6000_VARARGS_AREA
+#define RS6000_VARARGS_AREA ((rs6000_sysv_varargs_p) ? RS6000_VARARGS_SIZE : 0)
+
 /* Override default big endianism */
 #undef  BYTES_BIG_ENDIAN
 #undef  WORDS_BIG_ENDIAN
 #define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN)
 #define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN)
 
+/* Size of the outgoing register save area */
+#undef RS6000_REG_SAVE
+#define RS6000_REG_SAVE (TARGET_AIX_CALLS ? (TARGET_64BIT ? 64 : 32) : 0)
+
+/* Size of the fixed area on the stack.  For AIX, use the standard 6 word
+   area, otherwise use 2 words to store back chain & LR.  */
+#undef RS6000_SAVE_AREA
+#define RS6000_SAVE_AREA \
+  ((TARGET_AIX_CALLS ? 24 : 8) << (TARGET_64BIT ? 1 : 0))
+
+/* Define cutoff for using external functions to save floating point.
+   Currently on V.4, always use inline stores */
+#undef FP_SAVE_INLINE
+#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 64)
+
 /* Don't generate XCOFF debugging information.  */
 
 #undef XCOFF_DEBUGGING_INFO
@@ -192,37 +226,14 @@ toc_section ()                                                            \
                                                                        \
   if (in_section != in_toc)                                            \
     {                                                                  \
+      in_section = in_toc;                                             \
+      fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);      \
       if (! toc_initialized)                                           \
        {                                                               \
-         if (!TARGET_RELOCATABLE && !TARGET_NO_TOC)                    \
-           fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);         \
-                                                                       \
-         if (TARGET_MINIMAL_TOC)                                       \
-           {                                                           \
-             if (!TARGET_RELOCATABLE && !TARGET_NO_TOC)                \
-               {                                                       \
-                 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LCTOC", 0); \
-                 fprintf (asm_out_file, "\t.tc ");                     \
-                 ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1[TC],"); \
-                 ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
-                 fprintf (asm_out_file, "\n");                         \
-               }                                                       \
-                                                                       \
-             fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
-             ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
-             fprintf (asm_out_file, " = .+32768\n");                   \
-           }                                                           \
-                                                                       \
+         ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");    \
+         fprintf (asm_out_file, " = .+32768\n");                       \
          toc_initialized = 1;                                          \
        }                                                               \
-                                                                       \
-      else                                                             \
-       fprintf (asm_out_file, "%s\n",                                  \
-                (TARGET_MINIMAL_TOC                                    \
-                 ? MINIMAL_TOC_SECTION_ASM_OP                          \
-                 : TOC_SECTION_ASM_OP));                               \
-                                                                       \
-      in_section = in_toc;                                             \
     }                                                                  \
 }
 
@@ -342,7 +353,78 @@ while (0)
 
 #undef TARGET_VERSION
 #define TARGET_VERSION fprintf (stderr, " (PowerPC System V.4)");
+\f
+
+/* Output assembler code for a block containing the constant parts
+   of a trampoline, leaving space for the variable parts.
+
+   The trampoline should set the static chain pointer to value placed
+   into the trampoline and should branch to the specified routine.
+
+   Unlike AIX, this needs real code.  */
+
+#undef TRAMPOLINE_TEMPLATE
+#define TRAMPOLINE_TEMPLATE(FILE)                                      \
+do {                                                                   \
+  char *sc = reg_names[STATIC_CHAIN_REGNUM];                           \
+  char *r0 = reg_names[0];                                             \
+                                                                       \
+  if (STATIC_CHAIN_REGNUM == 0 || !TARGET_NEW_MNEMONICS)               \
+    abort ();                                                          \
+                                                                       \
+  if (TARGET_64BIT)                                                    \
+    {                                                                  \
+      fprintf (FILE, "\tmflr %s\n", r0);               /* offset  0 */ \
+      fprintf (FILE, "\tbl .LTRAMP1\n");               /* offset  4 */ \
+      fprintf (FILE, "\t.long 0,0,0,0\n");             /* offset  8 */ \
+      fprintf (FILE, ".LTRAMP1:\n");                                   \
+      fprintf (FILE, "\tmflr %s\n", sc);               /* offset 28 */ \
+      fprintf (FILE, "\tmtlr %s\n", r0);               /* offset 32 */ \
+      fprintf (FILE, "\tld %s,0(%s)\n", r0, sc);       /* offset 36 */ \
+      fprintf (FILE, "\tld %s,8(%s)\n", sc, sc);       /* offset 40 */ \
+      fprintf (FILE, "\tmtctr %s\n", r0);              /* offset 44 */ \
+      fprintf (FILE, "\tbctr\n");                      /* offset 48 */ \
+    }                                                                  \
+  else                                                                 \
+    {                                                                  \
+      fprintf (FILE, "\tmflr %s\n", r0);               /* offset  0 */ \
+      fprintf (FILE, "\tbl .LTRAMP1\n");               /* offset  4 */ \
+      fprintf (FILE, "\t.long 0,0\n");                 /* offset  8 */ \
+      fprintf (FILE, ".LTRAMP1:\n");                                   \
+      fprintf (FILE, "\tmflr %s\n", sc);               /* offset 20 */ \
+      fprintf (FILE, "\tmtlr %s\n", r0);               /* offset 24 */ \
+      fprintf (FILE, "\tlwz %s,0(%s)\n", r0, sc);      /* offset 28 */ \
+      fprintf (FILE, "\tlwz %s,4(%s)\n", sc, sc);      /* offset 32 */ \
+      fprintf (FILE, "\tmtctr %s\n", r0);              /* offset 36 */ \
+      fprintf (FILE, "\tbctr\n");                      /* offset 40 */ \
+    }                                                                  \
+} while (0)
+
+/* Length in units of the trampoline for entering a nested function.  */
+
+#undef TRAMPOLINE_SIZE
+#define TRAMPOLINE_SIZE    (TARGET_64BIT ? 52 : 44)
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+   FNADDR is an RTX for the address of the function's pure code.
+   CXT is an RTX for the static chain value for the function.  */
+
+#undef INITIALIZE_TRAMPOLINE
+#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT)                       \
+{                                                                      \
+  rtx reg = gen_reg_rtx (Pmode);                                       \
+                                                                       \
+  emit_move_insn (reg, FNADDR);                                                \
+  emit_move_insn (gen_rtx (MEM, Pmode,                                 \
+                          plus_constant (ADDR, 8)),                    \
+                 reg);                                                 \
+  emit_move_insn (gen_rtx (MEM, Pmode,                                 \
+                          plus_constant (ADDR, (TARGET_64BIT ? 16 : 12))), \
+                 CXT);                                                 \
+  emit_insn (gen_sync (gen_rtx (MEM, BLKmode, ADDR)));                 \
+}
 
+\f
 #undef CPP_PREDEFINES
 #define CPP_PREDEFINES \
   "-DPPC -Dunix -D__svr4__ -Asystem(unix) -Asystem(svr4) -Acpu(powerpc) -Amachine(powerpc)"
@@ -382,6 +464,8 @@ while (0)
 #define CPP_SPEC "\
 %{posix: -D_POSIX_SOURCE} \
 %{mrelocatable: -D_RELOCATABLE} \
+%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_SYSV}} \
+%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
 %{mlittle: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
 %{mlittle-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)} \
 %{!mlittle: %{!mlittle-endian: -D_BIG_ENDIAN -Amachine(bigendian)}} \
index c72bdb0..59bd1b7 100644 (file)
@@ -29,6 +29,8 @@ Boston, MA 02111-1307, USA.  */
 #define CPP_SPEC "\
 %{posix: -D_POSIX_SOURCE} \
 %{mrelocatable: -D_RELOCATABLE} \
+%{mcall-sysv: -D_CALL_SYSV} %{mcall-aix: -D_CALL_AIX} %{!mcall-sysv: %{!mcall-aix: -D_CALL_SYSV}} \
+%{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT} \
 %{mbig: -D_BIG_ENDIAN -Amachine(bigendian)} \
 %{mbig-endian: -D_BIG_ENDIAN -Amachine(bigendian)} \
 %{!mbig: %{!mbig-endian: -D_LITTLE_ENDIAN -Amachine(littleendian)}} \
index aa87b5e..db4b936 100644 (file)
@@ -16,15 +16,12 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
 # Build libgcc.a with different options.
 
 MULTILIB_OPTIONS       = msoft-float \
-                         mno-toc \
-                         mlittle/mbig
+                         mlittle
 
 MULTILIB_DIRNAMES      = soft-float \
-                         no-toc \
-                         little-endian big-endian
+                         little-endian
 
 MULTILIB_MATCHES       = mlittle=mlittle-endian \
-                         mbig=mbig-endian \
                          msoft-float=mcpu?403 \
                          msoft-float=mcpu?mpc403 \
                          msoft-float=mcpu?ppc403
index ee40677..382d15b 100644 (file)
@@ -15,8 +15,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
 
 # Build the libraries for both hard and soft floating point
 
-MULTILIB_OPTIONS = msoft-float
-MULTILIB_DIRNAMES = soft-float
+MULTILIB_OPTIONS = msoft-float mcpu=common
+MULTILIB_DIRNAMES = soft-float common
 
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib