OSDN Git Service

* config/cpu/s390/atomicity.h (__exchange_and_add): Add "memory"
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 046a4ad..9db8ae0 100644 (file)
@@ -1,6 +1,7 @@
 /* Expands front end tree to back end RTL for GCC.
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -59,6 +60,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "langhooks.h"
 #include "target.h"
 #include "cfglayout.h"
+#include "tree-gimple.h"
 
 #ifndef LOCAL_ALIGNMENT
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
@@ -285,7 +287,6 @@ pop_function_context_from (tree context ATTRIBUTE_UNUSED)
   outer_function_chain = p->outer;
 
   current_function_decl = p->decl;
-  reg_renumber = 0;
 
   lang_hooks.function.leave_nested (p);
 
@@ -352,7 +353,7 @@ free_after_compilation (struct function *f)
    This size counts from zero.  It is not rounded to PREFERRED_STACK_BOUNDARY;
    the caller may have to do that.  */
 
-HOST_WIDE_INT
+static HOST_WIDE_INT
 get_func_frame_size (struct function *f)
 {
 #ifdef FRAME_GROWS_DOWNWARD
@@ -1922,8 +1923,9 @@ use_register_for_decl (tree decl)
   if (flag_float_store && FLOAT_TYPE_P (TREE_TYPE (decl)))
     return false;
 
-  /* Compiler-generated temporaries can always go in registers.  */
-  if (DECL_ARTIFICIAL (decl))
+  /* If we're not interested in tracking debugging information for
+     this decl, then we can certainly put it in a register.  */
+  if (DECL_IGNORED_P (decl))
     return true;
 
   return (optimize || DECL_REGISTER (decl));
@@ -1990,7 +1992,6 @@ struct assign_parm_data_one
   struct locate_and_pad_arg_data locate;
   int partial;
   BOOL_BITFIELD named_arg : 1;
-  BOOL_BITFIELD last_named : 1;
   BOOL_BITFIELD passed_pointer : 1;
   BOOL_BITFIELD on_stack : 1;
   BOOL_BITFIELD loaded_in_reg : 1;
@@ -2049,6 +2050,7 @@ split_complex_args (tree args)
        {
          tree decl;
          tree subtype = TREE_TYPE (type);
+         bool addressable = TREE_ADDRESSABLE (p);
 
          /* Rewrite the PARM_DECL's type with its component.  */
          TREE_TYPE (p) = subtype;
@@ -2056,11 +2058,20 @@ split_complex_args (tree args)
          DECL_MODE (p) = VOIDmode;
          DECL_SIZE (p) = NULL;
          DECL_SIZE_UNIT (p) = NULL;
+         /* If this arg must go in memory, put it in a pseudo here.
+            We can't allow it to go in memory as per normal parms,
+            because the usual place might not have the imag part
+            adjacent to the real part.  */
+         DECL_ARTIFICIAL (p) = addressable;
+         DECL_IGNORED_P (p) = addressable;
+         TREE_ADDRESSABLE (p) = 0;
          layout_decl (p, 0);
 
          /* Build a second synthetic decl.  */
          decl = build_decl (PARM_DECL, NULL_TREE, subtype);
          DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (p);
+         DECL_ARTIFICIAL (decl) = addressable;
+         DECL_IGNORED_P (decl) = addressable;
          layout_decl (decl, 0);
 
          /* Splice it in; skip the new decl.  */
@@ -2095,6 +2106,7 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
       decl = build_decl (PARM_DECL, NULL_TREE, type);
       DECL_ARG_TYPE (decl) = type;
       DECL_ARTIFICIAL (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
 
       TREE_CHAIN (decl) = fnargs;
       fnargs = decl;
@@ -2123,24 +2135,15 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
 
   memset (data, 0, sizeof (*data));
 
-  /* Set LAST_NAMED if this is last named arg before last anonymous args.  */
-  if (current_function_stdarg)
-    {
-      tree tem;
-      for (tem = TREE_CHAIN (parm); tem; tem = TREE_CHAIN (tem))
-       if (DECL_NAME (tem))
-         break;
-      if (tem == 0)
-       data->last_named = true;
-    }
-
-  /* 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.  */
-  if (targetm.calls.strict_argument_naming (&all->args_so_far))
-    data->named_arg = 1;
+  /* NAMED_ARG is a mis-nomer.  We really mean 'non-varadic'. */
+  if (!current_function_stdarg)
+    data->named_arg = 1;  /* No varadic parms.  */
+  else if (TREE_CHAIN (parm))
+    data->named_arg = 1;  /* Not the last non-varadic parm. */
+  else if (targetm.calls.strict_argument_naming (&all->args_so_far))
+    data->named_arg = 1;  /* Only varadic ones are unnamed.  */
   else
-    data->named_arg = !data->last_named;
+    data->named_arg = 0;  /* Treat as varadic.  */
 
   nominal_type = TREE_TYPE (parm);
   passed_type = DECL_ARG_TYPE (parm);
@@ -2286,10 +2289,10 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
     {
       int partial;
 
-      partial = FUNCTION_ARG_PARTIAL_NREGS (all->args_so_far,
-                                           data->promoted_mode,
-                                           data->passed_type,
-                                           data->named_arg);
+      partial = targetm.calls.arg_partial_bytes (&all->args_so_far,
+                                                data->promoted_mode,
+                                                data->passed_type,
+                                                data->named_arg);
       data->partial = partial;
 
       /* The caller might already have allocated stack space for the
@@ -2315,7 +2318,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
             argument on the stack.  */
          gcc_assert (!all->extra_pretend_bytes && !all->pretend_args_size);
 
-         pretend_bytes = partial * UNITS_PER_WORD;
+         pretend_bytes = partial;
          all->pretend_args_size = CEIL_ROUND (pretend_bytes, STACK_BYTES);
 
          /* We want to align relative to the actual stack pointer, so
@@ -2393,22 +2396,21 @@ assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
 
   set_mem_attributes (stack_parm, parm, 1);
 
-  boundary = FUNCTION_ARG_BOUNDARY (data->promoted_mode, data->passed_type);
-  align = 0;
+  boundary = data->locate.boundary;
+  align = BITS_PER_UNIT;
 
   /* If we're padding upward, we know that the alignment of the slot
      is FUNCTION_ARG_BOUNDARY.  If we're using slot_offset, we're
      intentionally forcing upward padding.  Otherwise we have to come
      up with a guess at the alignment based on OFFSET_RTX.  */
-  if (data->locate.where_pad == upward || data->entry_parm)
+  if (data->locate.where_pad != downward || data->entry_parm)
     align = boundary;
   else if (GET_CODE (offset_rtx) == CONST_INT)
     {
       align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary;
       align = align & -align;
     }
-  if (align > 0)
-    set_mem_align (stack_parm, align);
+  set_mem_align (stack_parm, align);
 
   if (data->entry_parm)
     set_reg_attrs_for_parm (data->entry_parm, stack_parm);
@@ -2439,8 +2441,11 @@ assign_parm_adjust_entry_rtl (struct assign_parm_data_one *data)
                          data->passed_type, 
                          int_size_in_bytes (data->passed_type));
       else
-       move_block_from_reg (REGNO (entry_parm), validize_mem (stack_parm),
-                            data->partial);
+       {
+         gcc_assert (data->partial % UNITS_PER_WORD == 0);
+         move_block_from_reg (REGNO (entry_parm), validize_mem (stack_parm),
+                              data->partial / UNITS_PER_WORD);
+       }
 
       entry_parm = stack_parm;
     }
@@ -2477,7 +2482,6 @@ assign_parm_adjust_entry_rtl (struct assign_parm_data_one *data)
 /* A subroutine of assign_parms.  Adjust DATA->STACK_RTL such that it's
    always valid and properly aligned.  */
 
-
 static void
 assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
 {
@@ -2486,8 +2490,12 @@ assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
   /* If we can't trust the parm stack slot to be aligned enough for its
      ultimate type, don't use that slot after entry.  We'll make another
      stack slot, if we need one.  */
-  if (STRICT_ALIGNMENT && stack_parm
-      && GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm))
+  if (stack_parm
+      && ((STRICT_ALIGNMENT
+          && GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm))
+         || (data->nominal_type
+             && TYPE_ALIGN (data->nominal_type) > MEM_ALIGN (stack_parm)
+             && MEM_ALIGN (stack_parm) < PREFERRED_STACK_BOUNDARY)))
     stack_parm = NULL;
 
   /* If parm was passed in memory, and we need to convert it on entry,
@@ -2533,6 +2541,9 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
 {
   rtx entry_parm = data->entry_parm;
   rtx stack_parm = data->stack_parm;
+  HOST_WIDE_INT size;
+  HOST_WIDE_INT size_stored;
+  rtx orig_entry_parm = entry_parm;
 
   if (GET_CODE (entry_parm) == PARALLEL)
     entry_parm = emit_group_move_into_temps (entry_parm);
@@ -2540,68 +2551,78 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
   /* If we've a non-block object that's nevertheless passed in parts,
      reconstitute it in register operations rather than on the stack.  */
   if (GET_CODE (entry_parm) == PARALLEL
-      && data->nominal_mode != BLKmode
-      && XVECLEN (entry_parm, 0) > 1
-      && use_register_for_decl (parm))
+      && data->nominal_mode != BLKmode)
     {
-      rtx parmreg = gen_reg_rtx (data->nominal_mode);
+      rtx elt0 = XEXP (XVECEXP (orig_entry_parm, 0, 0), 0);
 
-      push_to_sequence (all->conversion_insns);
+      if ((XVECLEN (entry_parm, 0) > 1
+          || hard_regno_nregs[REGNO (elt0)][GET_MODE (elt0)] > 1)
+         && use_register_for_decl (parm))
+       {
+         rtx parmreg = gen_reg_rtx (data->nominal_mode);
 
-      /* For values returned in multiple registers, handle possible
-        incompatible calls to emit_group_store.
+         push_to_sequence (all->conversion_insns);
 
-        For example, the following would be invalid, and would have to
-        be fixed by the conditional below:
+         /* For values returned in multiple registers, handle possible
+            incompatible calls to emit_group_store.
 
-          emit_group_store ((reg:SF), (parallel:DF))
-          emit_group_store ((reg:SI), (parallel:DI))
+            For example, the following would be invalid, and would have to
+            be fixed by the conditional below:
 
-        An example of this are doubles in e500 v2:
-          (parallel:DF (expr_list (reg:SI) (const_int 0))
-                       (expr_list (reg:SI) (const_int 4))).  */
-      if (data->nominal_mode != data->passed_mode)
-       {
-         rtx t = gen_reg_rtx (GET_MODE (entry_parm));
-         emit_group_store (t, entry_parm, NULL_TREE,
-                           GET_MODE_SIZE (GET_MODE (entry_parm)));
-         convert_move (parmreg, t, 0);
-       }
-      else
-       emit_group_store (parmreg, entry_parm, data->nominal_type,
-                         int_size_in_bytes (data->nominal_type));
+            emit_group_store ((reg:SF), (parallel:DF))
+            emit_group_store ((reg:SI), (parallel:DI))
 
-      all->conversion_insns = get_insns ();
-      end_sequence ();
+            An example of this are doubles in e500 v2:
+            (parallel:DF (expr_list (reg:SI) (const_int 0))
+            (expr_list (reg:SI) (const_int 4))).  */
+         if (data->nominal_mode != data->passed_mode)
+           {
+             rtx t = gen_reg_rtx (GET_MODE (entry_parm));
+             emit_group_store (t, entry_parm, NULL_TREE,
+                               GET_MODE_SIZE (GET_MODE (entry_parm)));
+             convert_move (parmreg, t, 0);
+           }
+         else
+           emit_group_store (parmreg, entry_parm, data->nominal_type,
+                             int_size_in_bytes (data->nominal_type));
 
-      SET_DECL_RTL (parm, parmreg);
-      return;
+         all->conversion_insns = get_insns ();
+         end_sequence ();
+
+         SET_DECL_RTL (parm, parmreg);
+         return;
+       }
+    }
+
+  size = int_size_in_bytes (data->passed_type);
+  size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
+  if (stack_parm == 0)
+    {
+      DECL_ALIGN (parm) = MAX (DECL_ALIGN (parm), BITS_PER_WORD);
+      stack_parm = assign_stack_local (BLKmode, size_stored,
+                                      DECL_ALIGN (parm));
+      if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size)
+       PUT_MODE (stack_parm, GET_MODE (entry_parm));
+      set_mem_attributes (stack_parm, parm, 1);
     }
 
   /* If a BLKmode arrives in registers, copy it to a stack slot.  Handle
      calls that pass values in multiple non-contiguous locations.  */
   if (REG_P (entry_parm) || GET_CODE (entry_parm) == PARALLEL)
     {
-      HOST_WIDE_INT size = int_size_in_bytes (data->passed_type);
-      HOST_WIDE_INT size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
       rtx mem;
 
       /* Note that we will be storing an integral number of words.
         So we have to be careful to ensure that we allocate an
-        integral number of words.  We do this below in the
+        integral number of words.  We do this above when we call
         assign_stack_local if space was not allocated in the argument
         list.  If it was, this will not work if PARM_BOUNDARY is not
         a multiple of BITS_PER_WORD.  It isn't clear how to fix this
         if it becomes a problem.  Exception is when BLKmode arrives
         with arguments not conforming to word_mode.  */
 
-      if (stack_parm == 0)
-       {
-         stack_parm = assign_stack_local (BLKmode, size_stored, 0);
-         data->stack_parm = stack_parm;
-         PUT_MODE (stack_parm, GET_MODE (entry_parm));
-         set_mem_attributes (stack_parm, parm, 1);
-       }
+      if (data->stack_parm == 0)
+       ;
       else if (GET_CODE (entry_parm) == PARALLEL)
        ;
       else
@@ -2671,7 +2692,16 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
        move_block_from_reg (REGNO (entry_parm), mem,
                             size_stored / UNITS_PER_WORD);
     }
