OSDN Git Service

(assign_parms): Don't trust the callee to copy a TREE_ADDRESSABLE
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 3d64281..25a4911 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
-   Copyright (C) 1987, 88, 89, 91, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91-94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file handles the generation of rtl code from tree structure
@@ -60,7 +61,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
    give the same symbol without quotes for an alternative entry point.  You
-   must define both, or niether. */
+   must define both, or neither. */
 #ifndef NAME__MAIN
 #define NAME__MAIN "__main"
 #define SYMBOL__MAIN __main
@@ -152,9 +153,8 @@ int current_function_args_size;
 
 int current_function_pretend_args_size;
 
-/* # of bytes of outgoing arguments required to be pushed by the prologue.
-   If this is non-zero, it means that ACCUMULATE_OUTGOING_ARGS was defined
-   and no stack adjusts will be done on function calls.  */
+/* # of bytes of outgoing arguments.  If ACCUMULATE_OUTGOING_ARGS is
+   defined, the needed space is pushed by the prologue. */
 
 int current_function_outgoing_args_size;
 
@@ -168,6 +168,11 @@ rtx current_function_arg_offset_rtx;
 
 int current_function_varargs;
 
+/* Nonzero if current function uses stdarg.h or equivalent.
+   Zero for functions that use varargs.h.  */
+
+int current_function_stdarg;
+
 /* Quantities of various kinds of registers
    used for the current function's args.  */
 
@@ -356,10 +361,18 @@ struct temp_slot
   tree rtl_expr;
   /* Non-zero if this temporary is currently in use.  */
   char in_use;
+  /* Non-zero if this temporary has its address taken.  */
+  char addr_taken;
   /* Nesting level at which this slot is being used.  */
   int level;
   /* Non-zero if this should survive a call to free_temp_slots.  */
   int keep;
+  /* The offset of the slot from the frame_pointer, including extra space
+     for alignment.  This info is for combine_temp_slots.  */
+  int base_offset;
+  /* The size of the slot, including extra space for alignment.  This
+     info is for combine_temp_slots.  */
+  int full_size;
 };
 
 /* List of all temporaries allocated, both available and in use.  */
@@ -461,7 +474,8 @@ find_function_data (decl)
    since this function knows only about language-independent variables.  */
 
 void
-push_function_context ()
+push_function_context_to (context)
+     tree context;
 {
   struct function *p = (struct function *) xmalloc (sizeof (struct function));
 
@@ -479,10 +493,12 @@ push_function_context ()
   p->calls_alloca = current_function_calls_alloca;
   p->has_nonlocal_label = current_function_has_nonlocal_label;
   p->has_nonlocal_goto = current_function_has_nonlocal_goto;
+  p->contains_functions = current_function_contains_functions;
   p->args_size = current_function_args_size;
   p->pretend_args_size = current_function_pretend_args_size;
   p->arg_offset_rtx = current_function_arg_offset_rtx;
   p->varargs = current_function_varargs;
+  p->stdarg = current_function_stdarg;
   p->uses_const_pool = current_function_uses_const_pool;
   p->uses_pic_offset_table = current_function_uses_pic_offset_table;
   p->internal_arg_pointer = current_function_internal_arg_pointer;
@@ -512,7 +528,7 @@ push_function_context ()
   p->fixup_var_refs_queue = 0;
   p->epilogue_delay_list = current_function_epilogue_delay_list;
 
-  save_tree_status (p);
+  save_tree_status (p, context);
   save_storage_status (p);
   save_emit_status (p);
   init_emit ();
@@ -524,16 +540,26 @@ push_function_context ()
     (*save_machine_status) (p);
 }
 
+void
+push_function_context ()
+{
+  push_function_context_to (current_function_decl);
+}
+
 /* Restore the last saved context, at the end of a nested function.
    This function is called from language-specific code.  */
 
 void
-pop_function_context ()
+pop_function_context_from (context)
+     tree context;
 {
   struct function *p = outer_function_chain;
 
   outer_function_chain = p->next;
 
+  current_function_contains_functions
+    = p->contains_functions || p->inline_obstacks
+      || context == current_function_decl;
   current_function_name = p->name;
   current_function_decl = p->decl;
   current_function_pops_args = p->pops_args;
@@ -545,11 +571,11 @@ pop_function_context ()
   current_function_calls_alloca = p->calls_alloca;
   current_function_has_nonlocal_label = p->has_nonlocal_label;
   current_function_has_nonlocal_goto = p->has_nonlocal_goto;
-  current_function_contains_functions = 1;
   current_function_args_size = p->args_size;
   current_function_pretend_args_size = p->pretend_args_size;
   current_function_arg_offset_rtx = p->arg_offset_rtx;
   current_function_varargs = p->varargs;
+  current_function_stdarg = p->stdarg;
   current_function_uses_const_pool = p->uses_const_pool;
   current_function_uses_pic_offset_table = p->uses_pic_offset_table;
   current_function_internal_arg_pointer = p->internal_arg_pointer;
@@ -577,6 +603,7 @@ pop_function_context ()
   temp_slots = p->temp_slots;
   temp_slot_level = p->temp_slot_level;
   current_function_epilogue_delay_list = p->epilogue_delay_list;
+  reg_renumber = 0;
 
   restore_tree_status (p);
   restore_storage_status (p);
@@ -602,6 +629,11 @@ pop_function_context ()
   rtx_equal_function_value_matters = 1;
   virtuals_instantiated = 0;
 }
+
+void pop_function_context ()
+{
+  pop_function_context_from (current_function_decl);
+}
 \f
 /* Allocate fixed slots in the stack frame of the current function.  */
 
@@ -666,10 +698,8 @@ assign_stack_local (mode, size, align)
 
   /* On a big-endian machine, if we are allocating more space than we will use,
      use the least significant bytes of those that are allocated.  */
-#if BYTES_BIG_ENDIAN
-  if (mode != BLKmode)
+  if (BYTES_BIG_ENDIAN && mode != BLKmode)
     bigend_correction = size - GET_MODE_SIZE (mode);
-#endif
 
 #ifdef FRAME_GROWS_DOWNWARD
   frame_offset -= size;
