OSDN Git Service

(rs6000_output_load_toc_table): New function.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 4298987..c009eff 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines used for code generation on IBM RS/6000.
-   Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1991, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GNU CC.
@@ -36,6 +36,8 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "obstack.h"
 #include "tree.h"
+#include "except.h"
+#include "function.h"
 
 #ifndef TARGET_NO_PROTOTYPE
 #define TARGET_NO_PROTOTYPE 0
@@ -93,150 +95,47 @@ char *rs6000_sdata_name = (char *)0;
 /* Whether a System V.4 varargs area was created.  */
 int rs6000_sysv_varargs_p;
 
-/* Whether we need to save the TOC register.  */
-int rs6000_save_toc_p;
-
 /* ABI enumeration available for subtarget to use.  */
 enum rs6000_abi rs6000_current_abi;
 
+/* Offset & size for fpmem stack locations used for converting between
+   float and integral types.  */
+int rs6000_fpmem_offset;
+int rs6000_fpmem_size;
+
 \f
 /* Default register names.  */
 char rs6000_reg_names[][8] =
 {
-   "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
-   "8",  "9", "10", "11", "12", "13", "14", "15",
-  "16", "17", "18", "19", "20", "21", "22", "23",
-  "24", "25", "26", "27", "28", "29", "30", "31",
-   "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
-   "8",  "9", "10", "11", "12", "13", "14", "15",
-  "16", "17", "18", "19", "20", "21", "22", "23",
-  "24", "25", "26", "27", "28", "29", "30", "31",
-  "mq", "lr", "ctr","ap",
-   "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7"
+      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
+      "8",  "9", "10", "11", "12", "13", "14", "15",
+     "16", "17", "18", "19", "20", "21", "22", "23",
+     "24", "25", "26", "27", "28", "29", "30", "31",
+      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
+      "8",  "9", "10", "11", "12", "13", "14", "15",
+     "16", "17", "18", "19", "20", "21", "22", "23",
+     "24", "25", "26", "27", "28", "29", "30", "31",
+     "mq", "lr", "ctr","ap",
+      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
+  "fpmem"
 };
 
 #ifdef TARGET_REGNAMES
 static char alt_reg_names[][8] =
 {
-   "%r0",  "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
-   "%r8",  "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
-  "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
-  "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
-   "%f0",  "%f1",  "%f2",  "%f3",  "%f4",  "%f5",  "%f6",  "%f7",
-   "%f8",  "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
-  "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
-  "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
-    "mq",   "lr",  "ctr",   "ap",
-  "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7"
+   "%r0",   "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
+   "%r8",   "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+  "%r16",  "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
+  "%r24",  "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
+   "%f0",   "%f1",  "%f2",  "%f3",  "%f4",  "%f5",  "%f6",  "%f7",
+   "%f8",   "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+  "%f16",  "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+  "%f24",  "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+    "mq",    "lr",  "ctr",   "ap",
+  "%cr0",  "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
+ "fpmem"
 };
 #endif
-
-
-\f
-/* Print the options used in the assembly file.  */
-
-extern char *version_string, *language_string;
-
-struct asm_option
-{
-  char *string;
-  int *variable;
-  int on_value;
-};
-
-#define MAX_LINE 79
-
-static int
-output_option (file, type, name, pos)
-     FILE *file;
-     char *type;
-     char *name;
-     int pos;
-{
-  int type_len = strlen (type);
-  int name_len = strlen (name);
-
-  if (1 + type_len + name_len + pos > MAX_LINE)
-    {
-      fprintf (file, "\n # %s%s", type, name);
-      return 3 + type_len + name_len;
-    }
-  fprintf (file, " %s%s", type, name);
-  return pos + 1 + type_len + name_len;
-}
-
-static struct { char *name; int value; } m_options[] = TARGET_SWITCHES;
-
-void
-output_options (file, f_options, f_len, W_options, W_len)
-     FILE *file;
-     struct asm_option *f_options;
-     int f_len;
-     struct asm_option *W_options;
-     int W_len;
-{
-  int j;
-  int flags = target_flags;
-  int pos = 32767;
-
-  fprintf (file, " # %s %s", language_string, version_string);
-
-  if (optimize)
-    {
-      char opt_string[20];
-      sprintf (opt_string, "%d", optimize);
-      pos = output_option (file, "-O", opt_string, pos);
-    }
-
-  if (profile_flag)
-    pos = output_option (file, "-p", "", pos);
-
-  if (profile_block_flag)
-    pos = output_option (file, "-a", "", pos);
-
-  if (inhibit_warnings)
-    pos = output_option (file, "-w", "", pos);
-
-  for (j = 0; j < f_len; j++)
-    {
-      if (*f_options[j].variable == f_options[j].on_value)
-       pos = output_option (file, "-f", f_options[j].string, pos);
-    }
-
-  for (j = 0; j < W_len; j++)
-    {
-      if (*W_options[j].variable == W_options[j].on_value)
-       pos = output_option (file, "-W", W_options[j].string, pos);
-    }
-
-  for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
-    {
-      if (m_options[j].name[0] != '\0'
-         && m_options[j].value > 0
-         && ((m_options[j].value & flags) == m_options[j].value))
-       {
-         pos = output_option (file, "-m", m_options[j].name, pos);
-         flags &= ~ m_options[j].value;
-       }
-    }
-
-  for (j = 0; j < sizeof (rs6000_select) / sizeof(rs6000_select[0]); j++)
-    if (rs6000_select[j].string != (char *)0)
-      pos = output_option (file, rs6000_select[j].name, rs6000_select[j].string, pos);
-
-#ifdef USING_SVR4_H
-  switch (rs6000_sdata)
-    {
-    case SDATA_NONE: pos = output_option (file, "-msdata=", "none", pos); break;
-    case SDATA_DATA: pos = output_option (file, "-msdata=", "data", pos); break;
-    case SDATA_SYSV: pos = output_option (file, "-msdata=", "sysv", pos); break;
-    case SDATA_EABI: pos = output_option (file, "-msdata=", "eabi", pos); break;
-    }
-#endif
-
-  fputs ("\n\n", file);
-}
-
 \f
 /* Override command line options.  Mostly we process the processor
    type and sometimes adjust other TARGET_ options.  */