+  else if (data->stack_parm == 0)
+    {
+      push_to_sequence (all->conversion_insns);
+      emit_block_move (stack_parm, data->entry_parm, GEN_INT (size),
+                      BLOCK_OP_NORMAL);
+      all->conversion_insns = get_insns ();
+      end_sequence ();
+    }
 
+  data->stack_parm = stack_parm;
   SET_DECL_RTL (parm, stack_parm);
 }
 
@@ -2804,50 +2834,6 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
       data->stack_parm = NULL;
     }
 
-  /* If we are passed an arg by reference and it is our responsibility
-     to make a copy, do it now.
-     PASSED_TYPE and PASSED mode now refer to the pointer, not the
-     original argument, so we must recreate them in the call to
-     FUNCTION_ARG_CALLEE_COPIES.  */
-  /* ??? Later add code to handle the case that if the argument isn't
-     modified, don't do the copy.  */
-
-  else if (data->passed_pointer)
-    {
-      tree type = TREE_TYPE (data->passed_type);
-    
-      if (reference_callee_copied (&all->args_so_far, TYPE_MODE (type),
-                                  type, data->named_arg))
-       {
-         rtx copy;
-
-         /* This sequence may involve a library call perhaps clobbering
-            registers that haven't been copied to pseudos yet.  */
-
-         push_to_sequence (all->conversion_insns);
-
-         if (!COMPLETE_TYPE_P (type)
-             || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
-           {
-             /* This is a variable sized object.  */
-             copy = allocate_dynamic_stack_space (expr_size (parm), NULL_RTX,
-                                                  TYPE_ALIGN (type));
-             copy = gen_rtx_MEM (BLKmode, copy);
-           }
-         else
-           copy = assign_stack_temp (TYPE_MODE (type),
-                                     int_size_in_bytes (type), 1);
-         set_mem_attributes (copy, parm, 1);
-
-         store_expr (parm, copy, 0);
-         emit_move_insn (parmreg, XEXP (copy, 0));
-         all->conversion_insns = get_insns ();
-         end_sequence ();
-
-         did_conversion = true;
-       }
-    }
-
   /* Mark the register as eliminable if we did no conversion and it was
      copied from memory at a fixed offset, and the arg pointer was not
      copied to a pseudo-reg.  If the arg pointer is a pseudo reg or the
@@ -2916,6 +2902,7 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
 {
   /* Value must be stored in the stack slot STACK_PARM during function
      execution.  */
+  bool to_conversion = false;
 
   if (data->promoted_mode != data->nominal_mode)
     {
@@ -2925,6 +2912,8 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
       emit_move_insn (tempreg, validize_mem (data->entry_parm));
 
       push_to_sequence (all->conversion_insns);
+      to_conversion = true;
+
       data->entry_parm = convert_to_mode (data->nominal_mode, tempreg,
                                          TYPE_UNSIGNED (TREE_TYPE (parm)));
 
@@ -2932,33 +2921,43 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
        /* ??? This may need a big-endian conversion on sparc64.  */
        data->stack_parm
          = adjust_address (data->stack_parm, data->nominal_mode, 0);
-
-      all->conversion_insns = get_insns ();
-      end_sequence ();
     }
 
   if (data->entry_parm != data->stack_parm)
     {
+      rtx src, dest;
+
       if (data->stack_parm == 0)
        {
          data->stack_parm
            = assign_stack_local (GET_MODE (data->entry_parm),
                                  GET_MODE_SIZE (GET_MODE (data->entry_parm)),
-                                 0);
+                                 TYPE_ALIGN (data->passed_type));
          set_mem_attributes (data->stack_parm, parm, 1);
        }
 
-      if (data->promoted_mode != data->nominal_mode)
+      dest = validize_mem (data->stack_parm);
+      src = validize_mem (data->entry_parm);
+
+      if (MEM_P (src))
        {
-         push_to_sequence (all->conversion_insns);
-         emit_move_insn (validize_mem (data->stack_parm),
-                         validize_mem (data->entry_parm));
-         all->conversion_insns = get_insns ();
-         end_sequence ();
+         /* Use a block move to handle potentially misaligned entry_parm.  */
+         if (!to_conversion)
+           push_to_sequence (all->conversion_insns);
+         to_conversion = true;
+
+         emit_block_move (dest, src,
+                          GEN_INT (int_size_in_bytes (data->passed_type)),
+                          BLOCK_OP_NORMAL);
        }
       else
-       emit_move_insn (validize_mem (data->stack_parm),
-                       validize_mem (data->entry_parm));
+       emit_move_insn (dest, src);
+    }
+
+  if (to_conversion)
+    {
+      all->conversion_insns = get_insns ();
+      end_sequence ();
     }
 
   SET_DECL_RTL (parm, data->stack_parm);