@@ -739,10 +769,8 @@ assign_outer_stack_local (mode, size, align, function)
 
   /* On a big-endian machine, if we are allocating more space than we will use,
      use the least significant bytes of those that are allocated.  */
-#if BYTES_BIG_ENDIAN
-  if (mode != BLKmode)
+  if (BYTES_BIG_ENDIAN && mode != BLKmode)
     bigend_correction = size - GET_MODE_SIZE (mode);
-#endif
 
 #ifdef FRAME_GROWS_DOWNWARD
   function->frame_offset -= size;
@@ -771,9 +799,10 @@ assign_outer_stack_local (mode, size, align, function)
    SIZE is the size in units of the space required.  We do no rounding here
    since assign_stack_local will do any required rounding.
 
-   KEEP is non-zero if this slot is to be retained after a call to
-   free_temp_slots.  Automatic variables for a block are allocated with this
-   flag.  */
+   KEEP is 1 if this slot is to be retained after a call to
+   free_temp_slots.  Automatic variables for a block are allocated
+   with this flag.  KEEP is 2, if we allocate a longer term temporary,
+   whose lifetime is controlled by CLEANUP_POINT_EXPRs.  */
 
 rtx
 assign_stack_temp (mode, size, keep)
@@ -783,6 +812,11 @@ assign_stack_temp (mode, size, keep)
 {
   struct temp_slot *p, *best_p = 0;
 
+  /* If SIZE is -1 it means that somebody tried to allocate a temporary
+     of a variable size.  */
+  if (size == -1)
+    abort ();
+
   /* First try to find an available, already-allocated temporary that is the
      exact size we require.  */
   for (p = temp_slots; p; p = p->next)
@@ -811,12 +845,15 @@ assign_stack_temp (mode, size, keep)
          if (best_p->size - rounded_size >= alignment)
            {
              p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
-             p->in_use = 0;
+             p->in_use = p->addr_taken = 0;
              p->size = best_p->size - rounded_size;
+             p->base_offset = best_p->base_offset + rounded_size;
+             p->full_size = best_p->full_size - rounded_size;
              p->slot = gen_rtx (MEM, BLKmode,
                                 plus_constant (XEXP (best_p->slot, 0),
                                                rounded_size));
              p->address = 0;
+             p->rtl_expr = 0;
              p->next = temp_slots;
              temp_slots = p;
 
@@ -824,6 +861,7 @@ assign_stack_temp (mode, size, keep)
                                         stack_slot_list);
 
              best_p->size = rounded_size;
+             best_p->full_size = rounded_size;
            }
        }
 
@@ -833,20 +871,50 @@ assign_stack_temp (mode, size, keep)
   /* If we still didn't find one, make a new temporary.  */
   if (p == 0)
     {
+      int frame_offset_old = frame_offset;
       p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
-      p->size = size;
       /* If the temp slot mode doesn't indicate the alignment,
         use the largest possible, so no one will be disappointed.  */
       p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0);
+      /* The following slot size computation is necessary because we don't
+        know the actual size of the temporary slot until assign_stack_local
+        has performed all the frame alignment and size rounding for the
+        requested temporary.  Note that extra space added for alignment
+        can be either above or below this stack slot depending on which
+        way the frame grows.  We include the extra space if and only if it
+        is above this slot.  */
+#ifdef FRAME_GROWS_DOWNWARD
+      p->size = frame_offset_old - frame_offset;
+#else
+      p->size = size;
+#endif
+      /* Now define the fields used by combine_temp_slots.  */
+#ifdef FRAME_GROWS_DOWNWARD
+      p->base_offset = frame_offset;
+      p->full_size = frame_offset_old - frame_offset;
+#else
+      p->base_offset = frame_offset_old;
+      p->full_size = frame_offset - frame_offset_old;
+#endif
       p->address = 0;
       p->next = temp_slots;
       temp_slots = p;
     }
 
   p->in_use = 1;
+  p->addr_taken = 0;
   p->rtl_expr = sequence_rtl_expr;
-  p->level = temp_slot_level;
-  p->keep = keep;
+
+  if (keep == 2)
+    {
+      p->level = target_temp_slot_level;
+      p->keep = 0;
+    }
+  else
+    {
+      p->level = temp_slot_level;
+      p->keep = keep;
+    }
   return p->slot;
 }
 
@@ -873,18 +941,18 @@ combine_temp_slots ()
            int delete_q = 0;
            if (! q->in_use && GET_MODE (q->slot) == BLKmode)
              {
-               if (rtx_equal_p (plus_constant (XEXP (p->slot, 0), p->size),
-                                XEXP (q->slot, 0)))
+               if (p->base_offset + p->full_size == q->base_offset)
                  {
                    /* Q comes after P; combine Q into P.  */
                    p->size += q->size;
+                   p->full_size += q->full_size;
                    delete_q = 1;
                  }
-               else if (rtx_equal_p (plus_constant (XEXP (q->slot, 0), q->size),
-                                     XEXP (p->slot, 0)))
+               else if (q->base_offset + q->full_size == p->base_offset)
                  {
                    /* P comes after Q; combine P into Q.  */
                    q->size += p->size;
+                   q->full_size += p->full_size;
                    delete_p = 1;
                    break;
                  }
@@ -937,7 +1005,7 @@ find_temp_slot_from_address (x)
   return 0;
 }
       
-/* Indicate that NEW is an alternate way of refering to the temp slot
+/* Indicate that NEW is an alternate way of referring to the temp slot
    that previous was known by OLD.  */
 
 void
@@ -960,6 +1028,28 @@ update_temp_slot_address (old, new)
     }
 }
 
