OSDN Git Service

# Fix misspellings in comments.
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.c
index 37707cd..29ea966 100644 (file)
@@ -75,23 +75,6 @@ extern tree   lookup_name ();
 extern void   pfatal_with_name ();
 extern void   warning ();
 
-extern rtx    gen_addsi3 ();
-extern rtx    gen_andsi3 ();
-extern rtx    gen_beq ();
-extern rtx    gen_bne ();
-extern rtx    gen_cmpsi ();
-extern rtx    gen_indirect_jump ();
-extern rtx    gen_iorsi3 ();
-extern rtx    gen_jump ();
-extern rtx    gen_movhi ();
-extern rtx    gen_movqi ();
-extern rtx    gen_movsi ();
-extern rtx    gen_movsi_ulw ();
-extern rtx    gen_movsi_usw ();
-extern rtx    gen_movstrsi_internal ();
-extern rtx    gen_return_internal ();
-extern rtx    gen_subsi3 ();
-
 extern tree   current_function_decl;
 extern FILE  *asm_out_file;
 
@@ -124,10 +107,6 @@ int mips_section_threshold = -1;
 /* Count the number of .file directives, so that .loc is up to date.  */
 int num_source_filenames = 0;
 
-/* Count of the number of functions created so far, in order to make
-   unique labels for omitting the frame pointer.  */
-int number_functions_processed = 0;
-
 /* Count the number of sdb related labels are generated (to find block
    start and end boundaries).  */
 int sdb_label_count = 0;
@@ -197,6 +176,10 @@ rtx branch_cmp[2];
 /* what type of branch to use */
 enum cmp_type branch_type;
 
+/* Number of previously seen half-pic pointers and references.  */
+static int prev_half_pic_ptrs = 0;
+static int prev_half_pic_refs = 0;
+
 /* which cpu are we scheduling for */
 enum processor_type mips_cpu;
 
@@ -421,7 +404,7 @@ large_int (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  long value;
+  HOST_WIDE_INT value;
 
   if (GET_CODE (op) != CONST_INT)
     return FALSE;
@@ -1552,8 +1535,6 @@ map_test_to_internal_test (test_code)
 \f
 /* Generate the code to compare two integer values.  The return value is:
    (reg:SI xx)         The pseudo register the comparison is in
-   (const_int 0)       The comparison is always false
-   (const_int 1)       The comparison is always true
    (rtx)0              No register, generate a simple branch.  */
 
 rtx
@@ -1573,20 +1554,21 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
     int reverse_regs;          /* reverse registers in test */
     int invert_const;          /* != 0 if invert value if cmp1 is constant */
     int invert_reg;            /* != 0 if invert value if cmp1 is register */
+    int unsignedp;             /* != 0 for unsigned comparisons.  */
   };
 
   static struct cmp_info info[ (int)ITEST_MAX ] = {
 
-    { XOR,      0,  65535,  0,  0,  0,  0 },   /* EQ  */
-    { XOR,      0,  65535,  0,  0,  1,  1 },   /* NE  */
-    { LT,   -32769,  32766,  1,         1,  1,  0 },   /* GT  */
-    { LT,   -32768,  32767,  0,         0,  1,  1 },   /* GE  */
-    { LT,   -32768,  32767,  0,         0,  0,  0 },   /* LT  */
-    { LT,   -32769,  32766,  1,         1,  0,  1 },   /* LE  */
-    { LTU,  -32769,  32766,  1,         1,  1,  0 },   /* GTU */
-    { LTU,  -32768,  32767,  0,         0,  1,  1 },   /* GEU */
-    { LTU,  -32768,  32767,  0,         0,  0,  0 },   /* LTU */
-    { LTU,  -32769,  32766,  1,         1,  0,  1 },   /* LEU */
+    { XOR,      0,  65535,  0,  0,  0,  0, 0 },        /* EQ  */
+    { XOR,      0,  65535,  0,  0,  1,  1, 0 },        /* NE  */
+    { LT,   -32769,  32766,  1,         1,  1,  0, 0 },        /* GT  */
+    { LT,   -32768,  32767,  0,         0,  1,  1, 0 },        /* GE  */
+    { LT,   -32768,  32767,  0,         0,  0,  0, 0 },        /* LT  */
+    { LT,   -32769,  32766,  1,         1,  0,  1, 0 },        /* LE  */
+    { LTU,  -32769,  32766,  1,         1,  1,  0, 1 },        /* GTU */
+    { LTU,  -32768,  32767,  0,         0,  1,  1, 1 },        /* GEU */
+    { LTU,  -32768,  32767,  0,         0,  0,  0, 1 },        /* LTU */
+    { LTU,  -32769,  32766,  1,         1,  0,  1, 1 },        /* LEU */
   };
 
   enum internal_test test;
@@ -1604,52 +1586,6 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
   p_info = &info[ (int)test ];
   eqne_p = (p_info->test_code == XOR);
 
-  /* See if the test is always true or false.  */
-  if ((GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG)
-      && GET_CODE (cmp1) == CONST_INT)
-    {
-      int value = INTVAL (cmp1);
-      rtx truth = (rtx)0;
-
-      if (test == ITEST_GEU && value == 0)
-       truth = const1_rtx;
-
-      else if (test == ITEST_LTU && value == 0)
-       truth = const0_rtx;
-
-      else if (!TARGET_INT64)
-       {
-         if (test == ITEST_LTU && value == -1)
-           truth = const1_rtx;
-
-         else if (test == ITEST_GTU && value == -1)
-           truth = const0_rtx;
-
-         else if (test == ITEST_LEU && value == -1)
-           truth = const1_rtx;
-
-         else if (test == ITEST_GT && value == 0x7fffffff)
-           truth = const0_rtx;
-
-         else if (test == ITEST_LE && value == 0x7fffffff)
-           truth = const1_rtx;
-
-         else if (test == ITEST_LT && value == 0x80000000)
-           truth = const0_rtx;
-
-         else if (test == ITEST_GE && value == 0x80000000)
-           truth = const1_rtx;
-       }
-
-      if (truth != (rtx)0)
-       {
-         if (result != (rtx)0)
-           emit_move_insn (result, truth);
-
-         return truth;
-       }
-    }
-
   /* Eliminate simple branches */
   branch_p = (result == (rtx)0);
   if (branch_p)