@@ -2968,9 +2967,10 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
    undo the frobbing that we did in assign_parms_augmented_arg_list.  */
 
 static void
-assign_parms_unsplit_complex (tree orig_fnargs, tree fnargs)
+assign_parms_unsplit_complex (struct assign_parm_data_all *all, tree fnargs)
 {
   tree parm;
+  tree orig_fnargs = all->orig_fnargs;
 
   for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm))
     {
@@ -2987,7 +2987,27 @@ assign_parms_unsplit_complex (tree orig_fnargs, tree fnargs)
              real = gen_lowpart_SUBREG (inner, real);
              imag = gen_lowpart_SUBREG (inner, imag);
            }
-         tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
+
+         if (TREE_ADDRESSABLE (parm))
+           {
+             rtx rmem, imem;
+             HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (parm));
+
+             /* split_complex_arg put the real and imag parts in
+                pseudos.  Move them to memory.  */
+             tmp = assign_stack_local (DECL_MODE (parm), size,
+                                       TYPE_ALIGN (TREE_TYPE (parm)));
+             set_mem_attributes (tmp, parm, 1);
+             rmem = adjust_address_nv (tmp, inner, 0);
+             imem = adjust_address_nv (tmp, inner, GET_MODE_SIZE (inner));
+             push_to_sequence (all->conversion_insns);
+             emit_move_insn (rmem, real);
+             emit_move_insn (imem, imag);
+             all->conversion_insns = get_insns ();
+             end_sequence ();
+           }
+         else
+           tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
          SET_DECL_RTL (parm, tmp);
 
          real = DECL_INCOMING_RTL (fnargs);