@@ -310,12 +209,21 @@ rs6000_override_options (default_cpu)
         {"604", PROCESSOR_PPC604,
            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
            POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+        {"604e", PROCESSOR_PPC604,
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
         {"620", PROCESSOR_PPC620,
            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
            POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+        {"801", PROCESSOR_MPCCORE,
+           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
         {"821", PROCESSOR_MPCCORE,
            MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
            POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+        {"823", PROCESSOR_MPCCORE,
+           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
         {"860", PROCESSOR_MPCCORE,
            MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
            POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}};
@@ -396,6 +304,55 @@ rs6000_override_options (default_cpu)
 #endif
 }
 \f
+/* Do anything needed at the start of the asm file.  */
+
+void
+rs6000_file_start (file, default_cpu)
+     FILE *file;
+     char *default_cpu;
+{
+  int i;
+  char buffer[80];
+  char *start = buffer;
+  struct rs6000_cpu_select *ptr;
+
+  if (flag_verbose_asm)
+    {
+      sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
+      rs6000_select[0].string = default_cpu;
+
+      for (i = 0; i < sizeof (rs6000_select) / sizeof (rs6000_select[0]); i++)
+       {
+         ptr = &rs6000_select[i];
+         if (ptr->string != (char *)0 && ptr->string[0] != '\0')
+           {
+             fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
+             start = "";
+           }
+       }
+
+#ifdef USING_SVR4_H
+      switch (rs6000_sdata)
+       {
+       case SDATA_NONE: fprintf (file, "%s -msdata=none", start); start = ""; break;
+       case SDATA_DATA: fprintf (file, "%s -msdata=data", start); start = ""; break;
+       case SDATA_SYSV: fprintf (file, "%s -msdata=sysv", start); start = ""; break;
+       case SDATA_EABI: fprintf (file, "%s -msdata=eabi", start); start = ""; break;
+       }
+
+      if (rs6000_sdata && g_switch_value)
+       {
+         fprintf (file, "%s -G %d", start, g_switch_value);
+         start = "";
+       }
+#endif
+
+      if (*start == '\0')
+       fputs ("\n", file);
+    }
+}
+
+\f
 /* Create a CONST_DOUBLE from a string.  */
 
 struct rtx_def *
@@ -470,6 +427,26 @@ int count_register_operand(op, mode)
   return 0;
 }
 
+/* Returns 1 if op is memory location for float/int conversions that masquerades
+   as a register.  */
+int fpmem_operand(op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) != REG)
+    return 0;
+
+  if (FPMEM_REGNO_P (REGNO (op)))
+    return 1;
+
+#if 0
+  if (REGNO (op) > FIRST_PSEUDO_REGISTER)
+    return 1;
+#endif
+
+  return 0;
+}
+
 /* Return 1 if OP is a constant that can fit in a D field.  */
 
 int
@@ -478,7 +455,7 @@ short_cint_operand (op, mode)
      enum machine_mode mode;
 {
   return (GET_CODE (op) == CONST_INT
-         && (unsigned) (INTVAL (op) + 0x8000) < 0x10000);
+         && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) < 0x10000);
 }
 
 /* Similar for a unsigned D field.  */
@@ -499,7 +476,7 @@ non_short_cint_operand (op, mode)
      enum machine_mode mode;
 {
   return (GET_CODE (op) == CONST_INT
-         && (unsigned) (INTVAL (op) + 0x8000) >= 0x10000);
+         && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000);
 }
 
 /* Returns 1 if OP is a register that is not special (i.e., not MQ,
@@ -511,7 +488,9 @@ gpc_reg_operand (op, mode)
      enum machine_mode mode;
 {
   return (register_operand (op, mode)
-         && (GET_CODE (op) != REG || REGNO (op) >= 67 || REGNO (op) < 64));
+         && (GET_CODE (op) != REG
+             || (REGNO (op) >= 67 && !FPMEM_REGNO_P (REGNO (op)))
+             || REGNO (op) < 64));
 }
 
 /* Returns 1 if OP is either a pseudo-register or a register denoting a
@@ -629,7 +608,7 @@ num_insns_constant_wide (value)
 
       else
        return (num_insns_constant_wide (high)
-               + num_insns_constant_low (low) + 1);
+               + num_insns_constant_wide (low) + 1);
     }
 #endif
 
@@ -642,12 +621,19 @@ num_insns_constant (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  if (mode != SImode && mode != DImode)
-    abort ();
-
   if (GET_CODE (op) == CONST_INT)
     return num_insns_constant_wide (INTVAL (op));
 
+  else if (GET_CODE (op) == CONST_DOUBLE && mode == SFmode)
+    {
+      long l;
+      REAL_VALUE_TYPE rv;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+      return num_insns_constant_wide ((HOST_WIDE_INT)l);
+    }
+
   else if (GET_CODE (op) == CONST_DOUBLE && TARGET_32BIT)
     return (num_insns_constant_wide (CONST_DOUBLE_LOW (op))
            + num_insns_constant_wide (CONST_DOUBLE_HIGH (op)));
@@ -694,6 +680,16 @@ easy_fp_constant (op, mode)
   if (TARGET_SOFT_FLOAT && mode != DImode)
     return 1;
 
+  /* If we are using V.4 style PIC, consider all constants to be hard */
+  if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+    return 0;
+
+#ifdef TARGET_RELOCATABLE
+  /* Similarly if we are using -mrelocatable, consider all constants to be hard */
+  if (TARGET_RELOCATABLE)
+    return 0;
+#endif
+
   if (mode == DFmode)
     {
       long k[2];
@@ -763,22 +759,6 @@ offsettable_addr_operand (op, mode)
                                mode, op);
 }
 