@@ -1675,7 +1611,7 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
 
   if (GET_CODE (cmp1) == CONST_INT)
     {
-      int value = INTVAL (cmp1);
+      HOST_WIDE_INT value = INTVAL (cmp1);
       if (value < p_info->const_low || value > p_info->const_high)
        cmp1 = force_reg (SImode, cmp1);
     }
@@ -1696,7 +1632,22 @@ gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
   if (GET_CODE (cmp1) == CONST_INT)
     {
       if (p_info->const_add != 0)
-       cmp1 = GEN_INT (INTVAL (cmp1) + p_info->const_add);
+       {
+         HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add;
+         /* If modification of cmp1 caused overflow,
+            we would get the wrong answer if we follow the usual path;
+            thus, x > 0xffffffffu would turn into x > 0u.  */
+         if ((p_info->unsignedp
+              ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1)
+              : new > INTVAL (cmp1))
+             != (p_info->const_add > 0))
+           /* 1 is the right value in the LE and LEU case.
+              In the GT and GTU case, *p_invert is already set,
+              so this is effectively 0.  */
+           return force_reg (SImode, const1_rtx);
+         else
+           cmp1 = GEN_INT (new);
+       }
     }
   else if (p_info->reverse_regs)
     {
@@ -1833,7 +1784,7 @@ gen_conditional_branch (operands, test_code)
       }
       break;
     }
-  
+
   /* Generate the jump */
   if (invert)
     {
@@ -1895,7 +1846,7 @@ block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align, orig_src)
     }
 
 #if 0
-  /* Don't generate unligned moves here, rather defer those to the
+  /* Don't generate unaligned moves here, rather defer those to the
      general movestrsi_internal pattern.  */
   else if (bytes >= UNITS_PER_WORD)
     {
@@ -2462,14 +2413,25 @@ init_cumulative_args (cum, fntype, libname)
      tree fntype;              /* tree ptr for function decl */
      rtx libname;              /* SYMBOL_REF of library name or 0 */
 {
+  static CUMULATIVE_ARGS zero_cum;
   tree param, next_param;
 
   if (TARGET_DEBUG_E_MODE)
-    fprintf (stderr, "\ninit_cumulative_args\n");
+    {
+      fprintf (stderr, "\ninit_cumulative_args, fntype = 0x%.8lx", (long)fntype);
+      if (!fntype)
+       fputc ('\n', stderr);
 
-  cum->gp_reg_found = 0;
-  cum->arg_number = 0;
-  cum->arg_words = 0;
+      else
+       {
+         tree ret_type = TREE_TYPE (fntype);
+         fprintf (stderr, ", fntype code = %s, ret code = %s\n",
+                  tree_code_name[ (int)TREE_CODE (fntype) ],
+                  tree_code_name[ (int)TREE_CODE (ret_type) ]);
+       }
+    }
+
+  *cum = zero_cum;
 
   /* Determine if this function has variable arguments.  This is
      indicated by the last argument being 'void_type_mode' if there
@@ -2485,24 +2447,6 @@ init_cumulative_args (cum, fntype, libname)
       if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
        cum->gp_reg_found = 1;
     }
-
-  /* Determine if the function is returning a structure, if so,
-     advance by one argument.  */
-
-  if (fntype
-      && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE)
-      && TREE_TYPE (fntype) != 0)
-    {
-      tree ret_type = TREE_TYPE (fntype);
-      enum tree_code ret_code = TREE_CODE (ret_type);
-
-      if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE)
-       {
-         cum->gp_reg_found = 1;
-         cum->arg_number = 1;
-         cum->arg_words = 1;
-       }
-    }
 }
 
 /* Advance the argument to the next argument position.  */
@@ -2516,7 +2460,7 @@ function_arg_advance (cum, mode, type, named)
 {
   if (TARGET_DEBUG_E_MODE)
     fprintf (stderr,
-            "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n",
+            "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n\n",
             cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
             type, named);
 
@@ -2567,8 +2511,12 @@ function_arg (cum, mode, type, named)
      tree type;                        /* type of the argument or 0 if lib support */
      int named;                        /* != 0 for normal args, == 0 for ... args */
 {
+  rtx ret;
   int regbase = -1;
   int bias = 0;
+  int struct_p = ((type != (tree)0)
+                 && (TREE_CODE (type) == RECORD_TYPE
+                     || TREE_CODE (type) == UNION_TYPE));
 
   if (TARGET_DEBUG_E_MODE)
     fprintf (stderr,
@@ -2600,8 +2548,14 @@ function_arg (cum, mode, type, named)
                        : FP_ARG_FIRST;
       break;
 
-    case VOIDmode:
     case BLKmode:
+      if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD)
+       cum->arg_words += (cum->arg_words & 1);
+
+      regbase = GP_ARG_FIRST;
+      break;
+
+    case VOIDmode:
     case QImode:
     case HImode:
     case SImode:
@@ -2616,18 +2570,42 @@ function_arg (cum, mode, type, named)
   if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)
     {
       if (TARGET_DEBUG_E_MODE)
-       fprintf (stderr, "<stack>\n");
+       fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : "");
 
-      return 0;
+      ret = (rtx)0;
     }
+  else
+    {
+      if (regbase == -1)
+       abort ();
 
-  if (regbase == -1)
-    abort ();
+      ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias);
 
