OSDN Git Service

(assign_parms): Don't trust the callee to copy a TREE_ADDRESSABLE
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 884cca7..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
@@ -167,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.  */
 
@@ -361,6 +367,12 @@ struct temp_slot
   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.  */
@@ -462,8 +474,8 @@ find_function_data (decl)
    since this function knows only about language-independent variables.  */
 
 void
-push_function_context_to (toplevel)
-     int toplevel;
+push_function_context_to (context)
+     tree context;
 {
   struct function *p = (struct function *) xmalloc (sizeof (struct function));
 
@@ -481,10 +493,12 @@ push_function_context_to (toplevel)
   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;
@@ -514,7 +528,7 @@ push_function_context_to (toplevel)
   p->fixup_var_refs_queue = 0;
   p->epilogue_delay_list = current_function_epilogue_delay_list;
 
-  save_tree_status (p, toplevel);
+  save_tree_status (p, context);
   save_storage_status (p);
   save_emit_status (p);
   init_emit ();
@@ -529,20 +543,23 @@ push_function_context_to (toplevel)
 void
 push_function_context ()
 {
-  push_function_context_to (0);
+  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_from (toplevel)
-     int toplevel;
+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;
@@ -554,12 +571,11 @@ pop_function_context_from (toplevel)
   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;
-  if (! toplevel)
-    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;
@@ -589,7 +605,7 @@ pop_function_context_from (toplevel)
   current_function_epilogue_delay_list = p->epilogue_delay_list;
   reg_renumber = 0;
 
-  restore_tree_status (p, toplevel);
+  restore_tree_status (p);
   restore_storage_status (p);
   restore_expr_status (p);
   restore_emit_status (p);
@@ -616,7 +632,7 @@ pop_function_context_from (toplevel)
 
 void pop_function_context ()
 {
-  pop_function_context_from (0);
+  pop_function_context_from (current_function_decl);
 }
 \f
 /* Allocate fixed slots in the stack frame of the current function.  */
@@ -831,6 +847,8 @@ assign_stack_temp (mode, size, keep)
              p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
              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));
@@ -843,6 +861,7 @@ assign_stack_temp (mode, size, keep)
                                         stack_slot_list);
 
              best_p->size = rounded_size;
+             best_p->full_size = rounded_size;
            }
        }
 
@@ -860,12 +879,22 @@ assign_stack_temp (mode, size, keep)
       /* 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.  Otherwise combine_temp_slots won't think that
-        adjacent slots really are adjacent.  */
+        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 = frame_offset - frame_offset_old;
+      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;
@@ -912,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;
                  }
@@ -976,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
@@ -1000,7 +1029,7 @@ update_temp_slot_address (old, new)
 }
 
 /* If X could be a reference to a temporary slot, mark the fact that its
-   adddress was taken.  */
+   address was taken.  */
 
 void
 mark_temp_addr_taken (x)
@@ -1080,6 +1109,7 @@ preserve_temp_slots (x)
          q->level--;
 
       p->level--;
+      p->addr_taken = 0;
       return;
     }
 
@@ -1238,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);
@@ -1467,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
@@ -2318,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);
@@ -2460,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
@@ -2479,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.  */
@@ -2955,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)))
@@ -3106,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.  */
@@ -3144,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
@@ -3196,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.  */
@@ -3224,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.  */
@@ -3248,14 +3303,14 @@ assign_parms (fndecl, second_time)
 
       if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
           && contains_placeholder_p (TYPE_SIZE (passed_type)))
-         || TYPE_NEEDS_CONSTRUCTING (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;
        }
@@ -3277,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
@@ -3293,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;
@@ -3313,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
@@ -3335,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));
 
@@ -3348,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
@@ -3362,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)
@@ -3402,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
@@ -3419,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. */
@@ -3431,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;
@@ -3474,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
@@ -3493,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
@@ -3507,9 +3574,11 @@ 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;
                }
 
@@ -3546,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
@@ -3583,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
@@ -3626,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);
@@ -3651,6 +3734,7 @@ assign_parms (fndecl, second_time)
              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 */
@@ -3710,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
@@ -3752,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));
@@ -3763,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 ();
            }
 
@@ -3778,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),
@@ -3853,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
@@ -3889,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));
@@ -4152,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);
@@ -4738,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);
@@ -4778,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
@@ -5071,7 +5154,7 @@ 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 copy the static chain
-     pointer into a psuedo.  If we have small register classes, copy the
+     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)
@@ -5200,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)
@@ -5419,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.  */