+/* If X could be a reference to a temporary slot, mark the fact that its
+   address was taken.  */
+
+void
+mark_temp_addr_taken (x)
+     rtx x;
+{
+  struct temp_slot *p;
+
+  if (x == 0)
+    return;
+
+  /* If X is not in memory or is at a constant address, it cannot be in
+     a temporary slot.  */
+  if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
+    return;
+
+  p = find_temp_slot_from_address (XEXP (x, 0));
+  if (p != 0)
+    p->addr_taken = 1;
+}
+
 /* If X could be a reference to a temporary slot, mark that slot as belonging
    to the to one level higher.  If X matched one of our slots, just mark that
    one.  Otherwise, we can't easily predict which it is, so upgrade all of
@@ -972,32 +1062,54 @@ void
 preserve_temp_slots (x)
      rtx x;
 {
-  struct temp_slot *p;
+  struct temp_slot *p = 0;
 
+  /* If there is no result, we still might have some objects whose address
+     were taken, so we need to make sure they stay around.  */
   if (x == 0)
-    return;
+    {
+      for (p = temp_slots; p; p = p->next)
+       if (p->in_use && p->level == temp_slot_level && p->addr_taken)
+         p->level--;
+
+      return;
+    }
 
   /* If X is a register that is being used as a pointer, see if we have
      a temporary slot we know it points to.  To be consistent with
      the code below, we really should preserve all non-kept slots
      if we can't find a match, but that seems to be much too costly.  */
-  if (GET_CODE (x) == REG && REGNO_POINTER_FLAG (REGNO (x))
-      && (p = find_temp_slot_from_address (x)) != 0)
+  if (GET_CODE (x) == REG && REGNO_POINTER_FLAG (REGNO (x)))
+    p = find_temp_slot_from_address (x);
+
+  /* If X is not in memory or is at a constant address, it cannot be in
+     a temporary slot, but it can contain something whose address was
+     taken.  */
+  if (p == 0 && (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))))
     {
-      p->level--;
+      for (p = temp_slots; p; p = p->next)
+       if (p->in_use && p->level == temp_slot_level && p->addr_taken)
+         p->level--;
+
       return;
     }
-    
-  /* If X is not in memory or is at a constant address, it cannot be in
-     a temporary slot.  */
-  if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
-    return;
 
   /* First see if we can find a match.  */
-  p = find_temp_slot_from_address (XEXP (x, 0));
+  if (p == 0)
+    p = find_temp_slot_from_address (XEXP (x, 0));
+
   if (p != 0)
     {
+      /* Move everything at our level whose address was taken to our new
+        level in case we used its address.  */
+      struct temp_slot *q;
+
+      for (q = temp_slots; q; q = q->next)
+       if (q != p && q->addr_taken && q->level == p->level)
+         q->level--;
+
       p->level--;
+      p->addr_taken = 0;
       return;
     }
 
@@ -1023,14 +1135,14 @@ preserve_rtl_expr_result (x)
   if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
     return;
 
-  /* If we can find a match, move it to our level.  */
-  for (p = temp_slots; p; p = p->next)
-    if (p->in_use && rtx_equal_p (x, p->slot))
-      {
-       p->level = temp_slot_level;
-       p->rtl_expr = 0;
-       return;
-      }
+  /* If we can find a match, move it to our level unless it is already at
+     an upper level.  */
+  p = find_temp_slot_from_address (XEXP (x, 0));
+  if (p != 0)
+    {
+      p->level = MIN (p->level, temp_slot_level);
+      p->rtl_expr = 0;
+    }
 
   return;
 }
@@ -1156,7 +1268,7 @@ put_var_into_stack (decl)
         We do it so they end up consecutive.  */
       enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
       tree part_type = TREE_TYPE (TREE_TYPE (decl));
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef FRAME_GROWS_DOWNWARD
       /* Since part 0 should have a lower address, do it second.  */
       put_reg_into_stack (function, XEXP (reg, 1),
                          part_type, part_mode, part_mode);
@@ -1385,7 +1497,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
 
                 If we don't use an intermediate pseudo, such things as
                 address computations to make the address of VAR valid
-                if it is not can be placed beween the CALL_INSN and INSN.
+                if it is not can be placed between the CALL_INSN and INSN.
 
                 To make sure this doesn't happen, we record the destination
                 of the CALL_INSN and see if the next insn uses both that
@@ -1617,10 +1729,9 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
                  /* If the bytes and bits are counted differently, we
                     must adjust the offset.  */
-#if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
-                 offset = (GET_MODE_SIZE (is_mode)
-                           - GET_MODE_SIZE (wanted_mode) - offset);
-#endif
+                 if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
+                   offset = (GET_MODE_SIZE (is_mode)
+                             - GET_MODE_SIZE (wanted_mode) - offset);
 
                  pos %= GET_MODE_BITSIZE (wanted_mode);
 
@@ -1790,10 +1901,9 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                    rtx old_pos = XEXP (outerdest, 2);
                    rtx newmem;
 
-#if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
-                   offset = (GET_MODE_SIZE (is_mode)
-                             - GET_MODE_SIZE (wanted_mode) - offset);
-#endif
+                   if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
+                     offset = (GET_MODE_SIZE (is_mode)
+                               - GET_MODE_SIZE (wanted_mode) - offset);
 
                    pos %= GET_MODE_BITSIZE (wanted_mode);
 
@@ -2002,10 +2112,9 @@ fixup_memory_subreg (x, insn, uncritical)
       && ! uncritical)
     abort ();
 
-#if BYTES_BIG_ENDIAN
-  offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-            - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-#endif
+  if (BYTES_BIG_ENDIAN)
+    offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+              - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
   addr = plus_constant (addr, offset);
   if (!flag_force_addr && memory_address_p (mode, addr))
     /* Shortcut if no insns need be emitted.  */
@@ -2182,26 +2291,31 @@ optimize_bit_field (body, insn, equiv_mem)
             and then for which byte of the word is wanted.  */
 
          register int offset = INTVAL (XEXP (bitfield, 2));
+         rtx insns;
+
          /* Adjust OFFSET to count bits from low-address byte.  */