-  if (TARGET_DEBUG_E_MODE)
-    fprintf (stderr, "%s\n", reg_names[regbase + cum->arg_words + bias]);
+      if (TARGET_DEBUG_E_MODE)
+       fprintf (stderr, "%s%s\n", reg_names[regbase + cum->arg_words + bias],
+                struct_p ? ", [struct]" : "");
+
+      /* The following is a hack in order to pass 1 byte structures
+        the same way that the MIPS compiler does (namely by passing
+        the structure in the high byte or half word of the register).
+        This also makes varargs work.  If we have such a structure,
+        we save the adjustment RTL, and the call define expands will
+        emit them.  For the VOIDmode argument (argument after the
+        last real argument, pass back a parallel vector holding each
+        of the adjustments.  */
+
+      if (struct_p && (mode == QImode || mode == HImode))
+       {
+         rtx amount = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode));
+         rtx reg = gen_rtx (REG, SImode, regbase + cum->arg_words + bias);
+         cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount);
+       }
+    }
+
+  if (mode == VOIDmode && cum->num_adjusts > 0)
+    ret = gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (cum->num_adjusts, cum->adjust));
 
-  return gen_rtx (REG, mode, regbase + cum->arg_words + bias);
+  return ret;
 }
 
 
@@ -2764,54 +2742,14 @@ trace (s, s1, s2)
 \f
 #ifdef SIGINFO
 
-#include <sys/wait.h>
-
 static void
 siginfo (signo)
      int signo;
 {
-  char select_pgrp[15];
-  char *argv[4];
-  pid_t pid;
-  pid_t pgrp;
-  int status;
-
   fprintf (stderr, "compiling '%s' in '%s'\n",
           (current_function_name != (char *)0) ? current_function_name : "<toplevel>",
           (current_function_file != (char *)0) ? current_function_file : "<no file>");
-
-  pgrp = getpgrp ();
-  if (pgrp != -1)
-    sprintf (select_pgrp, "-g%d", pgrp);
-  else
-    strcpy (select_pgrp, "-a");
-
-  /* Spawn a ps to tell about current memory usage, etc. */
-  argv[0] = "ps";
-  argv[1] = "-ouser,pid,pri,nice,usertime,systime,pcpu,cp,inblock,oublock,vsize,rss,pmem,ucomm";
-  argv[2] = select_pgrp;
-  argv[3] = (char *)0;
-
-  pid = vfork ();
-  if (pid == 0)                        /* child context */
-    {
-      execv ("/usr/bin/ps", argv);
-      execv ("/usr/sbin/ps", argv);
-      execvp ("ps", argv);
-      perror ("ps");
-      _exit (1);
-    }
-
-  else if (pid > 0)            /* parent context */
-    {
-      void (*sigint)(int)  = signal (SIGINT, SIG_IGN);
-      void (*sigquit)(int) = signal (SIGQUIT, SIG_IGN);
-
-      (void) waitpid (pid, &status, 0);
-
-      (void) signal (SIGINT,  sigint);
-      (void) signal (SIGQUIT, sigquit);
-    }
+  fflush (stderr);
 }
 #endif /* SIGINFO */
 
@@ -2956,17 +2894,13 @@ override_options ()
     }
 #endif
 
-#ifdef _IOLBF
+#if defined(_IOLBF)
+#if defined(ultrix) || defined(__ultrix) || defined(__OSF1__) || defined(__osf__) || defined(osf)
   /* If -mstats and -quiet, make stderr line buffered.  */
   if (quiet_flag && TARGET_STATS)
-    {
-#if defined (MIPS_BSD43) || defined (MIPS_NEWS)
-      setlinebuf (stderr);
-#else
-      setvbuf (stderr, (char *)0, _IOLBF, BUFSIZ);
+    setvbuf (stderr, (char *)0, _IOLBF, BUFSIZ);
 #endif
 #endif
-    }
 
   /* Set up the classification arrays now.  */
   mips_rtx_classify[(int)PLUS]  = CLASS_ADD_OP;
@@ -3067,11 +3001,14 @@ override_options ()
 
 \f
 /*
- * If the frame pointer has been eliminated, the offset for an auto
- * or argument will be based on the stack pointer.  But this is not
- * what the debugger expects--it needs to find an offset off of the
- * frame pointer (whether it exists or not).  So here we turn all
- * offsets into those based on the (possibly virtual) frame pointer.
+ * The MIPS debug format wants all automatic variables and arguments
+ * to be in terms of the virtual frame pointer (stack pointer before
+ * any adjustment in the function), while the MIPS 3.0 linker wants
+ * the frame pointer to be the stack pointer after the initial
+ * adjustment.  So, we do the adjustment here.  The arg pointer (which
+ * is eliminated) points to the virtual frame pointer, while the frame
+ * pointer (which may be eliminated) points to the stack pointer after
+ * the initial adjustments.
  */
 
 int
@@ -3085,7 +3022,7 @@ mips_debugger_offset (addr, offset)
   if (!offset)
     offset = INTVAL (offset2);
 
-  if (reg == stack_pointer_rtx)
+  if (reg == stack_pointer_rtx || reg == frame_pointer_rtx)
     {
       int frame_size = (!current_frame_info.initialized)
                                ? compute_frame_size (get_frame_size ())
@@ -3093,13 +3030,11 @@ mips_debugger_offset (addr, offset)
 
       offset = offset - frame_size;
     }
-
-  /* Any other register is, we hope, either the frame pointer,
-     or a pseudo equivalent to the frame pointer.  (Assign_parms
-     copies the arg pointer to a pseudo if ARG_POINTER_REGNUM is
-     equal to FRAME_POINTER_REGNUM, so references off of the
-     arg pointer are all off a pseudo.)  Seems like all we can
-     do is to just return OFFSET and hope for the best.  */
+  /* sdbout_parms does not want this to crash for unrecognized cases.  */
+#if 0
+  else if (reg != arg_pointer_rtx)
+    abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer.");
+#endif
 
   return offset;
 }
@@ -3397,6 +3332,9 @@ print_operand_address (file, addr)
        break;
 
       case REG:
+       if (REGNO (addr) == ARG_POINTER_REGNUM)
+         abort_with_insn (addr, "Arg pointer not eliminated.");
+
        fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
        break;
 
@@ -3430,6 +3368,9 @@ print_operand_address (file, addr)
          if (!CONSTANT_P (offset))
            abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2");
 
+       if (REGNO (reg) == ARG_POINTER_REGNUM)
+         abort_with_insn (addr, "Arg pointer not eliminated.");
+
          output_addr_const (file, offset);
          fprintf (file, "(%s)", reg_names [REGNO (reg)]);
        }
