OSDN Git Service

* README.ada: Removed, integrated in ../doc/sourcebuild.texi
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 301d59d..6531c02 100644 (file)
@@ -62,6 +62,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "integrate.h"
 #include "langhooks.h"
+#include "target.h"
 
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
@@ -75,6 +76,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #define STACK_ALIGNMENT_NEEDED 1
 #endif
 
+#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
+
 /* 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
@@ -284,7 +287,7 @@ static hashval_t insns_for_mem_hash (const void *);
 static int insns_for_mem_comp (const void *, const void *);
 static int insns_for_mem_walk (rtx *, void *);
 static void compute_insns_for_mem (rtx, rtx, htab_t);
-static void prepare_function_start (void);
+static void prepare_function_start (tree);
 static void do_clobber_return_reg (rtx, void *);
 static void do_use_return_reg (rtx, void *);
 static void instantiate_virtual_regs_lossage (rtx);
@@ -692,7 +695,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
 
          if (best_p->size - rounded_size >= alignment)
            {
-             p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
+             p = ggc_alloc (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;
@@ -723,7 +726,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
     {
       HOST_WIDE_INT frame_offset_old = frame_offset;
 
-      p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
+      p = ggc_alloc (sizeof (struct temp_slot));
 
       /* We are passing an explicit alignment request to assign_stack_local.
         One side effect of that is assign_stack_local will not round SIZE
@@ -877,7 +880,7 @@ assign_temp (tree type_or_decl, int keep, int memory_required,
       if (decl && size == -1
          && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST)
        {
-         error_with_decl (decl, "size of variable `%s' is too large");
+         error ("%Jsize of variable '%D' is too large", decl, decl);
          size = 1;
        }
 
@@ -1321,8 +1324,9 @@ put_var_into_stack (tree decl, int rescan)
       if (function->decl == context)
        break;
 
-  /* If this is a variable-size object with a pseudo to address it,
-     put that pseudo into the stack, if the var is nonlocal.  */
+  /* If this is a variable-sized object or a structure passed by invisible
+     reference, with a pseudo to address it, put that pseudo into the stack
+     if the var is non-local.  */
   if (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)
       && GET_CODE (reg) == MEM
       && GET_CODE (XEXP (reg, 0)) == REG
@@ -1332,8 +1336,12 @@ put_var_into_stack (tree decl, int rescan)
       decl_mode = promoted_mode = GET_MODE (reg);
     }
 
+  /* If this variable lives in the current function and we don't need to put it
+     in the stack for the sake of setjmp or the non-locality, try to keep it in
+     a register until we know we actually need the address.  */
   can_use_addressof
     = (function == 0
+       && ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl))
        && optimize > 0
        /* FIXME make it work for promoted modes too */
        && decl_mode == promoted_mode