@@ -3025,7 +3045,6 @@ assign_parms (tree fndecl)
   struct assign_parm_data_all all;
   tree fnargs, parm;
   rtx internal_arg_pointer;
-  int varargs_setup = 0;
 
   /* 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
@@ -3060,16 +3079,8 @@ assign_parms (tree fndecl)
          continue;
        }
 
-      /* Handle stdargs.  LAST_NAMED is a slight mis-nomer; it's also true
-        for the unnamed dummy argument following the last named argument.
-        See ABI silliness wrt strict_argument_naming and NAMED_ARG.  So
-        we only want to do this when we get to the actual last named
-        argument, which will be the first time LAST_NAMED gets set.  */
-      if (data.last_named && !varargs_setup)
-       {
-         varargs_setup = true;
-         assign_parms_setup_varargs (&all, &data, false);
-       }
+      if (current_function_stdarg && !TREE_CHAIN (parm))
+       assign_parms_setup_varargs (&all, &data, false);
 
       /* Find out where the parameter arrives in this function.  */
       assign_parm_find_entry_rtl (&all, &data);
@@ -3099,7 +3110,7 @@ assign_parms (tree fndecl)
     }
 
   if (targetm.calls.split_complex_arg && fnargs != all.orig_fnargs)
-    assign_parms_unsplit_complex (all.orig_fnargs, fnargs);
+    assign_parms_unsplit_complex (&all, fnargs);
 
   /* Output all parameter conversion instructions (possibly including calls)
      now that all parameters have been copied out of hard registers.  */