-/* Return 1 if the operand is either a floating-point register, a pseudo
-   register, or memory.  */
-
-int
-fp_reg_or_mem_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
-{
-  return (memory_operand (op, mode)
-         || volatile_mem_operand (op, mode)
-         || (register_operand (op, mode)
-             && (GET_CODE (op) != REG
-                 || REGNO (op) >= FIRST_PSEUDO_REGISTER
-                 || FP_REGNO_P (REGNO (op)))));
-}
-
 /* Return 1 if the operand is either an easy FP constant (see above) or
    memory.  */
 
@@ -810,7 +790,7 @@ non_add_cint_operand (op, mode)
      enum machine_mode mode;
 {
   return (GET_CODE (op) == CONST_INT
-         && (unsigned) (INTVAL (op) + 0x8000) >= 0x10000
+         && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000
          && (INTVAL (op) & 0xffff) != 0);
 }
 
@@ -1030,7 +1010,7 @@ small_data_operand (op, mode)
   if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
     return 0;
 
-  if (DEFAULT_ABI != ABI_V4 /* && DEFAULT_ABI != ABI_SOLARIS */)
+  if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
     return 0;
 
   if (GET_CODE (op) == SYMBOL_REF)
@@ -1061,7 +1041,7 @@ small_data_operand (op, mode)
    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.  */
+   so we never return a PARALLEL.  */
 
 void
 init_cumulative_args (cum, fntype, libname, incoming)
@@ -1081,7 +1061,7 @@ init_cumulative_args (cum, fntype, libname, incoming)
 
   if (incoming)
     {
-      cum->nargs_prototype = 1000;             /* don't return an EXPR_LIST */
+      cum->nargs_prototype = 1000;             /* don't return a PARALLEL */
       if (abi == ABI_V4 || abi == ABI_SOLARIS)
        cum->varargs_offset = RS6000_VARARGS_OFFSET;
     }
@@ -1230,7 +1210,7 @@ function_arg_advance (cum, mode, type, named)
    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.  */
+   doesn't support PARALLEL anyway.  */
 
 struct rtx_def *
 function_arg (cum, mode, type, named)
@@ -1279,17 +1259,37 @@ function_arg (cum, mode, type, named)
 
   if (USE_FP_FOR_ARG_P (*cum, mode, type))
     {
-      if ((cum->nargs_prototype > 0)
-         || DEFAULT_ABI == ABI_V4      /* V.4 never passes FP values in GP registers */
+      if (DEFAULT_ABI == ABI_V4 /* V.4 never passes FP values in GP registers */
          || DEFAULT_ABI == ABI_SOLARIS
-         || !type)
+         || ! type
+         || ((cum->nargs_prototype > 0)
+             /* IBM AIX extended its linkage convention definition always to
+                require FP args after register save area hole on the stack.  */
+             && (DEFAULT_ABI != ABI_AIX
+                 || ! TARGET_XL_CALL
+                 || (align_words < GP_ARG_NUM_REG))))
        return gen_rtx (REG, mode, cum->fregno);
 
-      return gen_rtx (EXPR_LIST, VOIDmode,
-                     ((align_words < GP_ARG_NUM_REG)
-                      ? gen_rtx (REG, mode, GP_ARG_MIN_REG + align_words)
-                      : NULL_RTX),
-                     gen_rtx (REG, mode, cum->fregno));
+      return gen_rtx (PARALLEL, mode,
+                     gen_rtvec
+                     (2,
+                      gen_rtx (EXPR_LIST, VOIDmode,
+                               ((align_words >= GP_ARG_NUM_REG)
+                                ? NULL_RTX
+                                : (align_words
+                                   + RS6000_ARG_SIZE (mode, type, named)
+                                   > GP_ARG_NUM_REG
+                                   /* If this is partially on the stack, then
+                                      we only include the portion actually
+                                      in registers here.  */
+                                   ? gen_rtx (REG, SImode,
+                                              GP_ARG_MIN_REG + align_words)
+                                   : gen_rtx (REG, mode,
+                                              GP_ARG_MIN_REG + align_words))),
+                               const0_rtx),
+                      gen_rtx (EXPR_LIST, VOIDmode,
+                               gen_rtx (REG, mode, cum->fregno),
+                               const0_rtx)));
     }
 
   /* Long longs won't be split between register and stack */
@@ -1892,7 +1892,7 @@ includes_rshift_p (shiftop, andop)
      register rtx shiftop;
      register rtx andop;
 {
-  unsigned shift_mask = ~0;
+  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
 
   shift_mask >>= INTVAL (shiftop);
 
@@ -2062,6 +2062,211 @@ ccr_bit (op, scc_p)
     }
 }
 \f