@@ -1352,9 +1360,6 @@ put_var_into_stack (tree decl, int rescan)
 
   if (GET_CODE (reg) == REG)
     {
-      /* If this variable lives in the current function and we don't need
-        to put things in the stack for the sake of setjmp, try to keep it
-        in a register until we know we actually need the address.  */
       if (can_use_addressof)
        gen_mem_addressof (reg, decl, rescan);
       else
@@ -1477,8 +1482,7 @@ schedule_fixup_var_refs (struct function *function, rtx reg, tree type,
     {
       struct var_refs_queue *temp;
 
-      temp
-       = (struct var_refs_queue *) ggc_alloc (sizeof (struct var_refs_queue));
+      temp = ggc_alloc (sizeof (struct var_refs_queue));
       temp->modified = reg;
       temp->promoted_mode = promoted_mode;
       temp->unsignedp = unsigned_p;
@@ -1553,7 +1557,7 @@ find_fixup_replacement (struct fixup_replacement **replacements, rtx x)
 
   if (p == 0)
     {
-      p = (struct fixup_replacement *) xmalloc (sizeof (struct fixup_replacement));
+      p = xmalloc (sizeof (struct fixup_replacement));
       p->old = x;
       p->new = 0;
       p->next = *replacements;
@@ -1627,7 +1631,7 @@ fixup_var_refs_insns_with_hash (htab_t ht, rtx var, enum machine_mode promoted_m
   rtx insn_list;
 
   tmp.key = var;
-  ime = (struct insns_for_mem_entry *) htab_find (ht, &tmp);
+  ime = htab_find (ht, &tmp);
   for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1))
     if (INSN_P (XEXP (insn_list, 0)))
       fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode,
@@ -3295,7 +3299,7 @@ insns_for_mem_walk (rtx *r, void *data)
     {
       struct insns_for_mem_entry *ifme;
       tmp.key = *r;
-      ifme = (struct insns_for_mem_entry *) htab_find (ifmwi->ht, &tmp);
+      ifme = htab_find (ifmwi->ht, &tmp);
 
       /* If we have not already recorded this INSN, do so now.  Since
         we process the INSNs in order, we know that if we have
@@ -4177,16 +4181,37 @@ get_first_nonparm_insn (void)
    EXP may be a type node or an expression (whose type is tested).  */
 
 int
-aggregate_value_p (tree exp)
+aggregate_value_p (tree exp, tree fntype)
 {
   int i, regno, nregs;
   rtx reg;
 
   tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
 
+  if (fntype)
+    switch (TREE_CODE (fntype))
+      {
+      case CALL_EXPR:
+       fntype = get_callee_fndecl (fntype);
+       fntype = fntype ? TREE_TYPE (fntype) : 0;
+       break;
+      case FUNCTION_DECL:
+       fntype = TREE_TYPE (fntype);
+       break;
+      case FUNCTION_TYPE:
+      case METHOD_TYPE:
+        break;
+      case IDENTIFIER_NODE:
+       fntype = 0;
+       break;
+      default:
+       /* We don't expect other rtl types here.  */
+       abort();
+      }
+
   if (TREE_CODE (type) == VOID_TYPE)
     return 0;
-  if (RETURN_IN_MEMORY (type))
+  if (targetm.calls.return_in_memory (type, fntype))
     return 1;
   /* Types that are TREE_ADDRESSABLE must be constructed in memory,
      and thus can't be returned in registers.  */
@@ -4230,9 +4255,7 @@ assign_parms (tree fndecl)
   /* This is a dummy PARM_DECL that we used for the function result if
      the function returns a structure.  */
   tree function_result_decl = 0;
-#ifdef SETUP_INCOMING_VARARGS
   int varargs_setup = 0;
-#endif
   int reg_parm_stack_space = 0;
   rtx conversion_insns = 0;
 
@@ -4265,9 +4288,9 @@ assign_parms (tree fndecl)
   stack_args_size.var = 0;
 
   /* If struct value address is treated as the first argument, make it so.  */
-  if (aggregate_value_p (DECL_RESULT (fndecl))
+  if (aggregate_value_p (DECL_RESULT (fndecl), fndecl)
       && ! current_function_returns_pcc_struct
-      && struct_value_incoming_rtx == 0)
+      && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0)
     {
       tree type = build_pointer_type (TREE_TYPE (fntype));
 
@@ -4281,7 +4304,7 @@ assign_parms (tree fndecl)
   orig_fnargs = fnargs;
 
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
-  parm_reg_stack_loc = (rtx *) ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
+  parm_reg_stack_loc = ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
 
   if (SPLIT_COMPLEX_ARGS)
     fnargs = split_complex_args (fnargs);
@@ -4319,6 +4342,7 @@ assign_parms (tree fndecl)
       int last_named = 0, named_arg;
       int in_regs;
       int partial = 0;
+      int pretend_bytes = 0;
 
       /* Set LAST_NAMED if this is last named arg before last
         anonymous args.  */
@@ -4336,7 +4360,7 @@ assign_parms (tree fndecl)
       /* Set NAMED_ARG if this arg should be treated as a named arg.  For
         most machines, if this is a varargs/stdarg function, then we treat
         the last named arg as if it were anonymous too.  */
-      named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named;
+      named_arg = targetm.calls.strict_argument_naming (&args_so_far) ? 1 : ! last_named;
 
       if (TREE_TYPE (parm) == error_mark_node
          /* This can happen after weird syntax errors
@@ -4401,11 +4425,12 @@ assign_parms (tree fndecl)
 
       promoted_mode = passed_mode;
 
-#ifdef PROMOTE_FUNCTION_ARGS
-      /* Compute the mode in which the arg is actually extended to.  */
-      unsignedp = TREE_UNSIGNED (passed_type);
-      promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
-#endif
+      if (targetm.calls.promote_function_args (TREE_TYPE (fndecl)))
+       {
+         /* Compute the mode in which the arg is actually extended to.  */
+         unsignedp = TREE_UNSIGNED (passed_type);
+         promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
+       }
 
       /* Let machine desc say which reg (if any) the parm arrives in.
         0 means it arrives on the stack.  */
@@ -4420,7 +4445,6 @@ assign_parms (tree fndecl)
       if (entry_parm == 0)
        promoted_mode = passed_mode;
 
-#ifdef SETUP_INCOMING_VARARGS
       /* If this is the last named parameter, do any required setup for
         varargs or stdargs.  We need to know about the case of this being an
         addressable type, in which case we skip the registers it
@@ -4433,11 +4457,18 @@ assign_parms (tree fndecl)
         Also, indicate when RTL generation is to be suppressed.  */
       if (last_named && !varargs_setup)
        {
-         SETUP_INCOMING_VARARGS (args_so_far, promoted_mode, passed_type,
-                                 current_function_pretend_args_size, 0);
+         int varargs_pretend_bytes = 0;
+         targetm.calls.setup_incoming_varargs (&args_so_far, promoted_mode,
+                                               passed_type,
+                                               &varargs_pretend_bytes, 0);
          varargs_setup = 1;
+
+         /* If the back-end has requested extra stack space, record how
+            much is needed.  Do not change pretend_args_size otherwise
+            since it may be nonzero from an earlier partial argument.  */
+         if (varargs_pretend_bytes > 0)
+           current_function_pretend_args_size = varargs_pretend_bytes;
        }
-#endif
 
       /* Determine parm's home in the stack,
         in case it arrives in the stack or we should pretend it did.
@@ -4457,7 +4488,8 @@ assign_parms (tree fndecl)
 #endif
       if (!in_regs && !named_arg)
        {
-         int pretend_named = PRETEND_OUTGOING_VARARGS_NAMED;
+         int pretend_named =
+           targetm.calls.pretend_outgoing_varargs_named (&args_so_far);
          if (pretend_named)
            {
 #ifdef FUNCTION_INCOMING_ARG
@@ -4479,8 +4511,43 @@ assign_parms (tree fndecl)
 
 #ifdef FUNCTION_ARG_PARTIAL_NREGS
       if (entry_parm)
-       partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
-                                             passed_type, named_arg);
+       {
+         partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
+                                               passed_type, named_arg);
+         if (partial
+#ifndef MAYBE_REG_PARM_STACK_SPACE
+             /* The caller might already have allocated stack space
+                for the register parameters.  */
+             && reg_parm_stack_space == 0
+#endif
+             )
+           {
+             /* Part of this argument is passed in registers and part
+                is passed on the stack.  Ask the prologue code to extend
+                the stack part so that we can recreate the full value.
+
+                PRETEND_BYTES is the size of the registers we need to store.
+                CURRENT_FUNCTION_PRETEND_ARGS_SIZE is the amount of extra
+                stack space that the prologue should allocate.
+
+                Internally, gcc assumes that the argument pointer is
+                aligned to STACK_BOUNDARY bits.  This is used both for
+                alignment optimizations (see init_emit) and to locate
+                arguments that are aligned to more than PARM_BOUNDARY
+                bits.  We must preserve this invariant by rounding
+                CURRENT_FUNCTION_PRETEND_ARGS_SIZE up to a stack
+                boundary.  */
+             pretend_bytes = partial * UNITS_PER_WORD;
+             current_function_pretend_args_size
+               = CEIL_ROUND (pretend_bytes, STACK_BYTES);
+
+             /* If PRETEND_BYTES != CURRENT_FUNCTION_PRETEND_ARGS_SIZE,
+                insert the padding before the start of the first pretend
+                argument.  */
+             stack_args_size.constant
+               = (current_function_pretend_args_size - pretend_bytes);
+           }
+       }
 #endif
 
       memset (&locate, 0, sizeof (locate));
@@ -4507,6 +4574,8 @@ assign_parms (tree fndecl)
                                                  offset_rtx));
 
        set_mem_attributes (stack_parm, parm, 1);
+       if (entry_parm && MEM_ATTRS (stack_parm)->align < PARM_BOUNDARY)
+         set_mem_align (stack_parm, PARM_BOUNDARY);
 
        /* Set also REG_ATTRS if parameter was passed in a register.  */
        if (entry_parm)
@@ -4523,21 +4592,11 @@ assign_parms (tree fndecl)
 
       if (partial)
        {
-#ifndef MAYBE_REG_PARM_STACK_SPACE
-         /* When REG_PARM_STACK_SPACE is nonzero, stack space for
-            split parameters was allocated by our caller, so we
-            won't be pushing it in the prolog.  */
-         if (reg_parm_stack_space == 0)
-#endif
-         current_function_pretend_args_size
-           = (((partial * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
-              / (PARM_BOUNDARY / BITS_PER_UNIT)
-              * (PARM_BOUNDARY / BITS_PER_UNIT));
-
          /* Handle calls that pass values in multiple non-contiguous
             locations.  The Irix 6 ABI has examples of this.  */
          if (GET_CODE (entry_parm) == PARALLEL)
            emit_group_store (validize_mem (stack_parm), entry_parm,
+                             TREE_TYPE (parm),
                              int_size_in_bytes (TREE_TYPE (parm)));
 
          else
@@ -4576,10 +4635,7 @@ assign_parms (tree fndecl)
 #endif
          )
        {
-         stack_args_size.constant += locate.size.constant;
-         /* locate.size doesn't include the part in regs.  */
-         if (partial)
-           stack_args_size.constant += current_function_pretend_args_size;
+         stack_args_size.constant += pretend_bytes + locate.size.constant;
          if (locate.size.var)
            ADD_PARM_SIZE (stack_args_size, locate.size.var);
        }
@@ -4644,7 +4700,12 @@ assign_parms (tree fndecl)
 
         Set DECL_RTL to that place.  */
 
-      if (nominal_mode == BLKmode || GET_CODE (entry_parm) == PARALLEL)
+      if (nominal_mode == BLKmode
+#ifdef BLOCK_REG_PADDING
+         || (locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward)
+             && GET_MODE_SIZE (promoted_mode) < UNITS_PER_WORD)
+#endif
+         || GET_CODE (entry_parm) == PARALLEL)
        {
          /* If a BLKmode arrives in registers, copy it to a stack slot.
             Handle calls that pass values in multiple non-contiguous
@@ -4666,9 +4727,8 @@ assign_parms (tree fndecl)
 
              if (stack_parm == 0)
                {
-                 stack_parm
-                   = assign_stack_local (GET_MODE (entry_parm),
-                                         size_stored, 0);
+                 stack_parm = assign_stack_local (BLKmode, size_stored, 0);
+                 PUT_MODE (stack_parm, GET_MODE (entry_parm));
                  set_mem_attributes (stack_parm, parm, 1);
                }
 
@@ -4680,7 +4740,7 @@ assign_parms (tree fndecl)
              /* Handle calls that pass values in multiple non-contiguous
                 locations.  The Irix 6 ABI has examples of this.  */
              if (GET_CODE (entry_parm) == PARALLEL)
-               emit_group_store (mem, entry_parm, size);
+               emit_group_store (mem, entry_parm, TREE_TYPE (parm), size);
 
              else if (size == 0)
                ;
@@ -4692,7 +4752,13 @@ assign_parms (tree fndecl)
                  enum machine_mode mode
                    = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
 
-                 if (mode != BLKmode)
+                 if (mode != BLKmode
+#ifdef BLOCK_REG_PADDING
+                     && (size == UNITS_PER_WORD
+                         || (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
+                             != (BYTES_BIG_ENDIAN ? upward : downward)))
+#endif
+                     )
                    {
                      rtx reg = gen_rtx_REG (mode, REGNO (entry_parm));
                      emit_move_insn (change_address (mem, mode, 0), reg);
@@ -4703,7 +4769,13 @@ assign_parms (tree fndecl)
                     to memory.  Note that the previous test doesn't
                     handle all cases (e.g. SIZE == 3).  */
                  else if (size != UNITS_PER_WORD
-                          && BYTES_BIG_ENDIAN)
+#ifdef BLOCK_REG_PADDING
+                          && (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
+                              == downward)
+#else
+                          && BYTES_BIG_ENDIAN
+#endif
+                          )
                    {
                      rtx tem, x;
                      int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
@@ -4812,7 +4884,7 @@ assign_parms (tree fndecl)
              /* TREE_USED gets set erroneously during expand_assignment.  */
              save_tree_used = TREE_USED (parm);
              expand_assignment (parm,
-                                make_tree (nominal_type, tempreg), 0, 0);
+                                make_tree (nominal_type, tempreg), 0);
              TREE_USED (parm) = save_tree_used;
              conversion_insns = get_insns ();
              did_conversion = 1;
@@ -4924,10 +4996,10 @@ assign_parms (tree fndecl)
                 but it's also rare and we need max_parm_reg to be
                 precisely correct.  */
              max_parm_reg = regno + 1;
-             new = (rtx *) ggc_realloc (parm_reg_stack_loc,
-                                     max_parm_reg * sizeof (rtx));
-             memset ((char *) (new + old_max_parm_reg), 0,
-                    (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
+             new = ggc_realloc (parm_reg_stack_loc,
+                                max_parm_reg * sizeof (rtx));
+             memset (new + old_max_parm_reg, 0,
+                     (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
              parm_reg_stack_loc = new;
            }
 
@@ -5111,11 +5183,7 @@ assign_parms (tree fndecl)
       rtx addr = DECL_RTL (function_result_decl);
       rtx x;
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-      if (GET_MODE (addr) != Pmode)
-       addr = convert_memory_address (Pmode, addr);
-#endif
-
+      addr = convert_memory_address (Pmode, addr);
       x = gen_rtx_MEM (DECL_MODE (result), addr);
       set_mem_attributes (x, result, 1);
       SET_DECL_RTL (result, x);
@@ -5135,8 +5203,6 @@ assign_parms (tree fndecl)
 #endif
 #endif
 
-#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
-
   current_function_args_size
     = ((current_function_args_size + STACK_BYTES - 1)
        / STACK_BYTES) * STACK_BYTES;
@@ -5256,8 +5322,6 @@ split_complex_args (tree args)
    that REGNO is promoted from and whether the promotion was signed or
    unsigned.  */
 
-#ifdef PROMOTE_FUNCTION_ARGS
-
 rtx
 promoted_input_arg (unsigned int regno, enum machine_mode *pmode, int *punsignedp)
 {
@@ -5285,7 +5349,6 @@ promoted_input_arg (unsigned int regno, enum machine_mode *pmode, int *punsigned
   return 0;
 }
 
-#endif
 \f
 /* Compute the size and offset from the start of the stacked arguments for a
    parm passed in mode PASSED_MODE and with type TYPE.
@@ -5367,6 +5430,7 @@ locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs,
     = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
   where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
   boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
+  locate->where_pad = where_pad;
 
 #ifdef ARGS_GROW_DOWNWARD
   locate->slot_offset.constant = -initial_offset_ptr->constant;
@@ -5449,8 +5513,17 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
 {
   tree save_var = NULL_TREE;
   HOST_WIDE_INT save_constant = 0;
-
   int boundary_in_bytes = boundary / BITS_PER_UNIT;
+  HOST_WIDE_INT sp_offset = STACK_POINTER_OFFSET;
+
+#ifdef SPARC_STACK_BOUNDARY_HACK
+  /* The sparc port has a bug.  It sometimes claims a STACK_BOUNDARY
+     higher than the real alignment of %sp.  However, when it does this,
+     the alignment of %sp+STACK_POINTER_OFFSET will be STACK_BOUNDARY.
+     This is a temporary hack while the sparc port is fixed.  */
+  if (SPARC_STACK_BOUNDARY_HACK)
+    sp_offset = 0;
+#endif
 
   if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
     {
@@ -5465,14 +5538,17 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
     {
       if (offset_ptr->var)
        {
-         offset_ptr->var =
+         tree sp_offset_tree = ssize_int (sp_offset);
+         tree offset = size_binop (PLUS_EXPR,
+                                   ARGS_SIZE_TREE (*offset_ptr),
+                                   sp_offset_tree);
 #ifdef ARGS_GROW_DOWNWARD
-           round_down
+         tree rounded = round_down (offset, boundary / BITS_PER_UNIT);
 #else
-           round_up
+         tree rounded = round_up   (offset, boundary / BITS_PER_UNIT);
 #endif
-             (ARGS_SIZE_TREE (*offset_ptr),
-              boundary / BITS_PER_UNIT);
+
+         offset_ptr->var = size_binop (MINUS_EXPR, rounded, sp_offset_tree);
          /* ARGS_SIZE_TREE includes constant term.  */
          offset_ptr->constant = 0;
          if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
@@ -5481,11 +5557,11 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
        }
       else
        {
-         offset_ptr->constant =
+         offset_ptr->constant = -sp_offset +
 #ifdef ARGS_GROW_DOWNWARD
-           FLOOR_ROUND (offset_ptr->constant, boundary_in_bytes);
+           FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
 #else
-           CEIL_ROUND (offset_ptr->constant, boundary_in_bytes);
+           CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
 #endif
            if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
              alignment_pad->constant = offset_ptr->constant - save_constant;
@@ -5543,19 +5619,19 @@ uninitialized_vars_warning (tree block)
             with a nonzero DECL_INITIAL had an initializer, so do not
             claim it is potentially uninitialized.
 
-            We do not care about the actual value in DECL_INITIAL, so we do
-            not worry that it may be a dangling pointer.  */
-         && DECL_INITIAL (decl) == NULL_TREE
+            When the DECL_INITIAL is NULL call the language hook to tell us
+            if we want to warn.  */
+         && (DECL_INITIAL (decl) == NULL_TREE || lang_hooks.decl_uninit (decl))
          && regno_uninitialized (REGNO (DECL_RTL (decl))))
-       warning_with_decl (decl,
-                          "`%s' might be used uninitialized in this function");
+       warning ("%J'%D' might be used uninitialized in this function",
+                decl, decl);
       if (extra_warnings
          && TREE_CODE (decl) == VAR_DECL
          && DECL_RTL (decl) != 0
          && GET_CODE (DECL_RTL (decl)) == REG
          && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
-       warning_with_decl (decl,
-                          "variable `%s' might be clobbered by `longjmp' or `vfork'");
+       warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'",
+                decl, decl);
     }
   for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
     uninitialized_vars_warning (sub);
@@ -5573,8 +5649,8 @@ setjmp_args_warning (void)
     if (DECL_RTL (decl) != 0
        && GET_CODE (DECL_RTL (decl)) == REG
        && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
-      warning_with_decl (decl,
-                        "argument `%s' might be clobbered by `longjmp' or `vfork'");
+      warning ("%Jargument '%D' might be clobbered by `longjmp' or `vfork'",
+              decl, decl);
 }
 
 /* If this function call setjmp, put all vars into the stack
@@ -5864,7 +5940,7 @@ identify_blocks (void)
   /* Fill the BLOCK_VECTOR with all of the BLOCKs in this function, in
      depth-first order.  */
   block_vector = get_block_vector (block, &n_blocks);
-  block_stack = (tree *) xmalloc (n_blocks * sizeof (tree));
+  block_stack = xmalloc (n_blocks * sizeof (tree));
 
   last_block_vector = identify_blocks_1 (get_insns (),
                                         block_vector + 1,
@@ -6168,7 +6244,7 @@ get_block_vector (tree block, int *n_blocks_p)
   tree *block_vector;
 
   *n_blocks_p = all_blocks (block, NULL);
-  block_vector = (tree *) xmalloc (*n_blocks_p * sizeof (tree));
+  block_vector = xmalloc (*n_blocks_p * sizeof (tree));
   all_blocks (block, block_vector);
 
   return block_vector;
@@ -6226,103 +6302,77 @@ debug_find_var_in_block_tree (tree var, tree block)
   return NULL_TREE;
 }
 \f
-/* Allocate a function structure and reset its contents to the defaults.  */
+/* Allocate a function structure for FNDECL and set its contents
+   to the defaults.  */
 
-static void
-prepare_function_start (void)
+void
+allocate_struct_function (tree fndecl)
 {
-  cfun = (struct function *) ggc_alloc_cleared (sizeof (struct function));
+  tree result;
 
-  init_stmt_for_function ();
-  init_eh_for_function ();
-
-  cse_not_expected = ! optimize;
+  cfun = ggc_alloc_cleared (sizeof (struct function));
 
-  /* Caller save not needed yet.  */
-  caller_save_needed = 0;
-
-  /* No stack slots have been made yet.  */
-  stack_slot_list = 0;
-
-  current_function_has_nonlocal_label = 0;
-  current_function_has_nonlocal_goto = 0;
-
-  /* There is no stack slot for handling nonlocal gotos.  */
-  nonlocal_goto_handler_slots = 0;
-  nonlocal_goto_stack_level = 0;
+  max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
 
-  /* No labels have been declared for nonlocal use.  */
-  nonlocal_labels = 0;
-  nonlocal_goto_handler_labels = 0;
+  cfun->stack_alignment_needed = STACK_BOUNDARY;
+  cfun->preferred_stack_boundary = STACK_BOUNDARY;
 
-  /* No function calls so far in this function.  */
-  function_call_count = 0;
+  current_function_funcdef_no = funcdef_no++;
 
-  /* No parm regs have been allocated.
-     (This is important for output_inline_function.)  */
-  max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
+  cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
 
-  /* Initialize the RTL mechanism.  */
+  init_stmt_for_function ();
+  init_eh_for_function ();
   init_emit ();
-
-  /* Initialize the queue of pending postincrement and postdecrements,
-     and some other info in expr.c.  */
   init_expr ();
-
-  /* We haven't done register allocation yet.  */
-  reg_renumber = 0;
-
   init_varasm_status (cfun);
 
-  /* Clear out data used for inlining.  */
-  cfun->inlinable = 0;
-  cfun->original_decl_initial = 0;
-  cfun->original_arg_vector = 0;
+  (*lang_hooks.function.init) (cfun);
+  if (init_machine_status)
+    cfun->machine = (*init_machine_status) ();
 
-  cfun->stack_alignment_needed = STACK_BOUNDARY;
-  cfun->preferred_stack_boundary = STACK_BOUNDARY;
+  if (fndecl == NULL)
+    return;
 
-  /* Set if a call to setjmp is seen.  */
-  current_function_calls_setjmp = 0;
+  DECL_SAVED_INSNS (fndecl) = cfun;
+  cfun->decl = fndecl;
 
-  /* Set if a call to longjmp is seen.  */
-  current_function_calls_longjmp = 0;
+  current_function_name = (*lang_hooks.decl_printable_name) (fndecl, 2);
 
-  current_function_calls_alloca = 0;
-  current_function_calls_eh_return = 0;
-  current_function_calls_constant_p = 0;
-  current_function_contains_functions = 0;
-  current_function_is_leaf = 0;
-  current_function_nothrow = 0;
-  current_function_sp_is_unchanging = 0;
-  current_function_uses_only_leaf_regs = 0;
-  current_function_has_computed_jump = 0;
-  current_function_is_thunk = 0;
+  result = DECL_RESULT (fndecl);
+  if (aggregate_value_p (result, fndecl))
+    {
+#ifdef PCC_STATIC_STRUCT_RETURN
+      current_function_returns_pcc_struct = 1;
+#endif
+      current_function_returns_struct = 1;
+    }
 
-  current_function_returns_pcc_struct = 0;
-  current_function_returns_struct = 0;
-  current_function_epilogue_delay_list = 0;
-  current_function_uses_const_pool = 0;
-  current_function_uses_pic_offset_table = 0;
-  current_function_cannot_inline = 0;
+  current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result));
 
-  /* We have not yet needed to make a label to jump to for tail-recursion.  */
-  tail_recursion_label = 0;
+  current_function_needs_context
+    = (decl_function_context (current_function_decl) != 0
+       && ! DECL_NO_STATIC_CHAIN (current_function_decl));
+}
 
-  /* We haven't had a need to make a save area for ap yet.  */
-  arg_pointer_save_area = 0;
+/* Reset cfun, and other non-struct-function variables to defaults as
+   appropriate for emitting rtl at the start of a function.  */
 
-  /* No stack slots allocated yet.  */
-  frame_offset = 0;
+static void
+prepare_function_start (tree fndecl)
+{
+  if (fndecl && DECL_SAVED_INSNS (fndecl))
+    cfun = DECL_SAVED_INSNS (fndecl);
+  else
+    allocate_struct_function (fndecl);
 
-  /* No SAVE_EXPRs in this function yet.  */
-  save_expr_regs = 0;
+  cse_not_expected = ! optimize;
 
-  /* No RTL_EXPRs in this function yet.  */
-  rtl_expr_chain = 0;
+  /* Caller save not needed yet.  */
+  caller_save_needed = 0;
 
-  /* Set up to allocate temporaries.  */
-  init_temp_slots ();
+  /* We haven't done register allocation yet.  */
+  reg_renumber = 0;
 
   /* Indicate that we need to distinguish between the return value of the
      present function and the return value of a function being called.  */
@@ -6336,27 +6386,6 @@ prepare_function_start (void)
 
   /* Indicate we have no need of a frame pointer yet.  */
   frame_pointer_needed = 0;
-
-  /* By default assume not stdarg.  */
-  current_function_stdarg = 0;
-
-  /* We haven't made any trampolines for this function yet.  */
-  trampoline_list = 0;
-
-  init_pending_stack_adjust ();
-  inhibit_defer_pop = 0;
-
-  current_function_outgoing_args_size = 0;
-
-  current_function_funcdef_no = funcdef_no++;
-
-  cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
-
-  cfun->max_jumptable_ents = 0;
-
-  (*lang_hooks.function.init) (cfun);
-  if (init_machine_status)
-    cfun->machine = (*init_machine_status) ();
 }
 
 /* Initialize the rtl expansion mechanism so that we can do simple things
@@ -6365,7 +6394,7 @@ prepare_function_start (void)
 void
 init_dummy_function_start (void)
 {
-  prepare_function_start ();
+  prepare_function_start (NULL);
 }
 
 /* Generate RTL for the start of the function SUBR (a FUNCTION_DECL tree node)
@@ -6375,16 +6404,7 @@ init_dummy_function_start (void)
 void
 init_function_start (tree subr)
 {
-  prepare_function_start ();
-
-  current_function_name = (*lang_hooks.decl_printable_name) (subr, 2);
-  cfun->decl = subr;
-
-  /* Nonzero if this is a nested function that uses a static chain.  */
-
-  current_function_needs_context
-    = (decl_function_context (current_function_decl) != 0
-       && ! DECL_NO_STATIC_CHAIN (current_function_decl));
+  prepare_function_start (subr);
 
   /* Within function body, compute a type's size as soon it is laid out.  */
   immediate_size_expand++;
@@ -6401,23 +6421,11 @@ init_function_start (tree subr)
      Also, final expects a note to appear there.  */
   emit_note (NOTE_INSN_DELETED);
 
-  /* Set flags used by final.c.  */
-  if (aggregate_value_p (DECL_RESULT (subr)))
-    {
-#ifdef PCC_STATIC_STRUCT_RETURN
-      current_function_returns_pcc_struct = 1;
-#endif
-      current_function_returns_struct = 1;
-    }
-
   /* Warn if this value is an aggregate type,
      regardless of which calling convention we are using for it.  */
   if (warn_aggregate_return
       && AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr))))
     warning ("function returns an aggregate");
-
-  current_function_returns_pointer
-    = POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (subr)));
 }
 
 /* Make sure all values used by the optimization passes have sane
@@ -6563,7 +6571,7 @@ expand_function_start (tree subr, int parms_have_cleanups)
      before any library calls that assign parms might generate.  */
 
   /* Decide whether to return the value in memory or in a register.  */
-  if (aggregate_value_p (DECL_RESULT (subr)))
+  if (aggregate_value_p (DECL_RESULT (subr), subr))
     {
       /* Returning something that won't go in a register.  */
       rtx value_address = 0;
@@ -6577,13 +6585,14 @@ expand_function_start (tree subr, int parms_have_cleanups)
       else
 #endif
        {
+         rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 1);
          /* Expect to be passed the address of a place to store the value.
             If it is passed as an argument, assign_parms will take care of
             it.  */
-         if (struct_value_incoming_rtx)
+         if (sv)
            {
              value_address = gen_reg_rtx (Pmode);
-             emit_move_insn (value_address, struct_value_incoming_rtx);
+             emit_move_insn (value_address, sv);
            }
        }
       if (value_address)
@@ -6899,7 +6908,7 @@ expand_function_end (void)
           decl; decl = TREE_CHAIN (decl))
        if (! TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
            && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
-         warning_with_decl (decl, "unused parameter `%s'");
+          warning ("%Junused parameter '%D'", decl, decl);
     }
 
   /* Delete handlers for nonlocal gotos if nothing uses them.  */
@@ -7020,10 +7029,9 @@ expand_function_end (void)
            {
              int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result));
 
-#ifdef PROMOTE_FUNCTION_RETURN
-             promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
-                           &unsignedp, 1);
-#endif
+             if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
+               promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
+                             &unsignedp, 1);
 
              convert_move (real_decl_rtl, decl_rtl, unsignedp);
            }
@@ -7036,6 +7044,7 @@ expand_function_end (void)
                emit_group_move (real_decl_rtl, decl_rtl);
              else
                emit_group_load (real_decl_rtl, decl_rtl,
+                                TREE_TYPE (decl_result),
                                 int_size_in_bytes (TREE_TYPE (decl_result)));
            }
          else
@@ -7068,12 +7077,9 @@ expand_function_end (void)
         assignment and USE below when inlining this function.  */
       REG_FUNCTION_VALUE_P (outgoing) = 1;
 
-#ifdef POINTERS_EXTEND_UNSIGNED
       /* The address may be ptr_mode and OUTGOING may be Pmode.  */
-      if (GET_MODE (outgoing) != GET_MODE (value_address))
-       value_address = convert_memory_address (GET_MODE (outgoing),
-                                               value_address);
-#endif
+      value_address = convert_memory_address (GET_MODE (outgoing),
+                                             value_address);
 
       emit_move_insn (outgoing, value_address);