@@ -3202,6 +3213,116 @@ assign_parms (tree fndecl)
        }
     }
 }
+
+/* A subroutine of gimplify_parameters, invoked via walk_tree.
+   For all seen types, gimplify their sizes.  */
+
+static tree
+gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
+{
+  tree t = *tp;
+
+  *walk_subtrees = 0;
+  if (TYPE_P (t))
+    {
+      if (POINTER_TYPE_P (t))
+       *walk_subtrees = 1;
+      else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
+              && !TYPE_SIZES_GIMPLIFIED (t))
+       {
+         gimplify_type_sizes (t, (tree *) data);
+         *walk_subtrees = 1;
+       }
+    }
+
+  return NULL;
+}
+
+/* Gimplify the parameter list for current_function_decl.  This involves
+   evaluating SAVE_EXPRs of variable sized parameters and generating code
+   to implement callee-copies reference parameters.  Returns a list of
+   statements to add to the beginning of the function, or NULL if nothing
+   to do.  */
+
+tree
+gimplify_parameters (void)
+{
+  struct assign_parm_data_all all;
+  tree fnargs, parm, stmts = NULL;
+
+  assign_parms_initialize_all (&all);
+  fnargs = assign_parms_augmented_arg_list (&all);
+
+  for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
+    {
+      struct assign_parm_data_one data;
+
+      /* Extract the type of PARM; adjust it according to ABI.  */
+      assign_parm_find_data_types (&all, parm, &data);
+
+      /* Early out for errors and void parameters.  */
+      if (data.passed_mode == VOIDmode || DECL_SIZE (parm) == NULL)
+       continue;
+
+      /* Update info on where next arg arrives in registers.  */
+      FUNCTION_ARG_ADVANCE (all.args_so_far, data.promoted_mode,
+                           data.passed_type, data.named_arg);
+
+      /* ??? Once upon a time variable_size stuffed parameter list
+        SAVE_EXPRs (amongst others) onto a pending sizes list.  This
+        turned out to be less than manageable in the gimple world.
+        Now we have to hunt them down ourselves.  */
+      walk_tree_without_duplicates (&data.passed_type,
+                                   gimplify_parm_type, &stmts);
+
+      if (!TREE_CONSTANT (DECL_SIZE (parm)))
+       {
+         gimplify_one_sizepos (&DECL_SIZE (parm), &stmts);
+         gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), &stmts);
+       }
+
+      if (data.passed_pointer)
+       {
+          tree type = TREE_TYPE (data.passed_type);
+         if (reference_callee_copied (&all.args_so_far, TYPE_MODE (type),
+                                      type, data.named_arg))
+           {
+             tree local, t;
+
+             /* For constant sized objects, this is trivial; for
+                variable-sized objects, we have to play games.  */
+             if (TREE_CONSTANT (DECL_SIZE (parm)))
+               {
+                 local = create_tmp_var (type, get_name (parm));
+                 DECL_IGNORED_P (local) = 0;
+               }
+             else
+               {
+                 tree ptr_type, addr, args;
+
+                 ptr_type = build_pointer_type (type);
+                 addr = create_tmp_var (ptr_type, get_name (parm));
+                 DECL_IGNORED_P (addr) = 0;
+                 local = build_fold_indirect_ref (addr);
+
+                 args = tree_cons (NULL, DECL_SIZE_UNIT (parm), NULL);
+                 t = built_in_decls[BUILT_IN_ALLOCA];
+                 t = build_function_call_expr (t, args);
+                 t = fold_convert (ptr_type, t);
+                 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
+                 gimplify_and_add (t, &stmts);
+               }
+
+             t = build2 (MODIFY_EXPR, void_type_node, local, parm);
+             gimplify_and_add (t, &stmts);
+
+             DECL_VALUE_EXPR (parm) = local;
+           }
+       }
+    }
+
+  return stmts;
+}
 \f
 /* Indicate whether REGNO is an incoming argument to the current function
    that was promoted to a wider mode.  If so, return the RTX for the
@@ -3303,17 +3424,14 @@ locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs,
     }
 #endif /* REG_PARM_STACK_SPACE */
 