+/* Return the GOT register, creating it if needed.  */
+
+struct rtx_def *
+rs6000_got_register (value)
+     rtx value;
+{
+  if (!current_function_uses_pic_offset_table || !pic_offset_table_rtx)
+    {
+      if (reload_in_progress || reload_completed)
+       fatal_insn ("internal error -- needed new GOT register during reload phase to load:", value);
+
+      current_function_uses_pic_offset_table = 1;
+      pic_offset_table_rtx = gen_rtx (REG, Pmode, GOT_TOC_REGNUM);
+    }
+
+  return pic_offset_table_rtx;
+}
+
+\f
+/* Replace all occurances of register FROM with an new pseduo register in an insn X.
+   Store the pseudo register used in REG.
+   This is only safe during FINALIZE_PIC, since the registers haven't been setup
+   yet.  */
+
+static rtx
+rs6000_replace_regno (x, from, reg)
+     rtx x;
+     int from;
+     rtx *reg;
+{
+  register int i, j;
+  register char *fmt;
+
+  /* Allow this function to make replacements in EXPR_LISTs.  */
+  if (!x)
+    return x;
+
+  switch (GET_CODE (x))
+    {
+    case SCRATCH:
+    case PC:
+    case CC0:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return x;
+
+    case REG:
+      if (REGNO (x) == from)
+       {
+         if (! *reg)
+           *reg = pic_offset_table_rtx = gen_reg_rtx (Pmode);
+
+         return *reg;
+       }
+
+      return x;
+    }
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       XEXP (x, i) = rs6000_replace_regno (XEXP (x, i), from, reg);
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         XVECEXP (x, i, j) = rs6000_replace_regno (XVECEXP (x, i, j), from, reg);
+    }
+
+  return x;
+}  
+
+\f
+/* By generating position-independent code, when two different
+   programs (A and B) share a common library (libC.a), the text of
+   the library can be shared whether or not the library is linked at
+   the same address for both programs.  In some of these
+   environments, position-independent code requires not only the use
+   of different addressing modes, but also special code to enable the
+   use of these addressing modes.
+
+   The `FINALIZE_PIC' macro serves as a hook to emit these special
+   codes once the function is being compiled into assembly code, but
+   not before.  (It is not done before, because in the case of
+   compiling an inline function, it would lead to multiple PIC
+   prologues being included in functions which used inline functions
+   and were compiled to assembly language.)  */
+
+void
+rs6000_finalize_pic ()
+{
+  /* Loop through all of the insns, replacing the special GOT_TOC_REGNUM
+     with an appropriate pseduo register.  If we find we need GOT/TOC,
+     add the appropriate init code.  */
+  if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+    {
+      rtx insn = get_insns ();
+      rtx reg = NULL_RTX;
+      rtx first_insn;
+
+      if (GET_CODE (insn) == NOTE)
+       insn = next_nonnote_insn (insn);
+
+      first_insn = insn;
+      for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn))
+       {
+         if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+           {
+             PATTERN (insn) = rs6000_replace_regno (PATTERN (insn),
+                                                    GOT_TOC_REGNUM,
+                                                    &reg);
+
+             if (REG_NOTES (insn))
+               REG_NOTES (insn) = rs6000_replace_regno (REG_NOTES (insn),
+                                                        GOT_TOC_REGNUM,
+                                                        &reg);
+           }
+       }
+
+      if (reg)
+       {
+         rtx init = gen_init_v4_pic (reg);
+         emit_insn_before (init, first_insn);
+       }
+    }
+}
+
+\f
+/* Search for any occurrance of the GOT_TOC register marker that should
+   have been eliminated, but may have crept back in.  */
+
+void
+rs6000_reorg (insn)
+     rtx insn;
+{
+  if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+    {
+      rtx got_reg = gen_rtx (REG, Pmode, GOT_TOC_REGNUM);
+      for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn))
+       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+           && reg_mentioned_p (got_reg, PATTERN (insn)))
+         fatal_insn ("GOT/TOC register marker not removed:", PATTERN (insn));
+    }
+}
+
+\f
+/* Define the structure for the machine field in struct function.  */
+struct machine_function
+{
+  int sysv_varargs_p;
+  int save_toc_p;
+  int fpmem_size;
+  int fpmem_offset;
+};
+
+/* Functions to save and restore rs6000_fpmem_size.
+   These will be called, via pointer variables,
+   from push_function_context and pop_function_context.  */
+
+void
+rs6000_save_machine_status (p)
+     struct function *p;
+{
+  struct machine_function *machine =
+    (struct machine_function *) xmalloc (sizeof (struct machine_function));
+
+  p->machine = machine;
+  machine->sysv_varargs_p = rs6000_sysv_varargs_p;
+  machine->fpmem_size     = rs6000_fpmem_size;
+  machine->fpmem_offset   = rs6000_fpmem_offset;
+}
+
+void
+rs6000_restore_machine_status (p)
+     struct function *p;
+{
+  struct machine_function *machine = p->machine;
+
+  rs6000_sysv_varargs_p = machine->sysv_varargs_p;
+  rs6000_fpmem_size     = machine->fpmem_size;
+  rs6000_fpmem_offset   = machine->fpmem_offset;
+
+  free (machine);
+  p->machine = (struct machine_function *)0;
+}
+
+/* Do anything needed before RTL is emitted for each function.  */
+
+void
+rs6000_init_expanders ()
+{
+  /* Reset varargs and save TOC indicator */
+  rs6000_sysv_varargs_p = 0;
+  rs6000_fpmem_size = 0;
+  rs6000_fpmem_offset = 0;
+  pic_offset_table_rtx = (rtx)0;
+
+  /* Arrange to save and restore machine status around nested functions.  */
+  save_machine_status = rs6000_save_machine_status;
+  restore_machine_status = rs6000_restore_machine_status;
+}
+
+\f
 /* Print an operand.  Recognize special options, documented below.  */
 
 #ifdef TARGET_SDATA
@@ -2426,13 +2631,29 @@ print_operand (file, x, code)
       return;
       
     case 'u':
-      /* High-order 16 bits of constant.  */
+      /* High-order 16 bits of constant for use in unsigned operand.  */
       if (! INT_P (x))
        output_operand_lossage ("invalid %%u value");
 
       fprintf (file, "0x%x", (INT_LOWPART (x) >> 16) & 0xffff);
       return;
 