@@ -3818,6 +3759,72 @@ mips_output_float (stream, value)
 }
 
 \f
+/* Return TRUE if any register used in the epilogue is used.  This to insure
+   any insn put into the epilogue delay slots is safe.  */
+
+int
+epilogue_reg_mentioned_p (insn)
+     rtx insn;
+{
+  register char *fmt;
+  register int i;
+  register enum rtx_code code;
+  register int regno;
+
+  if (insn == (rtx)0)
+    return 0;
+
+  if (GET_CODE (insn) == LABEL_REF)
+    return 0;
+
+  code = GET_CODE (insn);
+  switch (code)
+    {
+    case REG:
+      regno = REGNO (insn);
+      if (regno == STACK_POINTER_REGNUM)
+       return 1;
+
+      if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
+       return 1;
+
+      if (!call_used_regs[regno])
+       return 1;
+
+      if (regno != MIPS_TEMP1_REGNUM && regno != MIPS_TEMP2_REGNUM)
+       return 0;
+
+      if (!current_frame_info.initialized)
+       compute_frame_size (get_frame_size ());
+
+      return (current_frame_info.total_size >= 32768);
+
+    case SCRATCH:
+    case CC0:
+    case PC:
+    case CONST_INT:
+    case CONST_DOUBLE:
+      return 0;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+         for (j = XVECLEN (insn, i) - 1; j >= 0; j--)
+           if (epilogue_reg_mentioned_p (XVECEXP (insn, i, j)))
+             return 1;
+       }
+      else if (fmt[i] == 'e' && epilogue_reg_mentioned_p (XEXP (insn, i)))
+       return 1;
+    }
+
+  return 0;
+}
+
+\f
 /* Return the bytes needed to compute the frame pointer from the current
    stack pointer.
 
@@ -3843,10 +3850,6 @@ mips_output_float (stream, value)
                                        |  GP save for V.4 abi  |
                                        |                       |
                                        +-----------------------+
-                                       |                       |
-                                       |  local variables      |
-                                       |                       |
-                                       +-----------------------+
                                        |                       |
                                         |  fp register save     |
                                        |                       |
@@ -3856,6 +3859,10 @@ mips_output_float (stream, value)
                                         |                      |
                                        +-----------------------+
                                        |                       |
+                                       |  local variables      |
+                                       |                       |
+                                       +-----------------------+
+                                       |                       |
                                         |  alloca allocations   |
                                        |                       |
                                        +-----------------------+
@@ -3871,33 +3878,40 @@ mips_output_float (stream, value)
 
 */
 
-unsigned long
+long
 compute_frame_size (size)
      int size;                 /* # of var. bytes allocated */
 {
   int regno;
-  unsigned long total_size;    /* # bytes that the entire frame takes up */
-  unsigned long var_size;      /* # bytes that variables take up */
-  unsigned long args_size;     /* # bytes that outgoing arguments take up */
-  unsigned long extra_size;    /* # extra bytes */
-  unsigned int  gp_reg_rounded;        /* # bytes needed to store gp after rounding */
-  unsigned int  gp_reg_size;   /* # bytes needed to store gp regs */
-  unsigned int  fp_reg_size;   /* # bytes needed to store fp regs */
-  unsigned long mask;          /* mask of saved gp registers */
-  unsigned long fmask;         /* mask of saved fp registers */
-  int fp_inc;                  /* 1 or 2 depending on the size of fp regs */
-  int fp_bits;                 /* bitmask to use for each fp register */
-
-  extra_size    = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0)
-                                    -STARTING_FRAME_OFFSET);
+  long total_size;             /* # bytes that the entire frame takes up */
+  long var_size;               /* # bytes that variables take up */
+  long args_size;              /* # bytes that outgoing arguments take up */
+  long extra_size;             /* # extra bytes */
+  long gp_reg_rounded;         /* # bytes needed to store gp after rounding */
+  long gp_reg_size;            /* # bytes needed to store gp regs */
+  long fp_reg_size;            /* # bytes needed to store fp regs */
+  long mask;                   /* mask of saved gp registers */
+  long fmask;                  /* mask of saved fp registers */
+  int  fp_inc;                 /* 1 or 2 depending on the size of fp regs */
+  long fp_bits;                        /* bitmask to use for each fp register */
 
-  var_size      = MIPS_STACK_ALIGN (size);
-  args_size     = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
-  total_size    = var_size + args_size + extra_size;
   gp_reg_size   = 0;
   fp_reg_size   = 0;
   mask          = 0;
   fmask                 = 0;
+  extra_size    = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0));
+  var_size      = MIPS_STACK_ALIGN (size);
+  args_size     = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
+
+  /* The MIPS 3.0 linker does not like functions that dynamically
+     allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it
+     looks like we are trying to create a second frame pointer to the
+     function, so allocate some stack space to make it happy.  */
+
+  if (args_size == 0 && current_function_calls_alloca)
+    args_size = 4*UNITS_PER_WORD;
+
+  total_size = var_size + args_size + extra_size;
 
   /* Calculate space needed for gp registers.  */
   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
@@ -3905,7 +3919,7 @@ compute_frame_size (size)
       if (MUST_SAVE_REGISTER (regno))
        {
          gp_reg_size += UNITS_PER_WORD;
-         mask |= 1 << (regno - GP_REG_FIRST);
+         mask |= 1L << (regno - GP_REG_FIRST);
        }
     }
 
@@ -3951,173 +3965,241 @@ compute_frame_size (size)
 
   if (mask)
     {
-      unsigned long offset = args_size + gp_reg_size - UNITS_PER_WORD;
+      unsigned long offset = args_size + var_size + gp_reg_size - UNITS_PER_WORD;
       current_frame_info.gp_sp_offset = offset;
       current_frame_info.gp_save_offset = offset - total_size;
     }