-  part_size_in_regs = 0;
-  if (reg_parm_stack_space == 0)
-    part_size_in_regs = ((partial * UNITS_PER_WORD)
-                        / (PARM_BOUNDARY / BITS_PER_UNIT)
-                        * (PARM_BOUNDARY / BITS_PER_UNIT));
+  part_size_in_regs = (reg_parm_stack_space == 0 ? partial : 0);
 
   sizetree
     = 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;
+  locate->boundary = boundary;
 
 #ifdef ARGS_GROW_DOWNWARD
   locate->slot_offset.constant = -initial_offset_ptr->constant;
@@ -3972,22 +4090,6 @@ expand_main_function (void)
 #endif
 }
 \f
-/* The PENDING_SIZES represent the sizes of variable-sized types.
-   Create RTL for the various sizes now (using temporary variables),
-   so that we can refer to the sizes from the RTL we are generating
-   for the current function.  The PENDING_SIZES are a TREE_LIST.  The
-   TREE_VALUE of each node is a SAVE_EXPR.  */
-
-static void
-expand_pending_sizes (tree pending_sizes)
-{
-  tree tem;
-
-  /* Evaluate now the sizes of any types declared among the arguments.  */
-  for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem))
-    expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
-}
-
 /* Start the RTL for a new function, and set variables used for
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
@@ -4152,9 +4254,6 @@ expand_function_start (tree subr)
      since some things (like trampolines) get placed before this.  */
   tail_recursion_reentry = emit_note (NOTE_INSN_DELETED);
 