+    case 'v':
+      /* High-order 16 bits of constant for use in signed operand.  */
+      if (! INT_P (x))
+       output_operand_lossage ("invalid %%v value");
+
+      {
+       int value = (INT_LOWPART (x) >> 16) & 0xffff;
+
+       /* Solaris assembler doesn't like lis 0,0x80000 */
+       if (DEFAULT_ABI == ABI_SOLARIS && (value & 0x8000) != 0)
+         fprintf (file, "%d", value | (~0 << 16));
+       else
+         fprintf (file, "0x%x", value);
+       return;
+      }
+
     case 'U':
       /* Print `u' if this has an auto-increment or auto-decrement.  */
       if (GET_CODE (x) == MEM
@@ -2565,7 +2786,7 @@ print_operand_address (file, x)
 {
   if (GET_CODE (x) == REG)
     fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
-  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
+  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST || GET_CODE (x) == LABEL_REF)
     {
       output_addr_const (file, x);
       if (small_data_operand (x, GET_MODE (x)))
@@ -2616,7 +2837,7 @@ first_reg_to_save ()
       break;
 
   /* If profiling, then we must save/restore every register that contains
-     a parameter before/after the .mcount call.  Use registers from 30 down
+     a parameter before/after the .__mcount call.  Use registers from 30 down
      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.  */
@@ -2649,7 +2870,7 @@ rs6000_makes_calls ()
 {
   rtx insn;
 
-  /* If we are profiling, we will be making a call to mcount.  */
+  /* If we are profiling, we will be making a call to __mcount.  */
   if (profile_flag)
     return 1;
 
@@ -2686,9 +2907,11 @@ rs6000_makes_calls ()
                +---------------------------------------+
                | Local variable space (L)              | 24+P+A
                +---------------------------------------+
-               | Save area for GP registers (G)        | 24+P+A+L
+               | Float/int conversion temporary (X)    | 24+P+A+L
+               +---------------------------------------+
+               | Save area for GP registers (G)        | 24+P+A+X+L
                +---------------------------------------+
-               | Save area for FP registers (F)        | 24+P+A+L+G
+               | Save area for FP registers (F)        | 24+P+A+X+L+G
                +---------------------------------------+
        old SP->| back chain to caller's caller         |
                +---------------------------------------+
@@ -2703,16 +2926,18 @@ rs6000_makes_calls ()
                | 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
+               +---------------------------------------+    
+               | Float/int conversion temporary (X)    | 8+P+A+V+L
                +---------------------------------------+
-               | 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
+               | saved CR (C)                          | 8+P+A+V+L+X
+               +---------------------------------------+    
+               | Save area for GP registers (G)        | 8+P+A+V+L+X+C
+               +---------------------------------------+    
+               | Save area for FP registers (F)        | 8+P+A+V+L+X+C+G
                +---------------------------------------+
        old SP->| back chain to caller's caller         |
                +---------------------------------------+
@@ -2736,20 +2961,22 @@ rs6000_makes_calls ()
                | Parameter save area (P)               | 24
                +---------------------------------------+
                | Alloca space (A)                      | 24+P
-               +---------------------------------------+
+               +---------------------------------------+     
                | Local variable space (L)              | 24+P+A
+               +---------------------------------------+     
+               | Float/int conversion temporary (X)    | 24+P+A+L
                +---------------------------------------+
-               | Save area for FP registers (F)        | 24+P+A+L
-               +---------------------------------------+
-               | Possible alignment area (X)           | 24+P+A+L+F
-               +---------------------------------------+
-               | Save area for GP registers (G)        | 24+P+A+L+F+X
-               +---------------------------------------+
-               | Save area for CR (C)                  | 24+P+A+L+F+X+G
-               +---------------------------------------+
-               | Save area for TOC (T)                 | 24+P+A+L+F+X+G+C
-               +---------------------------------------+
-               | Save area for LR (R)                  | 24+P+A+L+F+X+G+C+T
+               | Save area for FP registers (F)        | 24+P+A+L+X
+               +---------------------------------------+     
+               | Possible alignment area (Y)           | 24+P+A+L+X+F
+               +---------------------------------------+     
+               | Save area for GP registers (G)        | 24+P+A+L+X+F+Y
+               +---------------------------------------+     
+               | Save area for CR (C)                  | 24+P+A+L+X+F+Y+G
+               +---------------------------------------+     
+               | Save area for TOC (T)                 | 24+P+A+L+X+F+Y+G+C
+               +---------------------------------------+     
+               | Save area for LR (R)                  | 24+P+A+L+X+F+Y+G+C+T
                +---------------------------------------+
        old SP->| back chain to caller's caller         |
                +---------------------------------------+
@@ -2760,6 +2987,10 @@ rs6000_makes_calls ()
    old SP.  To support calls through pointers, we also allocate a
    fixed slot to store the TOC, -8 off the old SP.  */
 
+#ifndef ABI_STACK_BOUNDARY
+#define ABI_STACK_BOUNDARY STACK_BOUNDARY
+#endif
+
 rs6000_stack_t *
 rs6000_stack_info ()
 {
@@ -2785,13 +3016,16 @@ rs6000_stack_info ()
   /* Does this function call anything? */
   info_ptr->calls_p = rs6000_makes_calls ();
 
-  /* Do we need to allocate space to save the toc? */
-  if (rs6000_save_toc_p)
+  /* Allocate space to save the toc. */
+  if (abi == ABI_NT && info_ptr->calls_p)
     {
       info_ptr->toc_save_p = 1;
       info_ptr->toc_size = reg_size;
     }
 
+  /* Does this machine need the float/int conversion area? */
+  info_ptr->fpmem_p = regs_ever_live[FPMEM_REGNUM];
+
   /* If this is main and we need to call a function to set things up,
      save main's arguments around the call.  */
 #ifdef TARGET_EABI
@@ -2856,6 +3090,7 @@ rs6000_stack_info ()
   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->fpmem_size  = (info_ptr->fpmem_p) ? 8 : 0;
   info_ptr->save_size    = ALIGN (info_ptr->fp_size
                                  + info_ptr->gp_size
                                  + info_ptr->cr_size
@@ -2865,11 +3100,12 @@ rs6000_stack_info ()
 
   total_raw_size        = (info_ptr->vars_size
                            + info_ptr->parm_size
+                           + info_ptr->fpmem_size
                            + info_ptr->save_size
                            + info_ptr->varargs_size
                            + info_ptr->fixed_size);
 
-  info_ptr->total_size   = ALIGN (total_raw_size, STACK_BOUNDARY / BITS_PER_UNIT);
+  info_ptr->total_size   = ALIGN (total_raw_size, ABI_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
@@ -2911,9 +3147,9 @@ rs6000_stack_info ()
     case ABI_SOLARIS:
       info_ptr->fp_save_offset   = - info_ptr->fp_size;
       info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
-      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - reg_size;
-      info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->cr_size;
-      info_ptr->main_save_offset = info_ptr->toc_save_offset - info_ptr->toc_size;
+      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
+      info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
+      info_ptr->main_save_offset = info_ptr->toc_save_offset - info_ptr->main_size;
       info_ptr->lr_save_offset   = reg_size;
       break;
 
@@ -2930,6 +3166,9 @@ rs6000_stack_info ()
       break;
     }
 
+  if (info_ptr->fpmem_p)
+    info_ptr->fpmem_offset = STARTING_FRAME_OFFSET - info_ptr->total_size + info_ptr->vars_size;
+
   /* Zero offsets if we're not saving those registers */
   if (!info_ptr->fp_size)
     info_ptr->fp_save_offset = 0;
@@ -2949,6 +3188,14 @@ rs6000_stack_info ()
   if (!info_ptr->main_save_p)
     info_ptr->main_save_offset = 0;
 
+  if (!info_ptr->fpmem_p)
+    info_ptr->fpmem_offset = 0;
+  else
+    {
+      rs6000_fpmem_size   = info_ptr->fpmem_size;
+      rs6000_fpmem_offset = info_ptr->total_size + info_ptr->fpmem_offset;
+    }
+
   return info_ptr;
 }
 
@@ -3006,6 +3253,9 @@ debug_stack_info (info)
   if (info->main_save_p)
     fprintf (stderr, "\tmain_save_p         = %5d\n", info->main_save_p);
 
+  if (info->fpmem_p)
+    fprintf (stderr, "\tfpmem_p             = %5d\n", info->fpmem_p);
+
   if (info->gp_save_offset)
     fprintf (stderr, "\tgp_save_offset      = %5d\n", info->gp_save_offset);
 
@@ -3027,6 +3277,9 @@ debug_stack_info (info)
   if (info->main_save_offset)
     fprintf (stderr, "\tmain_save_offset    = %5d\n", info->main_save_offset);
 
+  if (info->fpmem_offset)
+    fprintf (stderr, "\tfpmem_offset        = %5d\n", info->fpmem_offset);
+
   if (info->total_size)
     fprintf (stderr, "\ttotal_size          = %5d\n", info->total_size);
 
@@ -3039,6 +3292,9 @@ debug_stack_info (info)
   if (info->parm_size)
     fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
 
+  if (info->fpmem_size)
+    fprintf (stderr, "\tfpmem_size          = %5d\n", info->fpmem_size);
+
   if (info->fixed_size)
     fprintf (stderr, "\tfixed_size          = %5d\n", info->fixed_size);
 
@@ -3068,8 +3324,76 @@ debug_stack_info (info)
 
   fprintf (stderr, "\n");
 }
-
 \f
+/* Write out an instruction to load the TOC_TABLE address into register 30.
+   This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
+   a constant pool.  */
+
+void
+rs6000_output_load_toc_table (file)
+     FILE *file;
+{
+  char buf[256];
+
+#ifdef USING_SVR4_H
+  if (TARGET_RELOCATABLE)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+      fprintf (file, "\tbl ");
+      assemble_name (file, buf);
+      fprintf (file, "\n");
+
+      ASM_OUTPUT_INTERNAL_LABEL (file, "LCF", rs6000_pic_labelno);
+      fprintf (file, "\tmflr %s\n", reg_names[30]);
+
+      if (TARGET_POWERPC64)
+       fprintf (file, "\tld");
+      else if (TARGET_NEW_MNEMONICS)
+       fprintf (file, "\tlwz");
+      else
+       fprintf (file, "\tl");
+
+      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, ")(%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_64BIT)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
+      asm_fprintf (file, "\t{cau|addis} %s,%s,", reg_names[30], reg_names[0]);
+      assemble_name (file, buf);
+      asm_fprintf (file, "@ha\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 */
+}
+
 /* Write function prologue.  */
 void
 output_prolog (file, size)
@@ -3220,10 +3544,6 @@ output_prolog (file, size)
                     reg_names[sp_reg]);
     }
 
-  if (info->toc_save_p)
-    asm_fprintf (file, store_reg, reg_names[2], info->toc_save_offset + sp_offset,
-                reg_names[sp_reg]);
-
   /* NT needs us to probe the stack frame every 4k pages for large frames, so
      do it here.  */
   if (DEFAULT_ABI == ABI_NT && info->total_size > 4096)
@@ -3256,7 +3576,7 @@ output_prolog (file, size)
          asm_fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
          ASM_OUTPUT_INTERNAL_LABEL (file, "LCprobe", probe_labelno);
          asm_fprintf (file, "\t{lu|lwzu} %s,-4096(%s)\n", reg_names[0], reg_names[12]);
-         ASM_GENERATE_INTERNAL_LABEL (buf, "LCprobe", probe_labelno);
+         ASM_GENERATE_INTERNAL_LABEL (buf, "LCprobe", probe_labelno++);
          fputs ("\tbdnz ", file);
          assemble_name (file, buf);
          fputs ("\n", file);
@@ -3343,73 +3663,7 @@ output_prolog (file, size)
   /* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the
      TOC_TABLE address into register 30.  */
   if (TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
-    {
-      char buf[256];
-
-#ifdef TARGET_RELOCATABLE
-      if (TARGET_RELOCATABLE)
-       {
-         ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
-         fputs ("\tbl ", file);
-         assemble_name (file, buf);
-         putc ('\n', file);
-
-         ASM_OUTPUT_INTERNAL_LABEL (file, "LCF", rs6000_pic_labelno);
-         fprintf (file, "\tmflr %s\n", reg_names[30]);
-
-         asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz}" : "\tld");
-         fprintf (file, " %s,(", reg_names[0]);
-         ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
-         assemble_name (file, buf);
-         putc ('-', file);
-         ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
-         assemble_name (file, buf);
-         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
-#endif
-
-       switch (DEFAULT_ABI)
-         {
-         case ABI_V4:
-         case ABI_SOLARIS:
-         case ABI_AIX_NODESC:
-           if (TARGET_32BIT)
-             {
-               ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
-               asm_fprintf (file, "\t{cau|addis} %s,%s,", reg_names[30], reg_names[0]);
-               assemble_name (file, buf);
-               asm_fprintf (file, "@ha\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 ();
-
-         break;
-
-       case ABI_NT:
-       case ABI_AIX:
-         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]);
-         break;
-       }
-    }
+    rs6000_output_load_toc_table (file);
 
   if (DEFAULT_ABI == ABI_NT)
     {
@@ -3723,11 +3977,6 @@ output_epilog (file, size)
        fputs ("\t.byte 31\n", file);
     }
 
-  /* Reset varargs and save TOC indicator */
-  rs6000_sysv_varargs_p = 0;
-  rs6000_save_toc_p = 0;
-  pic_offset_table_rtx = (rtx)0;
-
   if (DEFAULT_ABI == ABI_NT)
     {
       RS6000_OUTPUT_BASENAME (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
@@ -3803,9 +4052,9 @@ output_toc (file, x, labelno)
       REAL_VALUE_TO_TARGET_SINGLE (rv, l);
 
       if (TARGET_MINIMAL_TOC)
-       fprintf (file, "\t.long %d\n", l);
+       fprintf (file, "\t.long %ld\n", l);
       else
-       fprintf (file, "\t.tc FS_%x[TC],%d\n", l, l);
+       fprintf (file, "\t.tc FS_%lx[TC],%ld\n", l, l);
       return;
     }
   else if (GET_MODE (x) == DImode
@@ -3834,10 +4083,10 @@ output_toc (file, x, labelno)
 #endif
 
       if (TARGET_MINIMAL_TOC)
-       fprintf (file, "\t.long %ld\n\t.long %ld\n", high, low);
+       fprintf (file, "\t.long %ld\n\t.long %ld\n", (long)high, (long)low);
       else
        fprintf (file, "\t.tc ID_%lx_%lx[TC],%ld,%ld\n",
-                high, low, high, low);
+                (long)high, (long)low, (long)high, (long)low);
       return;
     }
 
@@ -3856,11 +4105,11 @@ output_toc (file, x, labelno)
   else
     abort ();
 
+  STRIP_NAME_ENCODING (real_name, name);
   if (TARGET_MINIMAL_TOC)
     fputs ("\t.long ", file);
   else
     {
-      STRIP_NAME_ENCODING (real_name, name);
       fprintf (file, "\t.tc %s", real_name);
 
       if (offset < 0)
@@ -3870,7 +4119,23 @@ output_toc (file, x, labelno)
 
       fputs ("[TC],", file);
     }
-  output_addr_const (file, x);
+
+  /* Currently C++ toc references to vtables can be emitted before it
+     is decided whether the vtable is public or private.  If this is
+     the case, then the linker will eventually complain that there is
+     a TOC reference to an unknown section.  Thus, for vtables only,
+     we emit the TOC reference to reference the symbol and not the
+     section.  */
+  if (!strncmp ("_vt.", name, 4))
+    {
+      RS6000_OUTPUT_BASENAME (file, name);
+      if (offset < 0)
+       fprintf (file, "%d", offset);
+      else if (offset > 0)
+       fprintf (file, "+%d", offset);
+    }
+  else
+    output_addr_const (file, x);
   putc ('\n', file);
 }
 \f
@@ -4054,7 +4319,7 @@ output_function_profiler (file, labelno)
   ASM_GENERATE_INTERNAL_LABEL (buf, "LPC", labelno);
   asm_fprintf (file, "\t{l|lwz} %s,", reg_names[3]);
   assemble_name (file, buf);
-  asm_fprintf (file, "(%s)\n\tbl .mcount\n", reg_names[2]);
+  asm_fprintf (file, "(%s)\n\tbl %s\n", reg_names[2], RS6000_MCOUNT);
 
   /* Restore parameter registers.  */
 
@@ -4117,65 +4382,6 @@ int get_issue_rate()
   }
 }
 