+  else
+    {
+      current_frame_info.gp_sp_offset = 0;
+      current_frame_info.gp_save_offset = 0;
+    }
+
 
   if (fmask)
     {
-      unsigned long offset = args_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
+      unsigned long offset = args_size + var_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
       current_frame_info.fp_sp_offset = offset;
       current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD;
     }
+  else
+    {
+      current_frame_info.fp_sp_offset = 0;
+      current_frame_info.fp_save_offset = 0;
+    }
 
   /* Ok, we're done.  */
   return total_size;
 }
 
 \f
-/* Save/restore registers printing out the instructions to a file.  */
+/* Common code to emit the insns (or to write the instructions to a file)
+   to save/restore registers.
 
-void
-save_restore (file, gp_op, gp_2word_op, fp_op)
-     FILE *file;               /* stream to write to */
-     char *gp_op;              /* operation to do on gp registers */
-     char *gp_2word_op;                /* 2 word op to do on gp registers */
-     char *fp_op;              /* operation to do on fp registers */
+   Other parts of the code assume that MIPS_TEMP1_REGNUM (aka large_reg)
+   is not modified within save_restore_insns.  */
+
+#define BITSET_P(value,bit) (((value) & (1L << (bit))) != 0)
+
+static void
+save_restore_insns (store_p, large_reg, large_offset, file)
+     int store_p;              /* true if this is prologue */
+     rtx large_reg;            /* register holding large offset constant or NULL */
+     long large_offset;                /* large constant offset value */
+     FILE *file;               /* file to write instructions to instead of making RTL */
 {
+  long mask            = current_frame_info.mask;
+  long fmask           = current_frame_info.fmask;
   int regno;
-  unsigned long mask     = current_frame_info.mask;
-  unsigned long fmask    = current_frame_info.fmask;
-  unsigned long gp_offset;
-  unsigned long fp_offset;
-  unsigned long max_offset;
-  char *base_reg;
+  rtx base_reg_rtx;
+  long base_offset;
+  long gp_offset;
+  long fp_offset;
+  long end_offset;
+
+  if (frame_pointer_needed && !BITSET_P (mask, FRAME_POINTER_REGNUM - GP_REG_FIRST))
+    abort ();
 
   if (mask == 0 && fmask == 0)
     return;
 
-  base_reg   = reg_names[STACK_POINTER_REGNUM];
-  gp_offset  = current_frame_info.gp_sp_offset;
-  fp_offset  = current_frame_info.fp_sp_offset;
-  max_offset = (gp_offset > fp_offset) ? gp_offset : fp_offset;
-
-  /* Deal with calling functions with a large structure.  */
-  if (max_offset >= 32768)
-    {
-      char *temp = reg_names[MIPS_TEMP2_REGNUM];
-      fprintf (file, "\tli\t%s,%ld\n", temp, max_offset);
-      fprintf (file, "\taddu\t%s,%s,%s\n", temp, temp, base_reg);
-      base_reg = temp;
-      gp_offset = max_offset - gp_offset;
-      fp_offset = max_offset - fp_offset;
-    }
-
   /* Save registers starting from high to low.  The debuggers prefer
      at least the return register be stored at func+4, and also it
      allows us not to need a nop in the epilog if at least one
      register is reloaded in addition to return address.  */
 
-  if (mask || frame_pointer_needed)
+  /* Save GP registers if needed.  */
+  if (mask)
     {
-      for  (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
-       {
-         if ((mask & (1L << (regno - GP_REG_FIRST))) != 0
-             || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed))
-           {
-             fprintf (file, "\t%s\t%s,%d(%s)\n",
-                      gp_op, reg_names[regno],
-                      gp_offset, base_reg);
+      /* Pick which pointer to use as a base register.  For small
+        frames, just use the stack pointer.  Otherwise, use a
+        temporary register.  Save 2 cycles if the save area is near
+        the end of a large frame, by reusing the constant created in
+        the prologue/epilogue to adjust the stack frame.  */
 
-             gp_offset -= UNITS_PER_WORD;
-           }
+      gp_offset  = current_frame_info.gp_sp_offset;
+      end_offset = gp_offset - (current_frame_info.gp_reg_size - UNITS_PER_WORD);
+
+      if (gp_offset < 0 || end_offset < 0)
+       fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
+              gp_offset, end_offset);
+
+      else if (gp_offset < 32768)
+       {
+         base_reg_rtx = stack_pointer_rtx;
+         base_offset  = 0;
        }
-    }
 
-  if (fmask)
-    {
-      int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
+      else if (large_reg != (rtx)0
+              && (((unsigned long)(large_offset - gp_offset))  < 32768)
+              && (((unsigned long)(large_offset - end_offset)) < 32768))
+       {
+         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_offset  = large_offset;
+         if (file == (FILE *)0)
+           emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx));
+         else
+           fprintf (file, "\taddu\t%s,%s,%s\n",
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    reg_names[REGNO (large_reg)],
+                    reg_names[STACK_POINTER_REGNUM]);
+       }
 
-      for  (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
+      else
        {
-         if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0)
+         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_offset  = gp_offset;
+         if (file == (FILE *)0)
            {
-             fprintf (file, "\t%s\t%s,%d(%s)\n",
-                      fp_op, reg_names[regno], fp_offset, base_reg);
-
-             fp_offset -= 2*UNITS_PER_WORD;
+             emit_move_insn (base_reg_rtx, GEN_INT (gp_offset));
+             emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
            }
+         else
+           fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n",
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    (long)base_offset,
+                    (long)base_offset,
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    reg_names[STACK_POINTER_REGNUM]);
        }
-    }
-}
 