-#if BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN
-         offset = (GET_MODE_BITSIZE (GET_MODE (XEXP (bitfield, 0)))
-                   - offset - INTVAL (XEXP (bitfield, 1)));
-#endif
+         if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
+           offset = (GET_MODE_BITSIZE (GET_MODE (XEXP (bitfield, 0)))
+                     - offset - INTVAL (XEXP (bitfield, 1)));
+
          /* Adjust OFFSET to count bytes from low-address byte.  */
          offset /= BITS_PER_UNIT;
          if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
            {
              offset += SUBREG_WORD (XEXP (bitfield, 0)) * UNITS_PER_WORD;
-#if BYTES_BIG_ENDIAN
-             offset -= (MIN (UNITS_PER_WORD,
-                             GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
-                        - MIN (UNITS_PER_WORD,
-                               GET_MODE_SIZE (GET_MODE (memref))));
-#endif
+             if (BYTES_BIG_ENDIAN)
+               offset -= (MIN (UNITS_PER_WORD,
+                               GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
+                          - MIN (UNITS_PER_WORD,
+                                 GET_MODE_SIZE (GET_MODE (memref))));
            }
 
-         memref = change_address (memref, mode, 
+         start_sequence ();
+         memref = change_address (memref, mode,
                                   plus_constant (XEXP (memref, 0), offset));
+         insns = get_insns ();
+         end_sequence ();
+         emit_insns_before (insns, insn);
 
          /* Store this memory reference where
             we found the bit field reference.  */
@@ -2234,7 +2348,9 @@ optimize_bit_field (body, insn, equiv_mem)
              rtx dest = SET_DEST (body);
 
              while (GET_CODE (dest) == SUBREG
-                    && SUBREG_WORD (dest) == 0)
+                    && SUBREG_WORD (dest) == 0
+                    && (GET_MODE_CLASS (GET_MODE (dest))
+                        == GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest)))))
                dest = SUBREG_REG (dest);
 
              validate_change (insn, &SET_DEST (body), dest, 1);