-\f
-/* Output insns to flush the {data|instruction} caches after building a
-   trampoline. */
-
-static void
-rs6000_sync_trampoline (addr)
-     rtx addr;
-{
-  enum machine_mode pmode = Pmode;
-  rtx reg = gen_reg_rtx (pmode);
-  rtx mem2;
-  rtx mem1;
-  int size = rs6000_trampoline_size ();
-  rtx (*sub_fcn) PROTO ((rtx, rtx, rtx));
-  rtx (*cmp_fcn) PROTO ((rtx, rtx));
-  rtx label;
-
-  if (TARGET_32BIT)
-    {
-      sub_fcn = gen_subsi3;
-      cmp_fcn = gen_cmpsi;
-    }
-  else
-    {
-      sub_fcn = gen_subdi3;
-      cmp_fcn = gen_cmpdi;
-    }
-
-  addr = force_reg (pmode, addr);
-  mem2 = gen_rtx (MEM, pmode, gen_rtx (PLUS, pmode, addr, reg));
-  mem1 = gen_rtx (MEM, pmode, addr);
-
-  /* Issue a loop of dcbst's to flush the data cache */
-  emit_move_insn (reg, GEN_INT (size-4));
-  label = gen_label_rtx ();
-  emit_label (label);
-  emit_insn (gen_dcbst (mem2, addr, reg));
-  emit_insn ((*sub_fcn) (reg, reg, GEN_INT (4)));
-  emit_insn ((*cmp_fcn) (reg, const0_rtx));
-  emit_jump_insn (gen_bgt (label));
-
-  /* Issue a sync after the dcbst's to let things settle down */
-  emit_insn (gen_sync (mem1));
-
-  /* Issue a loop of icbi's to flush the instruction cache */
-  emit_move_insn (reg, GEN_INT (size-4));
-  label = gen_label_rtx ();
-  emit_label (label);
-  emit_insn (gen_icbi (mem2, addr, reg));
-  emit_insn ((*sub_fcn) (reg, reg, GEN_INT (4)));
-  emit_insn ((*cmp_fcn) (reg, const0_rtx));
-  emit_jump_insn (gen_bgt (label));
-
-  /* Issue a sync after the icbi's to let things settle down */
-  emit_insn (gen_sync (mem1));
-
-  /* Finally issue an isync to synchronize the icache */
-  emit_insn (gen_isync (mem1));
-}
 
 \f
 /* Output assembler code for a block containing the constant parts
@@ -4202,7 +4408,6 @@ rs6000_trampoline_template (file)
        the address of the function, the second word is the TOC pointer (r2),
        and the third word is the static chain value.  */
     case ABI_AIX:
-      fprintf (file, "\t.long %s\n", (TARGET_32BIT) ? "0,0,0" : "0,0,0,0,0,0");
       break;
 
 
@@ -4211,35 +4416,6 @@ rs6000_trampoline_template (file)
     case ABI_V4:
     case ABI_SOLARIS:
     case ABI_AIX_NODESC:
-      if (STATIC_CHAIN_REGNUM == 0 || !TARGET_NEW_MNEMONICS)
-       abort ();
-
-      if (TARGET_32BIT)
-       {
-         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 */
-       }
-      else
-       {
-         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 */
-       }
       break;
 
   /* NT function pointers point to a two word area (real address, TOC)
@@ -4336,18 +4512,16 @@ rs6000_initialize_trampoline (addr, fnaddr, cxt)
       }
       break;
 
-    /* Under V.4/eabi, update the two words after the bl to have the real
-       function address and the static chain.  */
+    /* Under V.4/eabi, call __trampoline_setup to do the real work.  */
     case ABI_V4:
     case ABI_SOLARIS:
     case ABI_AIX_NODESC:
-      {
-       rtx reg = gen_reg_rtx (pmode);
-       emit_move_insn (reg, fnaddr);
-       emit_move_insn (MEM_PLUS (addr, 8), reg);
-       emit_move_insn (MEM_PLUS (addr, 8 + regsize), ctx_reg);
-       rs6000_sync_trampoline (addr);
-      }
+      emit_library_call (gen_rtx (SYMBOL_REF, SImode, "__trampoline_setup"),
+                        FALSE, VOIDmode, 4,
+                        addr, pmode,
+                        GEN_INT (rs6000_trampoline_size ()), SImode,
+                        fnaddr, pmode,
+                        ctx_reg, pmode);
       break;
 
     /* Under NT, update the first word to point to the ..LTRAMP1..0 header,
@@ -4680,65 +4854,3 @@ rs6000_encode_section_info (decl)
 }
 
 #endif /* USING_SVR4_H */