-\f
-/* Common code to emit the insns to save/restore registers.  */
-
-static void
-save_restore_insns (store_p)
-     int store_p;              /* true if this is prologue */
-{
-  int regno;
-  rtx base_reg_rtx       = stack_pointer_rtx;
-  unsigned long mask     = current_frame_info.mask;
-  unsigned long fmask    = current_frame_info.fmask;
-  unsigned long gp_offset;
-  unsigned long fp_offset;
-  unsigned long max_offset;
-
-  if (mask == 0 && fmask == 0)
-    return;
-
-  gp_offset  = current_frame_info.gp_sp_offset;
-  fp_offset  = current_frame_info.fp_sp_offset;
-  max_offset = (gp_offset > fp_offset) ? gp_offset : fp_offset;
-
-  /* Deal with calling functions with a large structure.  */
-  if (max_offset >= 32768)
-    {
-      base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
-      emit_move_insn (base_reg_rtx, GEN_INT (max_offset));
-      emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
-      gp_offset = max_offset - gp_offset;
-      fp_offset = max_offset - fp_offset;
-    }
-
-  /* Save registers starting from high to low.  The debuggers prefer
-     at least the return register be stored at func+4, and also it
-     allows us not to need a nop in the epilog if at least one
-     register is reloaded in addition to return address.  */
-
-  if (mask || frame_pointer_needed)
-    {
       for  (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
        {
-         if ((mask & (1L << (regno - GP_REG_FIRST))) != 0
-             || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed))
+         if (BITSET_P (mask, regno - GP_REG_FIRST))
            {
-             rtx reg_rtx = gen_rtx (REG, Pmode, regno);
-             rtx mem_rtx = gen_rtx (MEM, Pmode,
-                                    gen_rtx (PLUS, Pmode, base_reg_rtx,
-                                             GEN_INT (gp_offset)));
+             if (file == (FILE *)0)
+               {
+                 rtx reg_rtx = gen_rtx (REG, Pmode, regno);
+                 rtx mem_rtx = gen_rtx (MEM, Pmode,
+                                        gen_rtx (PLUS, Pmode, base_reg_rtx,
+                                                 GEN_INT (gp_offset - base_offset)));
 
-             if (store_p)
-               emit_move_insn (mem_rtx, reg_rtx);
+                 if (store_p)
+                   emit_move_insn (mem_rtx, reg_rtx);
+                 else
+                   emit_move_insn (reg_rtx, mem_rtx);
+               }
              else
-               emit_move_insn (reg_rtx, mem_rtx);
+               fprintf (file, "\t%s\t%s,%ld(%s)\n",
+                        (store_p) ? "sw" : "lw",
+                        reg_names[regno],
+                        gp_offset - base_offset,
+                        reg_names[REGNO(base_reg_rtx)]);
 
              gp_offset -= UNITS_PER_WORD;
            }
        }
     }
+  else
+    {
+      base_reg_rtx = (rtx)0;           /* Make sure these are initialzed */
+      base_offset  = 0;
+    }
 
+  /* Save floating point registers if needed.  */
   if (fmask)
     {
       int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
 
+      /* Pick which pointer to use as a base register.  */
+      fp_offset  = current_frame_info.fp_sp_offset;
+      end_offset = fp_offset - (current_frame_info.fp_reg_size - 2*UNITS_PER_WORD);
+
+      if (fp_offset < 0 || end_offset < 0)
+       fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
+              fp_offset, end_offset);
+
+      else if (fp_offset < 32768)
+       {
+         base_reg_rtx = stack_pointer_rtx;
+         base_offset  = 0;
+       }
+
+      else if (base_reg_rtx != (rtx)0
+              && (((unsigned long)(base_offset - fp_offset))  < 32768)
+              && (((unsigned long)(base_offset - end_offset)) < 32768))
+       {
+         ;                     /* already set up for gp registers above */
+       }
+
+      else if (large_reg != (rtx)0
+              && (((unsigned long)(large_offset - fp_offset))  < 32768)
+              && (((unsigned long)(large_offset - end_offset)) < 32768))
+       {
+         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_offset  = large_offset;
+         if (file == (FILE *)0)
+           emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx));
+         else
+           fprintf (file, "\taddu\t%s,%s,%s\n",
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    reg_names[REGNO (large_reg)],
+                    reg_names[STACK_POINTER_REGNUM]);
+       }
+
+      else
+       {
+         base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
+         base_offset  = fp_offset;
+         if (file == (FILE *)0)
+           {
+             emit_move_insn (base_reg_rtx, GEN_INT (fp_offset));
+             emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
+           }
+         else
+           fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n",
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    (long)base_offset,
+                    (long)base_offset,
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    reg_names[MIPS_TEMP2_REGNUM],
+                    reg_names[STACK_POINTER_REGNUM]);
+       }
+
       for  (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
        {
-         if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0)
+         if (BITSET_P (fmask, regno - FP_REG_FIRST))
            {
-             rtx reg_rtx = gen_rtx (REG, DFmode, regno);
-             rtx mem_rtx = gen_rtx (MEM, DFmode,
-                                    gen_rtx (PLUS, Pmode, base_reg_rtx,
-                                             GEN_INT (fp_offset)));
+             if (file == (FILE *)0)
+               {
+                 rtx reg_rtx = gen_rtx (REG, DFmode, regno);
+                 rtx mem_rtx = gen_rtx (MEM, DFmode,
+                                        gen_rtx (PLUS, Pmode, base_reg_rtx,
+                                                 GEN_INT (fp_offset - base_offset)));
 
-             if (store_p)
-               emit_move_insn (mem_rtx, reg_rtx);
+                 if (store_p)
+                   emit_move_insn (mem_rtx, reg_rtx);
+                 else
+                   emit_move_insn (reg_rtx, mem_rtx);
+               }
              else
-               emit_move_insn (reg_rtx, mem_rtx);
+               fprintf (file, "\t%s\t%s,%ld(%s)\n",
+                        (store_p) ? "s.d" : "l.d",
+                        reg_names[regno],
+                        fp_offset - base_offset,
+                        reg_names[REGNO(base_reg_rtx)]);
+
 
              fp_offset -= 2*UNITS_PER_WORD;
            }
@@ -4133,17 +4215,18 @@ function_prologue (file, size)
      FILE *file;
      int size;
 {
-  int tsize = current_frame_info.total_size;
-  int vframe;
-  int vreg;
+  long tsize = current_frame_info.total_size;
 
   ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
-  ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
+
+  if (debug_info_level != DINFO_LEVEL_TERSE)
+    ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
 
   inside_function = 1;
   fputs ("\t.ent\t", file);
   assemble_name (file, current_function_name);
   fputs ("\n", file);
+
   assemble_name (file, current_function_name);
   fputs (":\n", file);
 
@@ -4156,20 +4239,9 @@ function_prologue (file, size)
   if (tsize > 0 && TARGET_ABICALLS)
     fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET);
 
-  if (frame_pointer_needed)
-    {
-      vframe = 0;
-      vreg   = FRAME_POINTER_REGNUM;
-    }
-  else
-    {
-      vframe = tsize;
-      vreg   = STACK_POINTER_REGNUM;
-    }
-
   fprintf (file, "\t.frame\t%s,%d,%s\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n",
-          reg_names[ vreg ],
-          vframe,
+          reg_names[ (frame_pointer_needed) ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ],
+          tsize,
           reg_names[31 + GP_REG_FIRST],
           current_frame_info.var_size,
           current_frame_info.num_gp,
@@ -4191,21 +4263,57 @@ void
 mips_expand_prologue ()
 {
   int regno;
-  int size;
-  int tsize;
-  tree fndecl = current_function_decl; /* current... is tooo long */
-  tree fntype = TREE_TYPE (fndecl);
-  tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE)
+  long tsize;
+  rtx tmp_rtx   = (rtx)0;
+  char *arg_name = (char *)0;
+  tree fndecl   = current_function_decl;
+  tree fntype   = TREE_TYPE (fndecl);
+  tree fnargs   = (TREE_CODE (fntype) != METHOD_TYPE)
                        ? DECL_ARGUMENTS (fndecl)
                        : 0;
+  rtx next_arg_reg;
+  int i;
   tree next_arg;
   tree cur_arg;
-  char *arg_name = (char *)0;
   CUMULATIVE_ARGS args_so_far;
 
   /* Determine the last argument, and get its name.  */
+
+  INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0);
+  regno = GP_ARG_FIRST;
+
   for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg)
     {
+      tree type = DECL_ARG_TYPE (cur_arg);
+      enum machine_mode passed_mode = TYPE_MODE (type);
+      rtx entry_parm = FUNCTION_ARG (args_so_far,
+                                    passed_mode,
+                                    DECL_ARG_TYPE (cur_arg),
+                                    1);
+
+      if (entry_parm)
+       {
+         int words;
+
+         /* passed in a register, so will get homed automatically */
+         if (GET_MODE (entry_parm) == BLKmode)
+           words = (int_size_in_bytes (type) + 3) / 4;
+         else
+           words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
+
+         regno = REGNO (entry_parm) + words - 1;
+       }
+      else
+       {
+         regno = GP_ARG_LAST+1;
+         break;
+       }
+
+      FUNCTION_ARG_ADVANCE (args_so_far,
+                           passed_mode,
+                           DECL_ARG_TYPE (cur_arg),
+                           1);
+
       next_arg = TREE_CHAIN (cur_arg);
       if (next_arg == (tree)0)
        {
@@ -4216,52 +4324,39 @@ mips_expand_prologue ()
        }
     }
 