-  /* Evaluate now the sizes of any types declared among the arguments.  */
-  expand_pending_sizes (nreverse (get_pending_sizes ()));
-
   /* Make sure there is a line number after the function entry setup code.  */
   force_next_line_note ();
 }
@@ -4342,18 +4441,6 @@ expand_function_end (void)
   if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
     sjlj_emit_function_exit_after (get_last_insn ());
 
-  /* If we had calls to alloca, and this machine needs
-     an accurate stack pointer to exit the function,
-     insert some code to save and restore the stack pointer.  */
-  if (! EXIT_IGNORE_STACK
-      && current_function_calls_alloca)
-    {
-      rtx tem = 0;
-
-      emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
-      emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
-    }
-
   /* If scalar return value was computed in a pseudo-reg, or was a named
      return value that got dumped to the stack, copy that to the hard
      return register.  */
@@ -4481,6 +4568,18 @@ expand_function_end (void)
   /* Output the label for the naked return from the function.  */
   emit_label (naked_return_label);
 
+  /* If we had calls to alloca, and this machine needs
+     an accurate stack pointer to exit the function,
+     insert some code to save and restore the stack pointer.  */
+  if (! EXIT_IGNORE_STACK
+      && current_function_calls_alloca)
+    {
+      rtx tem = 0;
+
+      emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
+      emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
+    }
+
   /* ??? This should no longer be necessary since stupid is no longer with
      us, but there are some parts of the compiler (eg reload_combine, and
      sh mach_dep_reorg) that still try and compute their own lifetime info
@@ -4512,7 +4611,7 @@ get_arg_pointer_save_area (struct function *f)
       end_sequence ();
 
       push_topmost_sequence ();
-      emit_insn_after (seq, get_insns ());
+      emit_insn_after (seq, entry_of_function ());
       pop_topmost_sequence ();
     }
 
@@ -5031,9 +5130,9 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
       /* Can't deal with multiple successors of the entry block
          at the moment.  Function should always have at least one
          entry point.  */