@@ -2376,7 +2492,7 @@ instantiate_decls (fndecl, valid_only)
 {
   tree decl;
 
-  if (DECL_INLINE (fndecl))
+  if (DECL_INLINE (fndecl) || DECL_DEFER_OUTPUT (fndecl))
     /* When compiling an inline function, the obstack used for
        rtl allocation is the maybepermanent_obstack.  Calling
        `resume_temporary_allocation' switches us back to that
@@ -2395,7 +2511,7 @@ instantiate_decls (fndecl, valid_only)
   /* Now process all variables defined in the function or its subblocks. */
   instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
 
-  if (DECL_INLINE (fndecl))
+  if (DECL_INLINE (fndecl) || DECL_DEFER_OUTPUT (fndecl))
     {
       /* Save all rtl allocated for this function by raising the
         high-water mark on the maybepermanent_obstack.  */
@@ -2591,7 +2707,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
       /* Handle special case of virtual register plus constant.  */
       if (CONSTANT_P (XEXP (x, 1)))
        {
-         rtx old;
+         rtx old, new_offset;
 
          /* Check for (plus (plus VIRT foo) (const_int)) first.  */
          if (GET_CODE (XEXP (x, 0)) == PLUS)
@@ -2638,18 +2754,26 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
              return 1;
            }
 
-         old = XEXP (x, 0);
-         XEXP (x, 0) = new;
-         new = plus_constant (XEXP (x, 1), offset);
+         new_offset = plus_constant (XEXP (x, 1), offset);
 
-         /* If the new constant is zero, try to replace the sum with its
-            first operand.  */
-         if (new == const0_rtx
-             && validate_change (object, loc, XEXP (x, 0), 0))
+         /* If the new constant is zero, try to replace the sum with just
+            the register.  */
+         if (new_offset == const0_rtx
+             && validate_change (object, loc, new, 0))
            return 1;
 
-         /* Next try to replace constant with new one.  */
-         if (!validate_change (object, &XEXP (x, 1), new, 0))
+         /* Next try to replace the register and new offset.
+            There are two changes to validate here and we can't assume that
+            in the case of old offset equals new just changing the register
+            will yield a valid insn.  In the interests of a little efficiency,
+            however, we only call validate change once (we don't queue up the
+            changes and then call apply_change_group). */
+
+         old = XEXP (x, 0);
+         if (offset == 0
+             ? ! validate_change (object, &XEXP (x, 0), new, 0)
+             : (XEXP (x, 0) = new,
+                ! validate_change (object, &XEXP (x, 1), new_offset, 0)))
            {
              if (! extra_insns)
                {
@@ -2660,15 +2784,16 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
              /* Otherwise copy the new constant into a register and replace
                 constant with that register.  */
              temp = gen_reg_rtx (Pmode);
+             XEXP (x, 0) = new;
              if (validate_change (object, &XEXP (x, 1), temp, 0))
-               emit_insn_before (gen_move_insn (temp, new), object);
+               emit_insn_before (gen_move_insn (temp, new_offset), object);
              else
                {
                  /* If that didn't work, replace this expression with a
                     register containing the sum.  */
 
-                 new = gen_rtx (PLUS, Pmode, XEXP (x, 0), new);
                  XEXP (x, 0) = old;
+                 new = gen_rtx (PLUS, Pmode, new, new_offset);
 
                  start_sequence ();
                  temp = force_operand (new, NULL_RTX);
@@ -2862,7 +2987,25 @@ delete_handlers ()
         Also permit deletion of the nonlocal labels themselves
         if nothing local refers to them.  */
       if (GET_CODE (insn) == CODE_LABEL)
-       LABEL_PRESERVE_P (insn) = 0;
+       {
+         tree t, last_t;
+
+         LABEL_PRESERVE_P (insn) = 0;
+
+         /* Remove it from the nonlocal_label list, to avoid confusing
+            flow.  */
+         for (t = nonlocal_labels, last_t = 0; t;
+              last_t = t, t = TREE_CHAIN (t))
+           if (DECL_RTL (TREE_VALUE (t)) == insn)
+             break;
+         if (t)
+           {
+             if (! last_t)
+               nonlocal_labels = TREE_CHAIN (nonlocal_labels);
+             else
+               TREE_CHAIN (last_t) = TREE_CHAIN (t);
+           }
+       }
       if (GET_CODE (insn) == INSN
          && ((nonlocal_goto_handler_slot != 0
               && reg_mentioned_p (nonlocal_goto_handler_slot, PATTERN (insn)))
@@ -3013,7 +3156,8 @@ assign_parms (fndecl, second_time)
   register rtx entry_parm = 0;
   register rtx stack_parm = 0;
   CUMULATIVE_ARGS args_so_far;
-  enum machine_mode promoted_mode, passed_mode, nominal_mode;
+  enum machine_mode promoted_mode, passed_mode;
+  enum machine_mode nominal_mode, promoted_nominal_mode;
   int unsignedp;
   /* Total space needed so far for args on the stack,
      given as a constant and a tree-expression.  */
@@ -3051,6 +3195,8 @@ assign_parms (fndecl, second_time)
        && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
           != void_type_node));
 
+  current_function_stdarg = stdarg;
+
   /* If the reg that the virtual arg pointer will be translated into is
      not a fixed reg or is the stack pointer, make a copy of the virtual
      arg pointer, and address parms via the copy.  The frame pointer is
@@ -3085,7 +3231,7 @@ assign_parms (fndecl, second_time)
     }
                               
   parm_reg_stack_loc = (rtx *) oballoc (nparmregs * sizeof (rtx));
-  bzero (parm_reg_stack_loc, nparmregs * sizeof (rtx));
+  bzero ((char *) parm_reg_stack_loc, nparmregs * sizeof (rtx));
 
 #ifdef INIT_CUMULATIVE_INCOMING_ARGS
   INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
@@ -3103,7 +3249,9 @@ assign_parms (fndecl, second_time)
       struct args_size stack_offset;
       struct args_size arg_size;
       int passed_pointer = 0;
+      int did_conversion = 0;
       tree passed_type = DECL_ARG_TYPE (parm);
+      tree nominal_type = TREE_TYPE (parm);
 
       /* Set LAST_NAMED if this is last named arg before some
         anonymous args.  We treat it as if it were anonymous too.  */
@@ -3131,7 +3279,7 @@ assign_parms (fndecl, second_time)
       /* Find mode of arg as it is passed, and mode of arg
         as it should be during execution of this function.  */
       passed_mode = TYPE_MODE (passed_type);
-      nominal_mode = TYPE_MODE (TREE_TYPE (parm));
+      nominal_mode = TYPE_MODE (nominal_type);
 
       /* If the parm's mode is VOID, its value doesn't matter,
         and avoid the usual things like emit_move_insn that could crash.  */
@@ -3141,6 +3289,13 @@ assign_parms (fndecl, second_time)
          continue;
        }
 
+      /* If the parm is to be passed as a transparent union, use the
+        type of the first field for the tests below.  We have already
+        verified that the modes are the same.  */
+      if (DECL_TRANSPARENT_UNION (parm)
+         || TYPE_TRANSPARENT_UNION (passed_type))
+       passed_type = TREE_TYPE (TYPE_FIELDS (passed_type));
+
       /* See if this arg was passed by invisible reference.  It is if
         it is an object whose size depends on the contents of the
         object itself or if the machine requires these objects be passed
@@ -3148,13 +3303,14 @@ assign_parms (fndecl, second_time)
 
       if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
           && contains_placeholder_p (TYPE_SIZE (passed_type)))
+         || TREE_ADDRESSABLE (passed_type)
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
          || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
                                              passed_type, ! last_named)
 #endif
          )
        {
-         passed_type = build_pointer_type (passed_type);
+         passed_type = nominal_type = build_pointer_type (passed_type);
          passed_pointer = 1;
          passed_mode = nominal_mode = Pmode;
        }
@@ -3176,8 +3332,8 @@ assign_parms (fndecl, second_time)
                                 passed_type, ! last_named);
 #endif
 
-      if (entry_parm)
-       passed_mode = promoted_mode;
+      if (entry_parm == 0)
+       promoted_mode = passed_mode;
 
 #ifdef SETUP_INCOMING_VARARGS
       /* If this is the last named parameter, do any required setup for
@@ -3192,7 +3348,7 @@ assign_parms (fndecl, second_time)
         Also, indicate when RTL generation is to be suppressed.  */
       if (last_named && !varargs_setup)
        {
-         SETUP_INCOMING_VARARGS (args_so_far, passed_mode, passed_type,
+         SETUP_INCOMING_VARARGS (args_so_far, promoted_mode, passed_type,
                                  current_function_pretend_args_size,
                                  second_time);
          varargs_setup = 1;
@@ -3212,17 +3368,17 @@ assign_parms (fndecl, second_time)
         In this case, we call FUNCTION_ARG with NAMED set to 1 instead of
         0 as it was the previous time.  */
 
-      locate_and_pad_parm (passed_mode, passed_type,
+      locate_and_pad_parm (promoted_mode, passed_type,
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
                           1,
 #else
 #ifdef FUNCTION_INCOMING_ARG
-                          FUNCTION_INCOMING_ARG (args_so_far, passed_mode,
+                          FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
                                                  passed_type,
                                                  (! last_named
                                                   || varargs_setup)) != 0,
 #else
-                          FUNCTION_ARG (args_so_far, passed_mode,
+                          FUNCTION_ARG (args_so_far, promoted_mode,
                                         passed_type,
                                         ! last_named || varargs_setup) != 0,
 #endif
@@ -3234,9 +3390,9 @@ assign_parms (fndecl, second_time)
          rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
 
          if (offset_rtx == const0_rtx)
-           stack_parm = gen_rtx (MEM, passed_mode, internal_arg_pointer);
+           stack_parm = gen_rtx (MEM, promoted_mode, internal_arg_pointer);
          else
-           stack_parm = gen_rtx (MEM, passed_mode,
+           stack_parm = gen_rtx (MEM, promoted_mode,
                                  gen_rtx (PLUS, Pmode,
                                           internal_arg_pointer, offset_rtx));
 
@@ -3247,7 +3403,7 @@ assign_parms (fndecl, second_time)
 
       /* If this parameter was passed both in registers and in the stack,
         use the copy on the stack.  */
-      if (MUST_PASS_IN_STACK (passed_mode, passed_type))
+      if (MUST_PASS_IN_STACK (promoted_mode, passed_type))
        entry_parm = 0;
 
 #ifdef FUNCTION_ARG_PARTIAL_NREGS
@@ -3261,7 +3417,7 @@ assign_parms (fndecl, second_time)
 
       if (entry_parm)
        {
-         int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, passed_mode,
+         int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
                                                  passed_type, ! last_named);
 
          if (nregs > 0)
@@ -3301,7 +3457,7 @@ assign_parms (fndecl, second_time)
             ??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
             whether this parameter already has a stack slot allocated,
             because an arg block exists only if current_function_args_size
-            is larger than some threshhold, and we haven't calculated that
+            is larger than some threshold, and we haven't calculated that
             yet.  So, for now, we just assume that stack slots never exist
             in this case.  */
          || REG_PARM_STACK_SPACE (fndecl) > 0
@@ -3318,7 +3474,7 @@ assign_parms (fndecl, second_time)
 
       /* Update info on where next arg arrives in registers.  */
 
-      FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
+      FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
                            passed_type, ! last_named);
 
       /* If this is our second time through, we are done with this parm. */
@@ -3330,7 +3486,7 @@ assign_parms (fndecl, second_time)
         We'll make another stack slot, if we need one.  */
       {
        int thisparm_boundary
-         = FUNCTION_ARG_BOUNDARY (passed_mode, passed_type);
+         = FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type);
 
        if (GET_MODE_ALIGNMENT (nominal_mode) > thisparm_boundary)
          stack_parm = 0;
@@ -3354,11 +3510,10 @@ assign_parms (fndecl, second_time)
        {
          rtx offset_rtx;
 
-#if BYTES_BIG_ENDIAN
-         if (GET_MODE_SIZE (nominal_mode) < UNITS_PER_WORD)
+         if (BYTES_BIG_ENDIAN
+             && GET_MODE_SIZE (nominal_mode) < UNITS_PER_WORD)
            stack_offset.constant += (GET_MODE_SIZE (passed_mode)
                                      - GET_MODE_SIZE (nominal_mode));
-#endif
 
          offset_rtx = ARGS_SIZE_RTX (stack_offset);
          if (offset_rtx == const0_rtx)
@@ -3374,6 +3529,17 @@ assign_parms (fndecl, second_time)
        }
 #endif /* 0 */
 
+#ifdef STACK_REGS
+      /* We need this "use" info, because the gcc-register->stack-register
+        converter in reg-stack.c needs to know which registers are active
+        at the start of the function call.  The actual parameter loading
+        instructions are not always available then anymore, since they might
+        have been optimised away.  */
+
+      if (GET_CODE (entry_parm) == REG && !(hide_last_arg && last_named))
+         emit_insn (gen_rtx (USE, GET_MODE (entry_parm), entry_parm));
+#endif
+
       /* ENTRY_PARM is an RTX for the parameter as it arrives,
         in the mode in which it arrives.
         STACK_PARM is an RTX for a stack slot where the parameter can live
@@ -3393,8 +3559,9 @@ assign_parms (fndecl, second_time)
          /* If a BLKmode arrives in registers, copy it to a stack slot.  */
          if (GET_CODE (entry_parm) == REG)
            {
-             int size_stored = CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
-                                           UNITS_PER_WORD);
+             int size_stored
+               = CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
+                             UNITS_PER_WORD);
 
              /* Note that we will be storing an integral number of words.
                 So we have to be careful to ensure that we allocate an
@@ -3407,15 +3574,20 @@ assign_parms (fndecl, second_time)
              if (stack_parm == 0)
                {
                  stack_parm
-                   = assign_stack_local (GET_MODE (entry_parm), size_stored, 0);
-                 /* If this is a memory ref that contains aggregate components,
-                    mark it as such for cse and loop optimize.  */
+                   = assign_stack_local (GET_MODE (entry_parm),
+                                         size_stored, 0);
+
+                 /* If this is a memory ref that contains aggregate
+                    components, mark it as such for cse and loop optimize.  */
                  MEM_IN_STRUCT_P (stack_parm) = aggregate;
                }
 
              else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
                abort ();
 
+             if (TREE_READONLY (parm))
+               RTX_UNCHANGING_P (stack_parm) = 1;
+
              move_block_from_reg (REGNO (entry_parm),
                                   validize_mem (stack_parm),
                                   size_stored / UNITS_PER_WORD,
@@ -3443,26 +3615,35 @@ assign_parms (fndecl, second_time)
          int regno, regnoi, regnor;
 
          unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
-         nominal_mode = promote_mode (TREE_TYPE (parm), nominal_mode,
-                                      &unsignedp, 1);
 
-         parmreg = gen_reg_rtx (nominal_mode);
+         promoted_nominal_mode
+           = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
+
+         parmreg = gen_reg_rtx (promoted_nominal_mode);
          REG_USERVAR_P (parmreg) = 1;
 
          /* If this was an item that we received a pointer to, set DECL_RTL
             appropriately.  */
          if (passed_pointer)
            {
-             DECL_RTL (parm) = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
+             DECL_RTL (parm)
+               = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
              MEM_IN_STRUCT_P (DECL_RTL (parm)) = aggregate;
            }
          else
            DECL_RTL (parm) = parmreg;
 
          /* Copy the value into the register.  */
-         if (GET_MODE (parmreg) != GET_MODE (entry_parm))
+         if (nominal_mode != passed_mode
+             || promoted_nominal_mode != promoted_mode)
            {
-             /* If ENTRY_PARM is a hard register, it might be in a register
+             /* ENTRY_PARM has been converted to PROMOTED_MODE, its
+                mode, by the caller.  We now have to convert it to 
+                NOMINAL_MODE, if different.  However, PARMREG may be in
+                a diffent mode than NOMINAL_MODE if it is being stored
+                promoted.
+
+                If ENTRY_PARM is a hard register, it might be in a register
                 not valid for operating in its mode (e.g., an odd-numbered
                 register for a DFmode).  In that case, moves are the only
                 thing valid, so we can't do a convert from there.  This
@@ -3480,8 +3661,12 @@ assign_parms (fndecl, second_time)
              emit_move_insn (tempreg, validize_mem (entry_parm));
 
              push_to_sequence (conversion_insns);
-             convert_move (parmreg, tempreg, unsignedp);
+             tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
+
+             expand_assignment (parm,
+                                make_tree (nominal_type, tempreg), 0, 0);
              conversion_insns = get_insns ();
+             did_conversion = 1;
              end_sequence ();
            }
          else
@@ -3503,6 +3688,7 @@ assign_parms (fndecl, second_time)
              /* We can't use nominal_mode, because it will have been set to
                 Pmode above.  We must use the actual mode of the parm.  */
              parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
+             REG_USERVAR_P (parmreg) = 1;
              emit_move_insn (parmreg, DECL_RTL (parm));
              DECL_RTL (parm) = parmreg;
              /* STACK_PARM is the pointer, not the parm, and PARMREG is
@@ -3522,7 +3708,8 @@ assign_parms (fndecl, second_time)
                   && FUNCTION_ARG_CALLEE_COPIES (args_so_far,
                                                  TYPE_MODE (DECL_ARG_TYPE (parm)),
                                                  DECL_ARG_TYPE (parm),
-                                                 ! last_named))
+                                                 ! last_named)
+                  && ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
            {
              rtx copy;
              tree type = DECL_ARG_TYPE (parm);
@@ -3542,10 +3729,12 @@ assign_parms (fndecl, second_time)
              else
                copy = assign_stack_temp (TYPE_MODE (type),
                                          int_size_in_bytes (type), 1);
+             MEM_IN_STRUCT_P (copy) = AGGREGATE_TYPE_P (type);
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
              conversion_insns = get_insns ();
+             did_conversion = 1;
              end_sequence ();
            }
 #endif /* FUNCTION_ARG_CALLEE_COPIES */
@@ -3568,8 +3757,9 @@ assign_parms (fndecl, second_time)
 
              nparmregs = regno + 5;
              new = (rtx *) oballoc (nparmregs * sizeof (rtx));
-             bcopy (parm_reg_stack_loc, new, old_nparmregs * sizeof (rtx));
-             bzero (new + old_nparmregs,
+             bcopy ((char *) parm_reg_stack_loc, (char *) new,
+                    old_nparmregs * sizeof (rtx));
+             bzero ((char *) (new + old_nparmregs),
                     (nparmregs - old_nparmregs) * sizeof (rtx));
              parm_reg_stack_loc = new;
            }
@@ -3604,7 +3794,7 @@ assign_parms (fndecl, second_time)
             an invalid address, such memory-equivalences
             as we make here would screw up life analysis for it.  */
          if (nominal_mode == passed_mode
-             && ! conversion_insns
+             && ! did_conversion
              && GET_CODE (entry_parm) == MEM
              && entry_parm == stack_parm
              && stack_offset.var == 0
@@ -3646,7 +3836,7 @@ assign_parms (fndecl, second_time)
          /* Value must be stored in the stack slot STACK_PARM
             during function execution.  */
 
-         if (passed_mode != nominal_mode)
+         if (promoted_mode != nominal_mode)
            {
              /* Conversion is required.   */
              rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
@@ -3657,6 +3847,7 @@ assign_parms (fndecl, second_time)
              entry_parm = convert_to_mode (nominal_mode, tempreg,
                                            TREE_UNSIGNED (TREE_TYPE (parm)));
              conversion_insns = get_insns ();
+             did_conversion = 1;
              end_sequence ();
            }
 
@@ -3672,7 +3863,7 @@ assign_parms (fndecl, second_time)
                  MEM_IN_STRUCT_P (stack_parm) = aggregate;
                }
 
-             if (passed_mode != nominal_mode)
+             if (promoted_mode != nominal_mode)
                {
                  push_to_sequence (conversion_insns);
                  emit_move_insn (validize_mem (stack_parm),
@@ -3747,7 +3938,7 @@ assign_parms (fndecl, second_time)
   /* See how many bytes, if any, of its args a function should try to pop
      on return.  */
 
-  current_function_pops_args = RETURN_POPS_ARGS (TREE_TYPE (fndecl),
+  current_function_pops_args = RETURN_POPS_ARGS (fndecl, TREE_TYPE (fndecl),
                                                 current_function_args_size);
 
   /* For stdarg.h function, save info about
@@ -3783,7 +3974,8 @@ promoted_input_arg (regno, pmode, punsignedp)
   for (arg = DECL_ARGUMENTS (current_function_decl); arg;
        arg = TREE_CHAIN (arg))
     if (GET_CODE (DECL_INCOMING_RTL (arg)) == REG
-       && REGNO (DECL_INCOMING_RTL (arg)) == regno)
+       && REGNO (DECL_INCOMING_RTL (arg)) == regno
+       && TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
       {
        enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
        int unsignedp = TREE_UNSIGNED (TREE_TYPE (arg));
@@ -3919,15 +4111,19 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     sizetree = size_int (PUSH_ROUNDING (TREE_INT_CST_LOW (sizetree)));
 #endif
 
+  /* Pad_below needs the pre-rounded size to know how much to pad below
+     so this must be done before rounding up.  */
+  if (where_pad == downward
+    /* However, BLKmode args passed in regs have their padding done elsewhere.
+       The stack slot must be able to hold the entire register.  */
+      && !(in_regs && passed_mode == BLKmode))
+    pad_below (offset_ptr, passed_mode, sizetree);
+
   if (where_pad != none
       && (TREE_CODE (sizetree) != INTEGER_CST
          || ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
     sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
 
-  /* This must be done after rounding sizetree, so that it will subtract
-     the same value that we explicitly add below.  */
-  if (where_pad == downward)
-    pad_below (offset_ptr, passed_mode, sizetree);
   ADD_PARM_SIZE (*arg_size_ptr, sizetree);
 #endif /* ARGS_GROW_DOWNWARD */
 }
@@ -4042,8 +4238,7 @@ uninitialized_vars_warning (block)
    but for arguments instead of local variables.  */
 
 void
-setjmp_args_warning (block)
-     tree block;
+setjmp_args_warning ()
 {
   register tree decl;
   for (decl = DECL_ARGUMENTS (current_function_decl);
@@ -4239,7 +4434,9 @@ trampoline_address (function)
   /* Find an existing trampoline and return it.  */
   for (link = trampoline_list; link; link = TREE_CHAIN (link))
     if (TREE_PURPOSE (link) == function)
-      return XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0);
+      return
+       round_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
+
   for (fp = outer_function_chain; fp; fp = fp->next)
     for (link = fp->trampoline_list; link; link = TREE_CHAIN (link))
       if (TREE_PURPOSE (link) == function)
@@ -4613,6 +4810,7 @@ init_function_start (subr, filename, line)
   /* We have not allocated any temporaries yet.  */
   temp_slots = 0;
   temp_slot_level = 0;
+  target_temp_slot_level = 0;
 
   /* Within function body, compute a type's size as soon it is laid out.  */
   immediate_size_expand++;
@@ -4625,9 +4823,6 @@ init_function_start (subr, filename, line)
 
   current_function_outgoing_args_size = 0;
 
-  /* Initialize the insn lengths.  */
-  init_insn_lengths ();
-
   /* Prevent ever trying to delete the first instruction of a function.
      Also tell final how to output a linenum before the function prologue.  */
   emit_line_note (filename, line);
@@ -4653,7 +4848,7 @@ init_function_start (subr, filename, line)
     warning ("function returns an aggregate");
 
   current_function_returns_pointer
-    = (TREE_CODE (TREE_TYPE (DECL_RESULT (subr))) == POINTER_TYPE);
+    = POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (subr)));
 
   /* Indicate that we need to distinguish between the return value of the
      present function and the return value of a function being called.  */
@@ -4665,8 +4860,9 @@ init_function_start (subr, filename, line)
   /* Indicate we have no need of a frame pointer yet.  */
   frame_pointer_needed = 0;
 
-  /* By default assume not varargs.  */
+  /* By default assume not varargs or stdarg.  */
   current_function_varargs = 0;
+  current_function_stdarg = 0;
 }
 
 /* Indicate that the current function uses extra args
@@ -4680,6 +4876,11 @@ mark_varargs ()
 
 /* Expand a call to __main at the beginning of a possible main function.  */
 
+#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
+#undef HAS_INIT_SECTION
+#define HAS_INIT_SECTION
+#endif
+
 void
 expand_main_function ()
 {
@@ -4687,10 +4888,10 @@ expand_main_function ()
     {
       /* The zero below avoids a possible parse error */
       0;
-#if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
+#if !defined (HAS_INIT_SECTION)
       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, NAME__MAIN), 0,
                         VOIDmode, 0);
-#endif /* not INIT_SECTION_ASM_OP or INVOKE__main */
+#endif /* not HAS_INIT_SECTION */
     }
 }
 \f
@@ -4845,7 +5046,7 @@ expand_function_start (subr, parms_have_cleanups)
   if (aggregate_value_p (DECL_RESULT (subr)))
     {
       /* Returning something that won't go in a register.  */
-      register rtx value_address;
+      register rtx value_address = 0;
 
 #ifdef PCC_STATIC_STRUCT_RETURN
       if (current_function_returns_pcc_struct)
@@ -4952,11 +5153,23 @@ expand_function_start (subr, parms_have_cleanups)
 
   /* Fetch static chain values for containing functions.  */
   tem = decl_function_context (current_function_decl);
-  /* If not doing stupid register allocation, then start off with the static
-     chain pointer in a pseudo register.  Otherwise, we use the stack
-     address that was generated above.  */
+  /* If not doing stupid register allocation copy the static chain
+     pointer into a pseudo.  If we have small register classes, copy the
+     value from memory if static_chain_incoming_rtx is a REG.  If we do
+     stupid register allocation, we use the stack address generated above.  */
   if (tem && ! obey_regdecls)
-    last_ptr = copy_to_reg (static_chain_incoming_rtx);
+    {
+#ifdef SMALL_REGISTER_CLASSES
+      /* If the static chain originally came in a register, put it back
+        there, then move it out in the next insn.  The reason for
+        this peculiar code is to satisfy function integration.  */
+      if (GET_CODE (static_chain_incoming_rtx) == REG)
+       emit_move_insn (static_chain_incoming_rtx, last_ptr);
+#endif
+
+      last_ptr = copy_to_reg (static_chain_incoming_rtx);
+    }
+
   context_display = 0;
   while (tem)
     {
@@ -5023,7 +5236,9 @@ expand_function_end (filename, line, end_bindings)
      on a machine that fails to restore the registers.  */
   if (NON_SAVING_SETJMP && current_function_calls_setjmp)
     {
-      setjmp_protect (DECL_INITIAL (current_function_decl));
+      if (DECL_INITIAL (current_function_decl) != error_mark_node)
+       setjmp_protect (DECL_INITIAL (current_function_decl));
+
       setjmp_protect_args ();
     }
 #endif
@@ -5068,18 +5283,17 @@ expand_function_end (filename, line, end_bindings)
       emit_insns_before (seq, tail_recursion_reentry);
     }
 
-#if 0  /* I think unused parms are legitimate enough.  */
-  /* Warn about unused parms.  */
-  if (warn_unused)
+  /* Warn about unused parms if extra warnings were specified.  */
+  if (warn_unused && extra_warnings)
     {
-      rtx decl;
+      tree decl;
 
       for (decl = DECL_ARGUMENTS (current_function_decl);
           decl; decl = TREE_CHAIN (decl))
-       if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL)
+       if (! TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
+           && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
          warning_with_decl (decl, "unused parameter `%s'");
     }
-#endif
 
   /* Delete handlers for nonlocal gotos if nothing uses them.  */
   if (nonlocal_goto_handler_slot != 0 && !current_function_has_nonlocal_label)
@@ -5287,7 +5501,7 @@ contains (insn, vec)
   return 0;
 }
 
-/* Generate the prologe and epilogue RTL if the machine supports it.  Thread
+/* Generate the prologue and epilogue RTL if the machine supports it.  Thread
    this into place with notes indicating where the prologue ends and where
    the epilogue begins.  Update the basic block information when possible.  */