-  /* If this function is a varargs function, store any registers that
-     would normally hold arguments ($4 - $7) on the stack.  */
-  if ((TYPE_ARG_TYPES (fntype) != 0
-       && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
-      || (arg_name
-         && (strcmp (arg_name, "__builtin_va_alist") == 0
-             || strcmp (arg_name, "va_alist") == 0)))
-    {
-      tree parm;
+  /* In order to pass small structures by value in registers
+     compatibly with the MIPS compiler, we need to shift the value
+     into the high part of the register.  Function_arg has encoded a
+     PARALLEL rtx, holding a vector of adjustments to be made as the
+     next_arg_reg variable, so we split up the insns, and emit them
+     separately.  */
 
-      regno = GP_ARG_FIRST;
-      INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0);
+  next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
+  if (next_arg_reg != (rtx)0 && GET_CODE (next_arg_reg) == PARALLEL)
+    {
+      rtvec adjust = XVEC (next_arg_reg, 0);
+      int num = GET_NUM_ELEM (adjust);
 
-      for (parm = fnargs; (parm && (regno <= GP_ARG_LAST)); parm = TREE_CHAIN (parm))
+      for (i = 0; i < num; i++)
        {
-         rtx entry_parm;
-         enum machine_mode passed_mode;
-         tree type;
-
-         type = DECL_ARG_TYPE (parm);
-         passed_mode = TYPE_MODE (type);
-         entry_parm = FUNCTION_ARG (args_so_far, passed_mode,
-                                    DECL_ARG_TYPE (parm), 1);
-
-         if (entry_parm)
-           {
-             int words;
+         rtx pattern = RTVEC_ELT (adjust, i);
+         if (GET_CODE (pattern) != SET
+             || GET_CODE (SET_SRC (pattern)) != ASHIFT)
+           abort_with_insn (pattern, "Insn is not a shift");
 
-             /* passed in a register, so will get homed automatically */
-             if (GET_MODE (entry_parm) == BLKmode)
-               words = (int_size_in_bytes (type) + 3) / 4;
-             else
-               words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
-
-             regno = REGNO (entry_parm) + words - 1;
-           }
-         else
-           {
-             regno = GP_ARG_LAST+1;
-             break;
-           }
-
-         FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
-                               DECL_ARG_TYPE (parm), 1);
+         PUT_CODE (SET_SRC (pattern), ASHIFTRT);
+         emit_insn (pattern);
        }
+    }
 
+  /* If this function is a varargs function, store any registers that
+     would normally hold arguments ($4 - $7) on the stack.  */
+  if ((TYPE_ARG_TYPES (fntype) != 0
+       && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
+      || (arg_name != (char *)0
+         && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0)
+             || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0))))
+    {
       for (; regno <= GP_ARG_LAST; regno++)
        {
          rtx ptr = stack_pointer_rtx;
@@ -4273,27 +4368,31 @@ mips_expand_prologue ()
        }
     }
 