-      gcc_assert (EDGE_COUNT (ENTRY_BLOCK_PTR->succs) == 1);
+      gcc_assert (single_succ_p (ENTRY_BLOCK_PTR));
 
-      insert_insn_on_edge (seq, EDGE_SUCC (ENTRY_BLOCK_PTR, 0));
+      insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
       inserted = 1;
     }
 #endif
@@ -5129,7 +5228,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
                  /* If this block has only one successor, it both jumps
                     and falls through to the fallthru block, so we can't
                     delete the edge.  */
-                 if (EDGE_COUNT (bb->succs) == 1)
+                 if (single_succ_p (bb))
                    {
                      ei_next (&ei2);
                      continue;
@@ -5151,7 +5250,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
          emit_barrier_after (BB_END (last));
          emit_return_into_block (last, epilogue_line_note);
          epilogue_end = BB_END (last);
-         EDGE_SUCC (last, 0)->flags &= ~EDGE_FALLTHRU;
+         single_succ_edge (last)->flags &= ~EDGE_FALLTHRU;
          goto epilogue_done;
        }
     }
@@ -5226,8 +5325,6 @@ epilogue_done:
     {
       basic_block bb = e->src;
       rtx insn = BB_END (bb);
-      rtx i;
-      rtx newinsn;
 
       if (!CALL_P (insn)
          || ! SIBLING_CALL_P (insn))
@@ -5247,8 +5344,7 @@ epilogue_done:
       record_insns (seq, &sibcall_epilogue);
       set_insn_locators (seq, epilogue_locator);
 
-      i = PREV_INSN (insn);
-      newinsn = emit_insn_before (seq, insn);
+      emit_insn_before (seq, insn);
       ei_next (&ei);
     }
 #endif