-
-\f
-/* CYGNUS LOCAL mac */
-
-/* Whether we are using m68k-compatible alignment.  */
-
-int mac68k_aligned;
-
-/* Most Mac compiler pragmas are unimportant, but we must recognize
-   the m68k alignment pragma, because that is crucial to transitions
-   to and from the m68k emulator on PowerMacs.  */
-
-int
-handle_mac_pragma (finput, t)
-     FILE *finput;
-     tree t;
-{
-  int retval = 0;
-  register char *pname;
-  char pbuf[200];
-  int c, psize;
-
-  if (TREE_CODE (t) != IDENTIFIER_NODE)
-    return 0;
-
-  pname = IDENTIFIER_POINTER (t);
-  if (strcmp (pname, "segment") == 0)
-    {
-      retval = 1;
-      /* (should collect pbuf + 8 into a segment name) */
-    }
-  else if (strcmp (pname, "options") == 0)
-    {
-      c = getc (finput);
-      /* Skip over initial whitespace.  */
-      while (c == ' ' || c == '\t')
-       c = getc (finput);
-
-      /* Return without doing anything if no content.  */
-      if (c == '\n' || c == EOF)
-       return 0;
-
-      /* Collect the rest of the line.  */
-      while (psize < sizeof (pbuf) - 1 && c != '\n')
-       {
-         pbuf[psize++] = c;
-         c = getc (finput);
-       }
-
-      if (strncmp (pbuf, "align=mac68k", 12) == 0)
-       {
-         mac68k_aligned = retval = 1;
-       }
-      else if (strncmp (pbuf, "align=reset", 11) == 0)
-       {
-         mac68k_aligned = 0, retval = 1;
-       }
-    }
-
-  return c;
-}
-/* END CYGNUS LOCAL mac */