-  size  = MIPS_STACK_ALIGN (get_frame_size ());
-  tsize = compute_frame_size (size);
-
+  tsize = compute_frame_size (get_frame_size ());
   if (tsize > 0)
     {
       rtx tsize_rtx = GEN_INT (tsize);
 
       if (tsize > 32767)
        {
-         rtx tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
+         tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
          emit_move_insn (tmp_rtx, tsize_rtx);
          tsize_rtx = tmp_rtx;
        }
 
       emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx));
 
-      save_restore_insns (TRUE);
+      save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0);
 
       if (frame_pointer_needed)
-       emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, tsize_rtx));
+       emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
     }
+
+  /* If we are profiling, make sure no instructions are scheduled before
+     the call to mcount.  */
+
+  if (profile_flag || profile_block_flag)
+    emit_insn (gen_blockage ());
 }
 
 \f
@@ -4304,7 +4403,7 @@ function_epilogue (file, size)
      FILE *file;
      int size;
 {
-  int tsize;
+  long tsize;
   char *sp_str = reg_names[STACK_POINTER_REGNUM];
   char *t1_str = reg_names[MIPS_TEMP1_REGNUM];
   rtx epilogue_delay = current_function_epilogue_delay_list;
@@ -4312,6 +4411,9 @@ function_epilogue (file, size)
   int noepilogue = FALSE;
   int load_nop = FALSE;
   int load_only_r31;
+  rtx tmp_rtx = (rtx)0;
+  rtx restore_rtx;
+  int i;
 
   /* The epilogue does not depend on any registers, but the stack
      registers, so we assume that if we have 1 pending nop, it can be
@@ -4392,20 +4494,16 @@ function_epilogue (file, size)
        fprintf (file, "\t.set\tnoreorder\n");
 
       if (tsize > 32767)
-       fprintf (file, "\tli\t%s,%d\n", t1_str, tsize);
-
-      if (frame_pointer_needed)
        {
-         char *fp_str = reg_names[FRAME_POINTER_REGNUM];
-         if (tsize > 32767)
-           fprintf (file,"\tsubu\t%s,%s,%s\t\t# sp not trusted  here\n",
-                    sp_str, fp_str, t1_str);
-         else
-           fprintf (file,"\tsubu\t%s,%s,%d\t\t# sp not trusted  here\n",
-                    sp_str, fp_str, tsize);
+         fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n", t1_str, (long)tsize, (long)tsize);
+         tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
        }
 
-      save_restore (file, "lw", "ld", "l.d");
+      if (frame_pointer_needed)
+       fprintf (file, "\tmove\t%s,%s\t\t\t# sp not trusted here\n",
+                sp_str, reg_names[FRAME_POINTER_REGNUM]);
+
+      save_restore_insns (FALSE, tmp_rtx, tsize, file);
 
       load_only_r31 = (current_frame_info.mask == (1 << 31)
                       && current_frame_info.fmask == 0);
@@ -4471,6 +4569,10 @@ function_epilogue (file, size)
       int num_gp_regs = current_frame_info.gp_reg_size / 4;
       int num_fp_regs = current_frame_info.fp_reg_size / 8;
       int num_regs    = num_gp_regs + num_fp_regs;
+      char *name      = current_function_name;
+
+      if (name[0] == '*')
+       name++;
 
       dslots_load_total += num_regs;
 
@@ -4493,7 +4595,7 @@ function_epilogue (file, size)
 
       fprintf (stderr,
               "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3ld reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d",
-              current_function_name,
+              name,
               (frame_pointer_needed) ? 'y' : 'n',
               ((current_frame_info.mask & (1 << 31)) != 0) ? 'n' : 'y',
               (current_function_calls_alloca) ? 'y' : 'n',
@@ -4505,11 +4607,17 @@ function_epilogue (file, size)
               dslots_jump_total, dslots_jump_filled,
               num_refs[0], num_refs[1], num_refs[2]);
 
-      if (HALF_PIC_NUMBER_PTRS)
-       fprintf (stderr, " half-pic=%3d", HALF_PIC_NUMBER_PTRS);
+      if (HALF_PIC_NUMBER_PTRS > prev_half_pic_ptrs)
+       {
+         fprintf (stderr, " half-pic=%3d", HALF_PIC_NUMBER_PTRS - prev_half_pic_ptrs);
+         prev_half_pic_ptrs = HALF_PIC_NUMBER_PTRS;
+       }
 
-      if (HALF_PIC_NUMBER_REFS)
-       fprintf (stderr, " pic-ref=%3d", HALF_PIC_NUMBER_REFS);
+      if (HALF_PIC_NUMBER_REFS > prev_half_pic_refs)
+       {
+         fprintf (stderr, " pic-ref=%3d", HALF_PIC_NUMBER_REFS - prev_half_pic_refs);
+         prev_half_pic_refs = HALF_PIC_NUMBER_REFS;
+       }
 
       fputc ('\n', stderr);
     }
@@ -4526,7 +4634,6 @@ function_epilogue (file, size)
   num_refs[2]       = 0;
   mips_load_reg      = (rtx)0;
   mips_load_reg2     = (rtx)0;
-  number_functions_processed++;
   current_frame_info = zero_frame_info;
 
   /* Restore the output file if optimizing the GP (optimizing the GP causes
@@ -4543,12 +4650,13 @@ function_epilogue (file, size)
 void
 mips_expand_epilogue ()
 {
-  int tsize = current_frame_info.total_size;
+  long tsize = current_frame_info.total_size;
   rtx tsize_rtx = GEN_INT (tsize);
+  rtx tmp_rtx = (rtx)0;
 
   if (tsize > 32767)
     {
-      rtx tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
+      tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
       emit_move_insn (tmp_rtx, tsize_rtx);
       tsize_rtx = tmp_rtx;
     }
@@ -4556,9 +4664,9 @@ mips_expand_epilogue ()
   if (tsize > 0)
     {
       if (frame_pointer_needed)
-       emit_insn (gen_subsi3 (stack_pointer_rtx, frame_pointer_rtx, tsize_rtx));
+       emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
 
-      save_restore_insns (FALSE);
+      save_restore_insns (FALSE, tmp_rtx, tsize, (FILE *)0);
 
       emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx));
     }