OSDN Git Service

* c-decl.c (store_parm_decls_oldstyle): Let diagnostic machinery
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 19549b1..065c124 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
@@ -87,16 +89,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    alignment.  */
 #define CEIL_ROUND(VALUE,ALIGN)        (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
 
-/* NEED_SEPARATE_AP means that we cannot derive ap from the value of fp
-   during rtl generation.  If they are different register numbers, this is
-   always true.  It may also be true if
-   FIRST_PARM_OFFSET - STARTING_FRAME_OFFSET is not a constant during rtl
-   generation.  See fix_lexical_addr for details.  */
-
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
-#define NEED_SEPARATE_AP
-#endif
-
 /* Nonzero if function being compiled doesn't contain any calls
    (ignoring the prologue and epilogue).  This is set prior to
    local register allocation and is valid for the remaining
@@ -197,14 +189,9 @@ struct temp_slot GTY(())
 static rtx assign_stack_local_1 (enum machine_mode, HOST_WIDE_INT, int,
                                 struct function *);
 static struct temp_slot *find_temp_slot_from_address (rtx);
-static void instantiate_decls (tree, int);
-static void instantiate_decls_1 (tree, int);
-static void instantiate_decl (rtx, HOST_WIDE_INT, int);
-static rtx instantiate_new_reg (rtx, HOST_WIDE_INT *);
-static int instantiate_virtual_regs_1 (rtx *, rtx, int);
 static void pad_to_arg_alignment (struct args_size *, int, struct args_size *);
 static void pad_below (struct args_size *, enum machine_mode, tree);
-static void reorder_blocks_1 (rtx, tree, varray_type *);
+static void reorder_blocks_1 (rtx, tree, VEC(tree,heap) **);
 static void reorder_fix_fragments (tree);
 static int all_blocks (tree, tree *);
 static tree *get_block_vector (tree, int *);
@@ -216,14 +203,12 @@ static int contains (rtx, varray_type);
 #ifdef HAVE_return
 static void emit_return_into_block (basic_block, rtx);
 #endif
-static void purge_single_hard_subreg_set (rtx);
 #if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
 static rtx keep_stack_depressed (rtx);
 #endif
 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);
 static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED;
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
@@ -241,7 +226,7 @@ find_function_data (tree decl)
     if (p->decl == decl)
       return p;
 
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Save the current context for compilation of a nested function.
@@ -251,21 +236,10 @@ find_function_data (tree decl)
    variables.  */
 
 void
-push_function_context_to (tree context)
+push_function_context_to (tree context ATTRIBUTE_UNUSED)
 {
   struct function *p;
 
-  if (context)
-    {
-      if (context == current_function_decl)
-       cfun->contains_functions = 1;
-      else
-       {
-         struct function *containing = find_function_data (context);
-         containing->contains_functions = 1;
-       }
-    }
-
   if (cfun == 0)
     init_dummy_function_start ();
   p = cfun;
@@ -296,14 +270,10 @@ pop_function_context_from (tree context ATTRIBUTE_UNUSED)
   outer_function_chain = p->outer;
 
   current_function_decl = p->decl;
-  reg_renumber = 0;
-
-  restore_emit_status (p);
 
   lang_hooks.function.leave_nested (p);
 
   /* Reset variables that have known state during rtx generation.  */
-  rtx_equal_function_value_matters = 1;
   virtuals_instantiated = 0;
   generating_concat_p = 1;
 }
@@ -327,7 +297,6 @@ free_after_parsing (struct function *f)
   /* f->eh->eh_return_stub_label is used by code generation.  */
 
   lang_hooks.function.final (f);
-  f->stmt = NULL;
 }
 
 /* Clear out all parts of the state in F that can safely be discarded
@@ -342,6 +311,7 @@ free_after_compilation (struct function *f)
   f->emit = NULL;
   f->varasm = NULL;
   f->machine = NULL;
+  f->cfg = NULL;
 
   f->x_avail_temp_slots = NULL;
   f->x_used_temp_slots = NULL;
@@ -367,7 +337,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
@@ -405,7 +375,7 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align,
 {
   rtx x, addr;
   int bigend_correction = 0;
-  int alignment;
+  unsigned int alignment;
   int frame_off, frame_alignment, frame_phase;
 
   if (align == 0)
@@ -465,11 +435,13 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align,
          use logical operations which are unambiguous.  */
 #ifdef FRAME_GROWS_DOWNWARD
       function->x_frame_offset
-       = (FLOOR_ROUND (function->x_frame_offset - frame_phase, alignment)
+       = (FLOOR_ROUND (function->x_frame_offset - frame_phase,
+                       (unsigned HOST_WIDE_INT) alignment)
           + frame_phase);
 #else
       function->x_frame_offset
-       = (CEIL_ROUND (function->x_frame_offset - frame_phase, alignment)
+       = (CEIL_ROUND (function->x_frame_offset - frame_phase,
+                      (unsigned HOST_WIDE_INT) alignment)
           + frame_phase);
 #endif
     }
@@ -546,7 +518,6 @@ insert_slot_to_list (struct temp_slot *temp, struct temp_slot **list)
 static struct temp_slot **
 temp_slots_at_level (int level)
 {
-  level++;
 
   if (!used_temp_slots)
     VARRAY_GENERIC_PTR_INIT (used_temp_slots, 3, "used_temp_slots");
@@ -599,16 +570,15 @@ make_slot_available (struct temp_slot *temp)
 
    KEEP is 1 if this slot is to be retained after a call to
    free_temp_slots.  Automatic variables for a block are allocated
-   with this flag.  KEEP is 2 if we allocate a longer term temporary,
-   whose lifetime is controlled by CLEANUP_POINT_EXPRs.  KEEP is 3
-   if we are to allocate something at an inner level to be treated as
-   a variable in the block (e.g., a SAVE_EXPR).
+   with this flag.  KEEP values of 2 or 3 were needed respectively
+   for variables whose lifetime is controlled by CLEANUP_POINT_EXPRs
+   or for SAVE_EXPRs, but they are now unused.
 
    TYPE is the type that will be used for the stack slot.  */
 
 rtx
-assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep,
-                           tree type)
+assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size,
+                           int keep, tree type)
 {
   unsigned int align;
   struct temp_slot *p, *best_p = 0, *selected = NULL, **pp;
@@ -616,8 +586,10 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
 
   /* If SIZE is -1 it means that somebody tried to allocate a temporary
      of a variable size.  */
-  if (size == -1)
-    abort ();
+  gcc_assert (size != -1);
+
+  /* These are now unused.  */
+  gcc_assert (keep <= 1);
 
   if (mode == BLKmode)
     align = BIGGEST_ALIGNMENT;
@@ -703,8 +675,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
         So for requests which depended on the rounding of SIZE, we go ahead
         and round it now.  We also make sure ALIGNMENT is at least
         BIGGEST_ALIGNMENT.  */
-      if (mode == BLKmode && align < BIGGEST_ALIGNMENT)
-       abort ();
+      gcc_assert (mode != BLKmode || align == BIGGEST_ALIGNMENT);
       p->slot = assign_stack_local (mode,
                                    (mode == BLKmode
                                     ? CEIL_ROUND (size, (int) align / BITS_PER_UNIT)
@@ -743,22 +714,8 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
   p->in_use = 1;
   p->addr_taken = 0;
   p->type = type;
-
-  if (keep == 2)
-    {
-      p->level = target_temp_slot_level;
-      p->keep = 1;
-    }
-  else if (keep == 3)
-    {
-      p->level = var_temp_slot_level;
-      p->keep = 0;
-    }
-  else
-    {
-      p->level = temp_slot_level;
-      p->keep = keep;
-    }
+  p->level = temp_slot_level;
+  p->keep = keep;
 
   pp = temp_slots_at_level (p->level);
   insert_slot_to_list (p, pp);
@@ -776,8 +733,6 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
   /* If a type is specified, set the relevant flags.  */
   if (type != 0)
     {
-      RTX_UNCHANGING_P (slot) = (lang_hooks.honor_readonly
-                                && TYPE_READONLY (type));
       MEM_VOLATILE_P (slot) = TYPE_VOLATILE (type);
       MEM_SET_IN_STRUCT_P (slot, AGGREGATE_TYPE_P (type));
     }
@@ -854,11 +809,11 @@ assign_temp (tree type_or_decl, int keep, int memory_required,
       /* The size of the temporary may be too large to fit into an integer.  */
       /* ??? Not sure this should happen except for user silliness, so limit
         this to things that aren't compiler-generated temporaries.  The
-        rest of the time we'll abort in assign_stack_temp_for_type.  */
+        rest of the time we'll die in assign_stack_temp_for_type.  */
       if (decl && size == -1
          && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST)
        {
-         error ("%Jsize of variable '%D' is too large", decl, decl);
+         error ("%Jsize of variable %qD is too large", decl, decl);
          size = 1;
        }
 
@@ -880,7 +835,7 @@ assign_temp (tree type_or_decl, int keep, int memory_required,
    done for BLKmode slots because we can be sure that we won't have alignment
    problems in this case.  */
 
-void
+static void
 combine_temp_slots (void)
 {
   struct temp_slot *p, *q, *next, *next_q;
@@ -1200,8 +1155,6 @@ init_temp_slots (void)
   avail_temp_slots = 0;
   used_temp_slots = 0;
   temp_slot_level = 0;
-  var_temp_slot_level = 0;
-  target_temp_slot_level = 0;
 }
 \f
 /* These routines are responsible for converting virtual register references
@@ -1258,671 +1211,446 @@ static int cfa_offset;
 #endif
 
 \f
-/* Convert a SET of a hard subreg to a set of the appropriate hard
-   register.  A subroutine of purge_hard_subreg_sets.  */
+/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
+   is a virtual register, return the equivalent hard register and set the
+   offset indirectly through the pointer.  Otherwise, return 0.  */
 
-static void
-purge_single_hard_subreg_set (rtx pattern)
+static rtx
+instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
 {
-  rtx reg = SET_DEST (pattern);
-  enum machine_mode mode = GET_MODE (SET_DEST (pattern));
-  int offset = 0;
-
-  if (GET_CODE (reg) == SUBREG && REG_P (SUBREG_REG (reg))
-      && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
-    {
-      offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
-                                   GET_MODE (SUBREG_REG (reg)),
-                                   SUBREG_BYTE (reg),
-                                   GET_MODE (reg));
-      reg = SUBREG_REG (reg);
-    }
+  rtx new;
+  HOST_WIDE_INT offset;
 
+  if (x == virtual_incoming_args_rtx)
+    new = arg_pointer_rtx, offset = in_arg_offset;
+  else if (x == virtual_stack_vars_rtx)
+    new = frame_pointer_rtx, offset = var_offset;
+  else if (x == virtual_stack_dynamic_rtx)
+    new = stack_pointer_rtx, offset = dynamic_offset;
+  else if (x == virtual_outgoing_args_rtx)
+    new = stack_pointer_rtx, offset = out_arg_offset;
+  else if (x == virtual_cfa_rtx)
+    new = arg_pointer_rtx, offset = cfa_offset;
+  else
+    return NULL_RTX;
 
-  if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)
-    {
-      reg = gen_rtx_REG (mode, REGNO (reg) + offset);
-      SET_DEST (pattern) = reg;
-    }
+  *poffset = offset;
+  return new;
 }
 
-/* Eliminate all occurrences of SETs of hard subregs from INSNS.  The
-   only such SETs that we expect to see are those left in because
-   integrate can't handle sets of parts of a return value register.
-
-   We don't use alter_subreg because we only want to eliminate subregs
-   of hard registers.  */
+/* A subroutine of instantiate_virtual_regs, called via for_each_rtx.
+   Instantiate any virtual registers present inside of *LOC.  The expression
+   is simplified, as much as possible, but is not to be considered "valid"
+   in any sense implied by the target.  If any change is made, set CHANGED
+   to true.  */
 
-void
-purge_hard_subreg_sets (rtx insn)
+static int
+instantiate_virtual_regs_in_rtx (rtx *loc, void *data)
 {
-  for (; insn; insn = NEXT_INSN (insn))
+  HOST_WIDE_INT offset;
+  bool *changed = (bool *) data;
+  rtx x, new;
+
+  x = *loc;
+  if (x == 0)
+    return 0;
+
+  switch (GET_CODE (x))
     {
-      if (INSN_P (insn))
+    case REG:
+      new = instantiate_new_reg (x, &offset);
+      if (new)
        {
-         rtx pattern = PATTERN (insn);
-         switch (GET_CODE (pattern))
-           {
-           case SET:
-             if (GET_CODE (SET_DEST (pattern)) == SUBREG)
-               purge_single_hard_subreg_set (pattern);
-             break;
-           case PARALLEL:
-             {
-               int j;
-               for (j = XVECLEN (pattern, 0) - 1; j >= 0; j--)
-                 {
-                   rtx inner_pattern = XVECEXP (pattern, 0, j);
-                   if (GET_CODE (inner_pattern) == SET
-                       && GET_CODE (SET_DEST (inner_pattern)) == SUBREG)
-                     purge_single_hard_subreg_set (inner_pattern);
-                 }
-             }
-             break;
-           default:
-             break;
-           }
+         *loc = plus_constant (new, offset);
+         if (changed)
+           *changed = true;
        }
-    }
-}
-\f
-/* Pass through the INSNS of function FNDECL and convert virtual register
-   references to hard register references.  */
+      return -1;
 
-void
-instantiate_virtual_regs (void)
-{
-  rtx insn;
+    case PLUS:
+      new = instantiate_new_reg (XEXP (x, 0), &offset);
+      if (new)
+       {
+         new = plus_constant (new, offset);
+         *loc = simplify_gen_binary (PLUS, GET_MODE (x), new, XEXP (x, 1));
+         if (changed)
+           *changed = true;
+         return -1;
+       }
 
-  /* Compute the offsets to use for this function.  */
-  in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
-  var_offset = STARTING_FRAME_OFFSET;
-  dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
-  out_arg_offset = STACK_POINTER_OFFSET;
-  cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
+      /* FIXME -- from old code */
+         /* If we have (plus (subreg (virtual-reg)) (const_int)), we know
+            we can commute the PLUS and SUBREG because pointers into the
+            frame are well-behaved.  */
+      break;
 
-  /* Scan all variables and parameters of this function.  For each that is
-     in memory, instantiate all virtual registers if the result is a valid
-     address.  If not, we do it later.  That will handle most uses of virtual
-     regs on many machines.  */
-  instantiate_decls (current_function_decl, 1);
+    default:
+      break;
+    }
 
-  /* Initialize recognition, indicating that volatile is OK.  */
-  init_recog ();
+  return 0;
+}
 
-  /* Scan through all the insns, instantiating every virtual register still
-     present.  */
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
-       || GET_CODE (insn) == CALL_INSN)
-      {
-       instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1);
-       if (INSN_DELETED_P (insn))
-         continue;
-       instantiate_virtual_regs_1 (&REG_NOTES (insn), NULL_RTX, 0);
-       /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE.  */
-       if (GET_CODE (insn) == CALL_INSN)
-         instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn),
-                                     NULL_RTX, 0);
-
-       /* Past this point all ASM statements should match.  Verify that
-          to avoid failures later in the compilation process.  */
-        if (asm_noperands (PATTERN (insn)) >= 0
-           && ! check_asm_operands (PATTERN (insn)))
-          instantiate_virtual_regs_lossage (insn);
-      }
+/* A subroutine of instantiate_virtual_regs_in_insn.  Return true if X
+   matches the predicate for insn CODE operand OPERAND.  */
+
+static int
+safe_insn_predicate (int code, int operand, rtx x)
+{
+  const struct insn_operand_data *op_data;
 
-  /* Now instantiate the remaining register equivalences for debugging info.
-     These will not be valid addresses.  */
-  instantiate_decls (current_function_decl, 0);
+  if (code < 0)
+    return true;
 
-  /* Indicate that, from now on, assign_stack_local should use
-     frame_pointer_rtx.  */
-  virtuals_instantiated = 1;
-}
+  op_data = &insn_data[code].operand[operand];
+  if (op_data->predicate == NULL)
+    return true;
 
-/* Scan all decls in FNDECL (both variables and parameters) and instantiate
-   all virtual registers in their DECL_RTL's.
+  return op_data->predicate (x, op_data->mode);
+}
 
-   If VALID_ONLY, do this only if the resulting address is still valid.
-   Otherwise, always do it.  */
+/* A subroutine of instantiate_virtual_regs.  Instantiate any virtual
+   registers present inside of insn.  The result will be a valid insn.  */
 
 static void
-instantiate_decls (tree fndecl, int valid_only)
+instantiate_virtual_regs_in_insn (rtx insn)
 {
-  tree decl;
+  HOST_WIDE_INT offset;
+  int insn_code, i;
+  bool any_change;
+  rtx set, new, x, seq;
 
-  /* Process all parameters of the function.  */
-  for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
+  /* There are some special cases to be handled first.  */
+  set = single_set (insn);
+  if (set)
     {
-      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
-      HOST_WIDE_INT size_rtl;
+      /* We're allowed to assign to a virtual register.  This is interpreted
+        to mean that the underlying register gets assigned the inverse
+        transformation.  This is used, for example, in the handling of
+        non-local gotos.  */
+      new = instantiate_new_reg (SET_DEST (set), &offset);
+      if (new)
+       {
+         start_sequence ();
 
-      instantiate_decl (DECL_RTL (decl), size, valid_only);
+         for_each_rtx (&SET_SRC (set), instantiate_virtual_regs_in_rtx, NULL);
+         x = simplify_gen_binary (PLUS, GET_MODE (new), SET_SRC (set),
+                                  GEN_INT (-offset));
+         x = force_operand (x, new);
+         if (x != new)
+           emit_move_insn (new, x);
 
-      /* If the parameter was promoted, then the incoming RTL mode may be
-        larger than the declared type size.  We must use the larger of
-        the two sizes.  */
-      size_rtl = GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl)));
-      size = MAX (size_rtl, size);
-      instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
-    }
+         seq = get_insns ();
+         end_sequence ();
 
-  /* Now process all variables defined in the function or its subblocks.  */
-  instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
-}
+         emit_insn_before (seq, insn);
+         delete_insn (insn);
+         return;
+       }
 
-/* Subroutine of instantiate_decls: Process all decls in the given
-   BLOCK node and all its subblocks.  */
+      /* Handle a straight copy from a virtual register by generating a
+        new add insn.  The difference between this and falling through
+        to the generic case is avoiding a new pseudo and eliminating a
+        move insn in the initial rtl stream.  */
+      new = instantiate_new_reg (SET_SRC (set), &offset);
+      if (new && offset != 0
+         && REG_P (SET_DEST (set))
+         && REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER)
+       {
+         start_sequence ();
 
-static void
-instantiate_decls_1 (tree let, int valid_only)
-{
-  tree t;
+         x = expand_simple_binop (GET_MODE (SET_DEST (set)), PLUS,
+                                  new, GEN_INT (offset), SET_DEST (set),
+                                  1, OPTAB_LIB_WIDEN);
+         if (x != SET_DEST (set))
+           emit_move_insn (SET_DEST (set), x);
 
-  for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
-    if (DECL_RTL_SET_P (t))
-      instantiate_decl (DECL_RTL (t),
-                       int_size_in_bytes (TREE_TYPE (t)),
-                       valid_only);
+         seq = get_insns ();
+         end_sequence ();
 
-  /* Process all subblocks.  */
-  for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
-    instantiate_decls_1 (t, valid_only);
-}
+         emit_insn_before (seq, insn);
+         delete_insn (insn);
+         return;
+       }
 
-/* Subroutine of the preceding procedures: Given RTL representing a
-   decl and the size of the object, do any instantiation required.
+      extract_insn (insn);
 
-   If VALID_ONLY is nonzero, it means that the RTL should only be
-   changed if the new address is valid.  */
+      /* Handle a plus involving a virtual register by determining if the
+        operands remain valid if they're modified in place.  */
+      if (GET_CODE (SET_SRC (set)) == PLUS
+         && recog_data.n_operands >= 3
+         && recog_data.operand_loc[1] == &XEXP (SET_SRC (set), 0)
+         && recog_data.operand_loc[2] == &XEXP (SET_SRC (set), 1)
+         && GET_CODE (recog_data.operand[2]) == CONST_INT
+         && (new = instantiate_new_reg (recog_data.operand[1], &offset)))
+       {
+         offset += INTVAL (recog_data.operand[2]);
 
-static void
-instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only)
-{
-  enum machine_mode mode;
-  rtx addr;
+         /* If the sum is zero, then replace with a plain move.  */
+         if (offset == 0)
+           {
+             start_sequence ();
+             emit_move_insn (SET_DEST (set), new);
+             seq = get_insns ();
+             end_sequence ();
 
-  /* If this is not a MEM, no need to do anything.  Similarly if the
-     address is a constant or a register that is not a virtual register.  */
+             emit_insn_before (seq, insn);
+             delete_insn (insn);
+             return;
+           }
 
-  if (x == 0 || !MEM_P (x))
-    return;
+         x = gen_int_mode (offset, recog_data.operand_mode[2]);
+         insn_code = INSN_CODE (insn);
 
-  addr = XEXP (x, 0);
-  if (CONSTANT_P (addr)
-      || (REG_P (addr)
-         && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
-             || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
-    return;
+         /* Using validate_change and apply_change_group here leaves
+            recog_data in an invalid state.  Since we know exactly what
+            we want to check, do those two by hand.  */
+         if (safe_insn_predicate (insn_code, 1, new)
+             && safe_insn_predicate (insn_code, 2, x))
+           {
+             *recog_data.operand_loc[1] = recog_data.operand[1] = new;
+             *recog_data.operand_loc[2] = recog_data.operand[2] = x;
+             any_change = true;
+             goto verify;
+           }
+       }
+    }
+  else
+    extract_insn (insn);
 
-  /* If we should only do this if the address is valid, copy the address.
-     We need to do this so we can undo any changes that might make the
-     address invalid.  This copy is unfortunate, but probably can't be
-     avoided.  */
+  insn_code = INSN_CODE (insn);
+  any_change = false;
 
-  if (valid_only)
-    addr = copy_rtx (addr);
+  /* In the general case, we expect virtual registers to appear only in
+     operands, and then only as either bare registers or inside memories.  */
+  for (i = 0; i < recog_data.n_operands; ++i)
+    {
+      x = recog_data.operand[i];
+      switch (GET_CODE (x))
+       {
+       case MEM:
+         {
+           rtx addr = XEXP (x, 0);
+           bool changed = false;
 
-  instantiate_virtual_regs_1 (&addr, NULL_RTX, 0);
+           for_each_rtx (&addr, instantiate_virtual_regs_in_rtx, &changed);
+           if (!changed)
+             continue;
 
-  if (valid_only && size >= 0)
-    {
-      unsigned HOST_WIDE_INT decl_size = size;
+           start_sequence ();
+           x = replace_equiv_address (x, addr);
+           seq = get_insns ();
+           end_sequence ();
+           if (seq)
+             emit_insn_before (seq, insn);
+         }
+         break;
 
-      /* Now verify that the resulting address is valid for every integer or
-        floating-point mode up to and including SIZE bytes long.  We do this
-        since the object might be accessed in any mode and frame addresses
-        are shared.  */
+       case REG:
+         new = instantiate_new_reg (x, &offset);
+         if (new == NULL)
+           continue;
+         if (offset == 0)
+           x = new;
+         else
+           {
+             start_sequence ();
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
-          mode = GET_MODE_WIDER_MODE (mode))
-       if (! memory_address_p (mode, addr))
-         return;
+             /* Careful, special mode predicates may have stuff in
+                insn_data[insn_code].operand[i].mode that isn't useful
+                to us for computing a new value.  */
+             /* ??? Recognize address_operand and/or "p" constraints
+                to see if (plus new offset) is a valid before we put
+                this through expand_simple_binop.  */
+             x = expand_simple_binop (GET_MODE (x), PLUS, new,
+                                      GEN_INT (offset), NULL_RTX,
+                                      1, OPTAB_LIB_WIDEN);
+             seq = get_insns ();
+             end_sequence ();
+             emit_insn_before (seq, insn);
+           }
+         break;
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
-          mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
-          mode = GET_MODE_WIDER_MODE (mode))
-       if (! memory_address_p (mode, addr))
-         return;
-    }
+       case SUBREG:
+         new = instantiate_new_reg (SUBREG_REG (x), &offset);
+         if (new == NULL)
+           continue;
+         if (offset != 0)
+           {
+             start_sequence ();
+             new = expand_simple_binop (GET_MODE (new), PLUS, new,
+                                        GEN_INT (offset), NULL_RTX,
+                                        1, OPTAB_LIB_WIDEN);
+             seq = get_insns ();
+             end_sequence ();
+             emit_insn_before (seq, insn);
+           }
+         x = simplify_gen_subreg (insn_data[insn_code].operand[i].mode,
+                                  new, GET_MODE (new), SUBREG_BYTE (x));
+         break;
 
-  /* Put back the address now that we have updated it and we either know
-     it is valid or we don't care whether it is valid.  */
+       default:
+         continue;
+       }
 
-  XEXP (x, 0) = addr;
-}
-\f
-/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
-   is a virtual register, return the equivalent hard register and set the
-   offset indirectly through the pointer.  Otherwise, return 0.  */
+      /* At this point, X contains the new value for the operand.
+        Validate the new value vs the insn predicate.  Note that
+        asm insns will have insn_code -1 here.  */
+      if (!safe_insn_predicate (insn_code, i, x))
+       x = force_reg (insn_data[insn_code].operand[i].mode, x);
 
-static rtx
-instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
-{
-  rtx new;
-  HOST_WIDE_INT offset;
+      *recog_data.operand_loc[i] = recog_data.operand[i] = x;
+      any_change = true;
+    }
 
-  if (x == virtual_incoming_args_rtx)
-    new = arg_pointer_rtx, offset = in_arg_offset;
-  else if (x == virtual_stack_vars_rtx)
-    new = frame_pointer_rtx, offset = var_offset;
-  else if (x == virtual_stack_dynamic_rtx)
-    new = stack_pointer_rtx, offset = dynamic_offset;
-  else if (x == virtual_outgoing_args_rtx)
-    new = stack_pointer_rtx, offset = out_arg_offset;
-  else if (x == virtual_cfa_rtx)
-    new = arg_pointer_rtx, offset = cfa_offset;
-  else
-    return 0;
+ verify:
+  if (any_change)
+    {
+      /* Propagate operand changes into the duplicates.  */
+      for (i = 0; i < recog_data.n_dups; ++i)
+       *recog_data.dup_loc[i]
+         = recog_data.operand[(unsigned)recog_data.dup_num[i]];
 
-  *poffset = offset;
-  return new;
-}
-\f
+      /* Force re-recognition of the instruction for validation.  */
+      INSN_CODE (insn) = -1;
+    }
 
-/* Called when instantiate_virtual_regs has failed to update the instruction.
-   Usually this means that non-matching instruction has been emit, however for
-   asm statements it may be the problem in the constraints.  */
-static void
-instantiate_virtual_regs_lossage (rtx insn)
-{
   if (asm_noperands (PATTERN (insn)) >= 0)
     {
-      error_for_asm (insn, "impossible constraint in `asm'");
-      delete_insn (insn);
+      if (!check_asm_operands (PATTERN (insn)))
+       {
+         error_for_asm (insn, "impossible constraint in %<asm%>");
+         delete_insn (insn);
+       }
     }
   else
-    abort ();
+    {
+      if (recog_memoized (insn) < 0)
+       fatal_insn_not_found (insn);
+    }
 }
-/* Given a pointer to a piece of rtx and an optional pointer to the
-   containing object, instantiate any virtual registers present in it.
-
-   If EXTRA_INSNS, we always do the replacement and generate
-   any extra insns before OBJECT.  If it zero, we do nothing if replacement
-   is not valid.
 
-   Return 1 if we either had nothing to do or if we were able to do the
-   needed replacement.  Return 0 otherwise; we only return zero if
-   EXTRA_INSNS is zero.
+/* Subroutine of instantiate_decls.  Given RTL representing a decl,
+   do any instantiation required.  */
 
-   We first try some simple transformations to avoid the creation of extra
-   pseudos.  */
-
-static int
-instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
+static void
+instantiate_decl (rtx x)
 {
-  rtx x;
-  RTX_CODE code;
-  rtx new = 0;
-  HOST_WIDE_INT offset = 0;
-  rtx temp;
-  rtx seq;
-  int i, j;
-  const char *fmt;
-
-  /* Re-start here to avoid recursion in common cases.  */
- restart:
+  rtx addr;
 
-  x = *loc;
   if (x == 0)
-    return 1;
-
-  /* We may have detected and deleted invalid asm statements.  */
-  if (object && INSN_P (object) && INSN_DELETED_P (object))
-    return 1;
-
-  code = GET_CODE (x);
+    return;
 
-  /* Check for some special cases.  */
-  switch (code)
+  /* If this is a CONCAT, recurse for the pieces.  */
+  if (GET_CODE (x) == CONCAT)
     {
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_VECTOR:
-    case CONST:
-    case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-    case ASM_INPUT:
-    case ADDR_VEC:
-    case ADDR_DIFF_VEC:
-    case RETURN:
-      return 1;
-
-    case SET:
-      /* We are allowed to set the virtual registers.  This means that
-        the actual register should receive the source minus the
-        appropriate offset.  This is used, for example, in the handling
-        of non-local gotos.  */
-      if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0)
-       {
-         rtx src = SET_SRC (x);
-
-         /* We are setting the register, not using it, so the relevant
-            offset is the negative of the offset to use were we using
-            the register.  */
-         offset = - offset;
-         instantiate_virtual_regs_1 (&src, NULL_RTX, 0);
-
-         /* The only valid sources here are PLUS or REG.  Just do
-            the simplest possible thing to handle them.  */
-         if (!REG_P (src) && GET_CODE (src) != PLUS)
-           {
-             instantiate_virtual_regs_lossage (object);
-             return 1;
-           }
-
-         start_sequence ();
-         if (!REG_P (src))
-           temp = force_operand (src, NULL_RTX);
-         else
-           temp = src;
-         temp = force_operand (plus_constant (temp, offset), NULL_RTX);
-         seq = get_insns ();
-         end_sequence ();
-
-         emit_insn_before (seq, object);
-         SET_DEST (x) = new;
+      instantiate_decl (XEXP (x, 0));
+      instantiate_decl (XEXP (x, 1));
+      return;
+    }
 
-         if (! validate_change (object, &SET_SRC (x), temp, 0)
-             || ! extra_insns)
-           instantiate_virtual_regs_lossage (object);
+  /* If this is not a MEM, no need to do anything.  Similarly if the
+     address is a constant or a register that is not a virtual register.  */
+  if (!MEM_P (x))
+    return;
 
-         return 1;
-       }
+  addr = XEXP (x, 0);
+  if (CONSTANT_P (addr)
+      || (REG_P (addr)
+         && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
+             || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
+    return;
 
-      instantiate_virtual_regs_1 (&SET_DEST (x), object, extra_insns);
-      loc = &SET_SRC (x);
-      goto restart;
+  for_each_rtx (&XEXP (x, 0), instantiate_virtual_regs_in_rtx, NULL);
+}
 
-    case PLUS:
-      /* Handle special case of virtual register plus constant.  */
-      if (CONSTANT_P (XEXP (x, 1)))
-       {
-         rtx old, new_offset;
+/* Subroutine of instantiate_decls: Process all decls in the given
+   BLOCK node and all its subblocks.  */
 
-         /* Check for (plus (plus VIRT foo) (const_int)) first.  */
-         if (GET_CODE (XEXP (x, 0)) == PLUS)
-           {
-             if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset)))
-               {
-                 instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
-                                             extra_insns);
-                 new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
-               }
-             else
-               {
-                 loc = &XEXP (x, 0);
-                 goto restart;
-               }
-           }
+static void
+instantiate_decls_1 (tree let)
+{
+  tree t;
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-         /* If we have (plus (subreg (virtual-reg)) (const_int)), we know
-            we can commute the PLUS and SUBREG because pointers into the
-            frame are well-behaved.  */
-         else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode
-                  && GET_CODE (XEXP (x, 1)) == CONST_INT
-                  && 0 != (new
-                           = instantiate_new_reg (SUBREG_REG (XEXP (x, 0)),
-                                                  &offset))
-                  && validate_change (object, loc,
-                                      plus_constant (gen_lowpart (ptr_mode,
-                                                                  new),
-                                                     offset
-                                                     + INTVAL (XEXP (x, 1))),
-                                      0))
-               return 1;
-#endif
-         else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0)
-           {
-             /* We know the second operand is a constant.  Unless the
-                first operand is a REG (which has been already checked),
-                it needs to be checked.  */
-             if (!REG_P (XEXP (x, 0)))
-               {
-                 loc = &XEXP (x, 0);
-                 goto restart;
-               }
-             return 1;
-           }
+  for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
+    if (DECL_RTL_SET_P (t))
+      instantiate_decl (DECL_RTL (t));
 
-         new_offset = plus_constant (XEXP (x, 1), offset);
-
-         /* If the new constant is zero, try to replace the sum with just
-            the register.  */
-         if (new_offset == const0_rtx
-             && validate_change (object, loc, new, 0))
-           return 1;
-
-         /* Next try to replace the register and new offset.
-            There are two changes to validate here and we can't assume that
-            in the case of old offset equals new just changing the register
-            will yield a valid insn.  In the interests of a little efficiency,
-            however, we only call validate change once (we don't queue up the
-            changes and then call apply_change_group).  */
-
-         old = XEXP (x, 0);
-         if (offset == 0
-             ? ! validate_change (object, &XEXP (x, 0), new, 0)
-             : (XEXP (x, 0) = new,
-                ! validate_change (object, &XEXP (x, 1), new_offset, 0)))
-           {
-             if (! extra_insns)
-               {
-                 XEXP (x, 0) = old;
-                 return 0;
-               }
+  /* Process all subblocks.  */
+  for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
+    instantiate_decls_1 (t);
+}
 
-             /* Otherwise copy the new constant into a register and replace
-                constant with that register.  */
-             temp = gen_reg_rtx (Pmode);
-             XEXP (x, 0) = new;
-             if (validate_change (object, &XEXP (x, 1), temp, 0))
-               emit_insn_before (gen_move_insn (temp, new_offset), object);
-             else
-               {
-                 /* If that didn't work, replace this expression with a
-                    register containing the sum.  */
+/* Scan all decls in FNDECL (both variables and parameters) and instantiate
+   all virtual registers in their DECL_RTL's.  */
 
-                 XEXP (x, 0) = old;
-                 new = gen_rtx_PLUS (Pmode, new, new_offset);
+static void
+instantiate_decls (tree fndecl)
+{
+  tree decl;
 
-                 start_sequence ();
-                 temp = force_operand (new, NULL_RTX);
-                 seq = get_insns ();
-                 end_sequence ();
+  /* Process all parameters of the function.  */
+  for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
+    {
+      instantiate_decl (DECL_RTL (decl));
+      instantiate_decl (DECL_INCOMING_RTL (decl));
+    }
 
-                 emit_insn_before (seq, object);
-                 if (! validate_change (object, loc, temp, 0)
-                     && ! validate_replace_rtx (x, temp, object))
-                   {
-                     instantiate_virtual_regs_lossage (object);
-                     return 1;
-                   }
-               }
-           }
+  /* Now process all variables defined in the function or its subblocks.  */
+  instantiate_decls_1 (DECL_INITIAL (fndecl));
+}
 
-         return 1;
-       }
+/* Pass through the INSNS of function FNDECL and convert virtual register
+   references to hard register references.  */
 
-      /* Fall through to generic two-operand expression case.  */
-    case EXPR_LIST:
-    case CALL:
-    case COMPARE:
-    case MINUS:
-    case MULT:
-    case DIV:      case UDIV:
-    case MOD:      case UMOD:
-    case AND:      case IOR:      case XOR:
-    case ROTATERT: case ROTATE:
-    case ASHIFTRT: case LSHIFTRT: case ASHIFT:
-    case NE:       case EQ:
-    case GE:       case GT:       case GEU:    case GTU:
-    case LE:       case LT:       case LEU:    case LTU:
-      if (XEXP (x, 1) && ! CONSTANT_P (XEXP (x, 1)))
-       instantiate_virtual_regs_1 (&XEXP (x, 1), object, extra_insns);
-      loc = &XEXP (x, 0);
-      goto restart;
-
-    case MEM:
-      /* Most cases of MEM that convert to valid addresses have already been
-        handled by our scan of decls.  The only special handling we
-        need here is to make a copy of the rtx to ensure it isn't being
-        shared if we have to change it to a pseudo.
-
-        If the rtx is a simple reference to an address via a virtual register,
-        it can potentially be shared.  In such cases, first try to make it
-        a valid address, which can also be shared.  Otherwise, copy it and
-        proceed normally.
-
-        First check for common cases that need no processing.  These are
-        usually due to instantiation already being done on a previous instance
-        of a shared rtx.  */
-
-      temp = XEXP (x, 0);
-      if (CONSTANT_ADDRESS_P (temp)
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-         || temp == arg_pointer_rtx
-#endif
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         || temp == hard_frame_pointer_rtx
-#endif
-         || temp == frame_pointer_rtx)
-       return 1;
-
-      if (GET_CODE (temp) == PLUS
-         && CONSTANT_ADDRESS_P (XEXP (temp, 1))
-         && (XEXP (temp, 0) == frame_pointer_rtx
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-             || XEXP (temp, 0) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-             || XEXP (temp, 0) == arg_pointer_rtx
-#endif
-             ))
-       return 1;
-
-      if (temp == virtual_stack_vars_rtx
-         || temp == virtual_incoming_args_rtx
-         || (GET_CODE (temp) == PLUS
-             && CONSTANT_ADDRESS_P (XEXP (temp, 1))
-             && (XEXP (temp, 0) == virtual_stack_vars_rtx
-                 || XEXP (temp, 0) == virtual_incoming_args_rtx)))
-       {
-         /* This MEM may be shared.  If the substitution can be done without
-            the need to generate new pseudos, we want to do it in place
-            so all copies of the shared rtx benefit.  The call below will
-            only make substitutions if the resulting address is still
-            valid.
-
-            Note that we cannot pass X as the object in the recursive call
-            since the insn being processed may not allow all valid
-            addresses.  However, if we were not passed on object, we can
-            only modify X without copying it if X will have a valid
-            address.
-
-            ??? Also note that this can still lose if OBJECT is an insn that
-            has less restrictions on an address that some other insn.
-            In that case, we will modify the shared address.  This case
-            doesn't seem very likely, though.  One case where this could
-            happen is in the case of a USE or CLOBBER reference, but we
-            take care of that below.  */
-
-         if (instantiate_virtual_regs_1 (&XEXP (x, 0),
-                                         object ? object : x, 0))
-           return 1;
-
-         /* Otherwise make a copy and process that copy.  We copy the entire
-            RTL expression since it might be a PLUS which could also be
-            shared.  */
-         *loc = x = copy_rtx (x);
-       }
+void
+instantiate_virtual_regs (void)
+{
+  rtx insn;
 
-      /* Fall through to generic unary operation case.  */
-    case PREFETCH:
-    case SUBREG:
-    case STRICT_LOW_PART:
-    case NEG:          case NOT:
-    case PRE_DEC:      case PRE_INC:      case POST_DEC:    case POST_INC:
-    case SIGN_EXTEND:  case ZERO_EXTEND:
-    case TRUNCATE:     case FLOAT_EXTEND: case FLOAT_TRUNCATE:
-    case FLOAT:        case FIX:
-    case UNSIGNED_FIX: case UNSIGNED_FLOAT:
-    case ABS:
-    case SQRT:
-    case FFS:
-    case CLZ:          case CTZ:
-    case POPCOUNT:     case PARITY:
-      /* These case either have just one operand or we know that we need not
-        check the rest of the operands.  */
-      loc = &XEXP (x, 0);
-      goto restart;
-
-    case USE:
-    case CLOBBER:
-      /* If the operand is a MEM, see if the change is a valid MEM.  If not,
-        go ahead and make the invalid one, but do it to a copy.  For a REG,
-        just make the recursive call, since there's no chance of a problem.  */
-
-      if ((MEM_P (XEXP (x, 0))
-          && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
-                                         0))
-         || (REG_P (XEXP (x, 0))
-             && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
-       return 1;
-
-      XEXP (x, 0) = copy_rtx (XEXP (x, 0));
-      loc = &XEXP (x, 0);
-      goto restart;
+  /* Compute the offsets to use for this function.  */
+  in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
+  var_offset = STARTING_FRAME_OFFSET;
+  dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
+  out_arg_offset = STACK_POINTER_OFFSET;
+  cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
 
-    case REG:
-      /* Try to replace with a PLUS.  If that doesn't work, compute the sum
-        in front of this insn and substitute the temporary.  */
-      if ((new = instantiate_new_reg (x, &offset)) != 0)
-       {
-         temp = plus_constant (new, offset);
-         if (!validate_change (object, loc, temp, 0))
-           {
-             if (! extra_insns)
-               return 0;
+  /* Initialize recognition, indicating that volatile is OK.  */
+  init_recog ();
 
-             start_sequence ();
-             temp = force_operand (temp, NULL_RTX);
-             seq = get_insns ();
-             end_sequence ();
+  /* Scan through all the insns, instantiating every virtual register still
+     present.  */
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      {
+       /* These patterns in the instruction stream can never be recognized.
+          Fortunately, they shouldn't contain virtual registers either.  */
+       if (GET_CODE (PATTERN (insn)) == USE
+           || GET_CODE (PATTERN (insn)) == CLOBBER
+           || GET_CODE (PATTERN (insn)) == ADDR_VEC
+           || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+           || GET_CODE (PATTERN (insn)) == ASM_INPUT)
+         continue;
 
-             emit_insn_before (seq, object);
-             if (! validate_change (object, loc, temp, 0)
-                 && ! validate_replace_rtx (x, temp, object))
-               instantiate_virtual_regs_lossage (object);
-           }
-       }
+       instantiate_virtual_regs_in_insn (insn);
 
-      return 1;
+       if (INSN_DELETED_P (insn))
+         continue;
 
-    default:
-      break;
-    }
+       for_each_rtx (&REG_NOTES (insn), instantiate_virtual_regs_in_rtx, NULL);
 
-  /* Scan all subexpressions.  */
-  fmt = GET_RTX_FORMAT (code);
-  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
-    if (*fmt == 'e')
-      {
-       if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns))
-         return 0;
+       /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE.  */
+       if (GET_CODE (insn) == CALL_INSN)
+         for_each_rtx (&CALL_INSN_FUNCTION_USAGE (insn),
+                       instantiate_virtual_regs_in_rtx, NULL);
       }
-    else if (*fmt == 'E')
-      for (j = 0; j < XVECLEN (x, i); j++)
-       if (! instantiate_virtual_regs_1 (&XVECEXP (x, i, j), object,
-                                         extra_insns))
-         return 0;
 
-  return 1;
+  /* Instantiate the virtual registers in the DECLs for debugging purposes.  */
+  instantiate_decls (current_function_decl);
+
+  /* Indicate that, from now on, assign_stack_local should use
+     frame_pointer_rtx.  */
+  virtuals_instantiated = 1;
 }
 \f
 /* Return 1 if EXP is an aggregate type (or a value with aggregate type).
@@ -1956,11 +1684,16 @@ aggregate_value_p (tree exp, tree fntype)
        break;
       default:
        /* We don't expect other rtl types here.  */
-       abort();
+       gcc_unreachable ();
       }
 
   if (TREE_CODE (type) == VOID_TYPE)
     return 0;
+  /* If the front end has decided that this needs to be passed by
+     reference, do so.  */
+  if ((TREE_CODE (exp) == PARM_DECL || TREE_CODE (exp) == RESULT_DECL)
+      && DECL_BY_REFERENCE (exp))
+    return 1;
   if (targetm.calls.return_in_memory (type, fntype))
     return 1;
   /* Types that are TREE_ADDRESSABLE must be constructed in memory,
@@ -2011,19 +1744,45 @@ 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))
-    return true;
+  /* 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));
+}
+
+/* Return true if TYPE should be passed by invisible reference.  */
+
+bool
+pass_by_reference (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+                  tree type, bool named_arg)
+{
+  if (type)
+    {
+      /* If this type contains non-trivial constructors, then it is
+        forbidden for the middle-end to create any new copies.  */
+      if (TREE_ADDRESSABLE (type))
+       return true;
+
+      /* GCC post 3.4 passes *all* variable sized types by reference.  */
+      if (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+       return true;
+    }
+
+  return targetm.calls.pass_by_reference (ca, mode, type, named_arg);
+}
 
-#ifdef NON_SAVING_SETJMP
-  /* Protect variables not declared "register" from setjmp.  */
-  if (NON_SAVING_SETJMP
-      && current_function_calls_setjmp
-      && !DECL_REGISTER (decl))
-    return false;
-#endif
+/* Return true if TYPE, which is passed by reference, should be callee
+   copied instead of caller copied.  */
 
-  return (optimize || DECL_REGISTER (decl));
+bool
+reference_callee_copied (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+                        tree type, bool named_arg)
+{
+  if (type && TREE_ADDRESSABLE (type))
+    return false;
+  return targetm.calls.callee_copies (ca, mode, type, named_arg);
 }
 
 /* Structures to communicate between the subroutines of assign_parms.
@@ -2054,7 +1813,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;
@@ -2113,6 +1871,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;
@@ -2120,11 +1879,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.  */
@@ -2159,6 +1927,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;
@@ -2187,24 +1956,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);
@@ -2236,28 +1996,14 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
          && TYPE_TRANSPARENT_UNION (passed_type)))
     passed_type = TREE_TYPE (TYPE_FIELDS (passed_type));
 
-  /* See if this arg was passed by invisible reference.  It is if it is an
-     object whose size depends on the contents of the object itself or if
-     the machine requires these objects be passed that way.  */
-  if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (passed_type))
-      || TREE_ADDRESSABLE (passed_type)
-      || FUNCTION_ARG_PASS_BY_REFERENCE (all->args_so_far, passed_mode,
-                                        passed_type, data->named_arg)
-      )
+  /* See if this arg was passed by invisible reference.  */
+  if (pass_by_reference (&all->args_so_far, passed_mode,
+                        passed_type, data->named_arg))
     {
       passed_type = nominal_type = build_pointer_type (passed_type);
       data->passed_pointer = true;
       passed_mode = nominal_mode = Pmode;
     }
-  /* See if the frontend wants to pass this by invisible reference.  */
-  else if (passed_type != nominal_type
-          && POINTER_TYPE_P (passed_type)
-          && TREE_TYPE (passed_type) == nominal_type)
-    {
-      nominal_type = passed_type;
-      data->passed_pointer = 1;
-      passed_mode = nominal_mode = Pmode;
-    }
 
   /* Find mode as it is passed by the ABI.  */
   promoted_mode = passed_mode;
@@ -2356,17 +2102,18 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
 
   /* If this parameter was passed both in registers and in the stack, use
      the copy on the stack.  */
-  if (MUST_PASS_IN_STACK (data->promoted_mode, data->passed_type))
+  if (targetm.calls.must_pass_in_stack (data->promoted_mode,
+                                       data->passed_type))
     entry_parm = 0;
 
   if (entry_parm)
     {
       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
@@ -2390,10 +2137,9 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
 
          /* We assume at most one partial arg, and it must be the first
             argument on the stack.  */
-         if (all->extra_pretend_bytes || all->pretend_args_size)
-           abort ();
+         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
@@ -2421,7 +2167,7 @@ static bool
 assign_parm_is_stack_parm (struct assign_parm_data_all *all,
                           struct assign_parm_data_one *data)
 {
-  /* Trivially true if we've no incomming register.  */
+  /* Trivially true if we've no incoming register.  */
   if (data->entry_parm == NULL)
     ;
   /* Also true if we're partially in registers and partially not,
@@ -2471,22 +2217,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);
@@ -2517,8 +2262,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;
     }
@@ -2555,7 +2303,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)
 {
@@ -2564,8 +2311,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,
@@ -2590,8 +2341,12 @@ assign_parm_setup_block_p (struct assign_parm_data_one *data)
     return true;
 
 #ifdef BLOCK_REG_PADDING
-  if (data->locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward)
-      && GET_MODE_SIZE (data->promoted_mode) < UNITS_PER_WORD)
+  /* Only assign_parm_setup_block knows how to deal with register arguments
+     that are padded at the least significant end.  */
+  if (REG_P (data->entry_parm)
+      && GET_MODE_SIZE (data->promoted_mode) < UNITS_PER_WORD
+      && (BLOCK_REG_PADDING (data->passed_mode, data->passed_type, 1)
+         == (BYTES_BIG_ENDIAN ? upward : downward)))
     return true;
 #endif
 
@@ -2602,60 +2357,108 @@ assign_parm_setup_block_p (struct assign_parm_data_one *data)
    present and valid in DATA->STACK_RTL.  */
 
 static void
-assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
+assign_parm_setup_block (struct assign_parm_data_all *all,
+                        tree parm, struct assign_parm_data_one *data)
 {
   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);
 
   /* 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
-      && optimize)
+      && data->nominal_mode != BLKmode)
     {
-      rtx parmreg = gen_reg_rtx (data->nominal_mode);
+      rtx elt0 = XEXP (XVECEXP (orig_entry_parm, 0, 0), 0);
 
-      emit_group_store (parmreg, entry_parm, data->nominal_type,
-                       int_size_in_bytes (data->nominal_type));
-      SET_DECL_RTL (parm, parmreg);
-      return;
+      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);
+
+         push_to_sequence (all->conversion_insns);
+
+         /* For values returned in multiple registers, handle possible
+            incompatible calls to emit_group_store.
+
+            For example, the following would be invalid, and would have to
+            be fixed by the conditional below:
+
+            emit_group_store ((reg:SF), (parallel:DF))
+            emit_group_store ((reg:SI), (parallel:DI))
+
+            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));
+
+         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 if (size != 0 && PARM_BOUNDARY % BITS_PER_WORD != 0)
-       abort ();
+      else
+       gcc_assert (!size || !(PARM_BOUNDARY % BITS_PER_WORD));
 
       mem = validize_mem (stack_parm);
 
       /* Handle values in multiple non-contiguous locations.  */
       if (GET_CODE (entry_parm) == PARALLEL)
-       emit_group_store (mem, entry_parm, data->passed_type, size);
+       {
+         push_to_sequence (all->conversion_insns);
+         emit_group_store (mem, entry_parm, data->passed_type, size);
+         all->conversion_insns = get_insns ();
+         end_sequence ();
+       }
 
       else if (size == 0)
        ;
@@ -2694,22 +2497,32 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
            {
              rtx tem, x;
              int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
-             rtx reg = gen_rtx_REG (word_mode, REGNO (data->entry_parm));
+             rtx reg = gen_rtx_REG (word_mode, REGNO (entry_parm));
 
              x = expand_shift (LSHIFT_EXPR, word_mode, reg,
-                               build_int_2 (by, 0), NULL_RTX, 1);
+                               build_int_cst (NULL_TREE, by),
+                               NULL_RTX, 1);
              tem = change_address (mem, word_mode, 0);
              emit_move_insn (tem, x);
            }
          else
-           move_block_from_reg (REGNO (data->entry_parm), mem,
+           move_block_from_reg (REGNO (entry_parm), mem,
                                 size_stored / UNITS_PER_WORD);
        }
       else
-       move_block_from_reg (REGNO (data->entry_parm), mem,
+       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);
 }
 
@@ -2745,10 +2558,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
       SET_DECL_RTL (parm, x);
     }
   else
-    {
-      SET_DECL_RTL (parm, parmreg);
-      maybe_set_unchanging (DECL_RTL (parm), parm);
-    }
+    SET_DECL_RTL (parm, parmreg);
 
   /* Copy the value into the register.  */
   if (data->nominal_mode != data->passed_mode
@@ -2798,7 +2608,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 
       /* TREE_USED gets set erroneously during expand_assignment.  */
       save_tree_used = TREE_USED (parm);
-      expand_assignment (parm, make_tree (data->nominal_type, tempreg), 0);
+      expand_assignment (parm, make_tree (data->nominal_type, tempreg));
       TREE_USED (parm) = save_tree_used;
       all->conversion_insns = get_insns ();
       end_sequence ();
@@ -2830,7 +2640,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
          emit_move_insn (tempreg, DECL_RTL (parm));
          tempreg = convert_to_mode (GET_MODE (parmreg), tempreg, unsigned_p);
          emit_move_insn (parmreg, tempreg);
-         all->conversion_insns = get_insns();
+         all->conversion_insns = get_insns ();
          end_sequence ();
 
          did_conversion = true;
@@ -2845,51 +2655,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 (FUNCTION_ARG_CALLEE_COPIES (all->args_so_far, TYPE_MODE (type),
-                                     type, data->named_arg)
-          && !TREE_ADDRESSABLE (type))
-       {
-         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
@@ -2911,10 +2676,11 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
        {
          enum machine_mode submode
            = GET_MODE_INNER (GET_MODE (parmreg));
-         int regnor = REGNO (gen_realpart (submode, parmreg));
-         int regnoi = REGNO (gen_imagpart (submode, parmreg));
-         rtx stackr = gen_realpart (submode, data->stack_parm);
-         rtx stacki = gen_imagpart (submode, data->stack_parm);
+         int regnor = REGNO (XEXP (parmreg, 0));
+         int regnoi = REGNO (XEXP (parmreg, 1));
+         rtx stackr = adjust_address_nv (data->stack_parm, submode, 0);
+         rtx stacki = adjust_address_nv (data->stack_parm, submode,
+                                         GET_MODE_SIZE (submode));
 
          /* Scan backwards for the set of the real and
             imaginary parts.  */
@@ -2957,6 +2723,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)
     {
@@ -2966,6 +2733,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)));
 
@@ -2973,33 +2742,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);
@@ -3009,9 +2788,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))
     {
@@ -3028,7 +2808,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);
@@ -3060,13 +2860,12 @@ assign_parms_unsplit_complex (tree orig_fnargs, tree fnargs)
 /* Assign RTL expressions to the function's parameters.  This may involve
    copying them into registers and using those registers as the DECL_RTL.  */
 
-void
+static void
 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
@@ -3101,16 +2900,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);
@@ -3132,7 +2923,7 @@ assign_parms (tree fndecl)
       assign_parm_adjust_stack_rtl (&data);
 
       if (assign_parm_setup_block_p (&data))
-       assign_parm_setup_block (parm, &data);
+       assign_parm_setup_block (&all, parm, &data);
       else if (data.passed_pointer || use_register_for_decl (parm))
        assign_parm_setup_reg (&all, parm, &data);
       else
@@ -3140,7 +2931,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.  */
@@ -3156,9 +2947,14 @@ assign_parms (tree fndecl)
       rtx addr = DECL_RTL (all.function_result_decl);
       rtx x;
 
-      addr = convert_memory_address (Pmode, addr);
-      x = gen_rtx_MEM (DECL_MODE (result), addr);
-      set_mem_attributes (x, result, 1);
+      if (DECL_BY_REFERENCE (result))
+       x = addr;
+      else
+       {
+         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);
     }
 
@@ -3238,6 +3034,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
@@ -3339,17 +3245,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;
@@ -3529,7 +3432,8 @@ setjmp_vars_warning (tree block)
          && DECL_RTL_SET_P (decl)
          && REG_P (DECL_RTL (decl))
          && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
-       warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'",
+       warning (0, "%Jvariable %qD might be clobbered by %<longjmp%>"
+                " or %<vfork%>",
                 decl, decl);
     }
 
@@ -3549,46 +3453,11 @@ setjmp_args_warning (void)
     if (DECL_RTL (decl) != 0
        && REG_P (DECL_RTL (decl))
        && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
-      warning ("%Jargument '%D' might be clobbered by `longjmp' or `vfork'",
+      warning (0, "%Jargument %qD might be clobbered by %<longjmp%> or %<vfork%>",
               decl, decl);
 }
 
 \f
-/* Convert a stack slot address ADDR for variable VAR
-   (from a containing function)
-   into an address valid in this function (using a static chain).  */
-
-rtx
-fix_lexical_addr (rtx addr, tree var)
-{
-  rtx basereg;
-  HOST_WIDE_INT displacement;
-  tree context = decl_function_context (var);
-  struct function *fp;
-  rtx base = 0;
-
-  /* If this is the present function, we need not do anything.  */
-  if (context == current_function_decl)
-    return addr;
-
-  fp = find_function_data (context);
-
-  /* Decode given address as base reg plus displacement.  */
-  if (REG_P (addr))
-    basereg = addr, displacement = 0;
-  else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
-    basereg = XEXP (addr, 0), displacement = INTVAL (XEXP (addr, 1));
-  else
-    abort ();
-
-  if (base == 0)
-    abort ();
-
-  /* Use same offset, relative to appropriate static chain or argument
-     pointer.  */
-  return plus_constant (base, displacement);
-}
-\f
 /* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END},
    and create duplicate blocks.  */
 /* ??? Need an option to either create block fragments or to create
@@ -3599,12 +3468,12 @@ void
 reorder_blocks (void)
 {
   tree block = DECL_INITIAL (current_function_decl);
-  varray_type block_stack;
+  VEC(tree,heap) *block_stack;
 
   if (block == NULL_TREE)
     return;
 
-  VARRAY_TREE_INIT (block_stack, 10, "block_stack");
+  block_stack = VEC_alloc (tree, heap, 10);
 
   /* Reset the TREE_ASM_WRITTEN bit for all blocks.  */
   clear_block_marks (block);
@@ -3619,6 +3488,8 @@ reorder_blocks (void)
 
   /* Remove deleted blocks from the block fragment chains.  */
   reorder_fix_fragments (block);
+
+  VEC_free (tree, heap, block_stack);
 }
 
 /* Helper function for reorder_blocks.  Reset TREE_ASM_WRITTEN.  */
@@ -3635,7 +3506,7 @@ clear_block_marks (tree block)
 }
 
 static void
-reorder_blocks_1 (rtx insns, tree current_block, varray_type *p_block_stack)
+reorder_blocks_1 (rtx insns, tree current_block, VEC(tree,heap) **p_block_stack)
 {
   rtx insn;
 
@@ -3678,12 +3549,11 @@ reorder_blocks_1 (rtx insns, tree current_block, varray_type *p_block_stack)
                  BLOCK_SUBBLOCKS (current_block) = block;
                  current_block = block;
                }
-             VARRAY_PUSH_TREE (*p_block_stack, block);
+             VEC_safe_push (tree, heap, *p_block_stack, block);
            }
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
            {
-             NOTE_BLOCK (insn) = VARRAY_TOP_TREE (*p_block_stack);
-             VARRAY_POP (*p_block_stack);
+             NOTE_BLOCK (insn) = VEC_pop (tree, *p_block_stack);
              BLOCK_SUBBLOCKS (current_block)
                = blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
              current_block = BLOCK_SUPERCONTEXT (current_block);
@@ -3871,6 +3741,9 @@ allocate_struct_function (tree fndecl)
   tree fntype = fndecl ? TREE_TYPE (fndecl) : NULL_TREE;
 
   cfun = ggc_alloc_cleared (sizeof (struct function));
+  cfun->cfg = ggc_alloc_cleared (sizeof (struct control_flow_graph));
+
+  n_edges = 0;
 
   cfun->stack_alignment_needed = STACK_BOUNDARY;
   cfun->preferred_stack_boundary = STACK_BOUNDARY;
@@ -3879,7 +3752,6 @@ allocate_struct_function (tree fndecl)
 
   cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
 
-  init_stmt_for_function ();
   init_eh_for_function ();
 
   lang_hooks.function.init (cfun);
@@ -3908,6 +3780,10 @@ allocate_struct_function (tree fndecl)
        && TYPE_ARG_TYPES (fntype) != 0
        && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
           != void_type_node));
+
+  /* Assume all registers in stdarg functions need to be saved.  */
+  cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
+  cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
 }
 
 /* Reset cfun, and other non-struct-function variables to defaults as
@@ -3932,10 +3808,6 @@ prepare_function_start (tree fndecl)
   /* 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.  */
-  rtx_equal_function_value_matters = 1;
-
   /* Indicate that we have not instantiated virtual registers yet.  */
   virtuals_instantiated = 0;
 
@@ -3978,9 +3850,8 @@ init_function_start (tree subr)
 
   /* 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");
+  if (AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr))))
+    warning (OPT_Waggregate_return, "function returns an aggregate");
 }
 
 /* Make sure all values used by the optimization passes have sane
@@ -3996,13 +3867,6 @@ init_function_for_compilation (void)
   VARRAY_GROW (sibcall_epilogue, 0);
 }
 
-/* Expand a call to __main at the beginning of a possible main function.  */
-
-#if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
-#undef HAS_INIT_SECTION
-#define HAS_INIT_SECTION
-#endif
-
 void
 expand_main_function (void)
 {
@@ -4042,32 +3906,14 @@ expand_main_function (void)
     }
 #endif
 
-#ifndef HAS_INIT_SECTION
+#if (defined(INVOKE__main)                             \
+     || (!defined(HAS_INIT_SECTION)                    \
+        && !defined(INIT_SECTION_ASM_OP)               \
+        && !defined(INIT_ARRAY_SECTION_ASM_OP)))
   emit_library_call (init_one_libfunc (NAME__MAIN), LCT_NORMAL, VOIDmode, 0);
 #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.  */
-
-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);
-      /* Flush the queue in case this parameter declaration has
-        side-effects.  */
-      emit_queue ();
-    }
-}
-
 /* Start the RTL for a new function, and set variables used for
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
@@ -4124,8 +3970,12 @@ expand_function_start (tree subr)
        }
       if (value_address)
        {
-         rtx x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
-         set_mem_attributes (x, DECL_RESULT (subr), 1);
+         rtx x = value_address;
+         if (!DECL_BY_REFERENCE (DECL_RESULT (subr)))
+           {
+             x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), x);
+             set_mem_attributes (x, DECL_RESULT (subr), 1);
+           }
          SET_DECL_RTL (DECL_RESULT (subr), x);
        }
     }
@@ -4136,22 +3986,32 @@ expand_function_start (tree subr)
     {
       /* Compute the return values into a pseudo reg, which we will copy
         into the true return register after the cleanups are done.  */
-
-      /* In order to figure out what mode to use for the pseudo, we
-        figure out what the mode of the eventual return register will
-        actually be, and use that.  */
-      rtx hard_reg
-       = hard_function_value (TREE_TYPE (DECL_RESULT (subr)),
-                              subr, 1);
-
-      /* Structures that are returned in registers are not aggregate_value_p,
-        so we may see a PARALLEL or a REG.  */
-      if (REG_P (hard_reg))
-       SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
-      else if (GET_CODE (hard_reg) == PARALLEL)
-       SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
+      tree return_type = TREE_TYPE (DECL_RESULT (subr));
+      if (TYPE_MODE (return_type) != BLKmode
+         && targetm.calls.return_in_msb (return_type))
+       /* expand_function_end will insert the appropriate padding in
+          this case.  Use the return value's natural (unpadded) mode
+          within the function proper.  */
+       SET_DECL_RTL (DECL_RESULT (subr),
+                     gen_reg_rtx (TYPE_MODE (return_type)));
       else
-       abort ();
+       {
+         /* In order to figure out what mode to use for the pseudo, we
+            figure out what the mode of the eventual return register will
+            actually be, and use that.  */
+         rtx hard_reg = hard_function_value (return_type, subr, 1);
+
+         /* Structures that are returned in registers are not
+            aggregate_value_p, so we may see a PARALLEL or a REG.  */
+         if (REG_P (hard_reg))
+           SET_DECL_RTL (DECL_RESULT (subr),
+                         gen_reg_rtx (GET_MODE (hard_reg)));
+         else
+           {
+             gcc_assert (GET_CODE (hard_reg) == PARALLEL);
+             SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
+           }
+       }
 
       /* Set DECL_REGISTER flag so that expand_function_end will copy the
         result to the real return register(s).  */
@@ -4170,7 +4030,6 @@ expand_function_start (tree subr)
 
       set_decl_incoming_rtl (parm, static_chain_incoming_rtx);
       SET_DECL_RTL (parm, local);
-      maybe_set_unchanging (local, parm);
       mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
 
       emit_move_insn (local, static_chain_incoming_rtx);
@@ -4187,8 +4046,9 @@ expand_function_start (tree subr)
         before the frame variable gets declared.  Help out...  */
       expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0));
 
-      t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
-                     integer_zero_node, NULL_TREE, NULL_TREE);
+      t_save = build4 (ARRAY_REF, ptr_type_node,
+                      cfun->nonlocal_goto_save_area,
+                      integer_zero_node, NULL_TREE, NULL_TREE);
       r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
       r_save = convert_memory_address (Pmode, r_save);
 
@@ -4218,9 +4078,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 ();
 }
@@ -4313,7 +4170,7 @@ do_warn_unused_parameter (tree fn)
        decl; decl = TREE_CHAIN (decl))
     if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
        && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))
-      warning ("%Junused parameter '%D'", decl, decl);
+      warning (0, "%Junused parameter %qD", decl, decl);
 }
 
 static GTY(()) rtx initial_trampoline;
@@ -4325,8 +4182,6 @@ expand_function_end (void)
 {
   rtx clobber_after;
 
-  finish_expr_for_function ();
-
   /* If arg_pointer_save_area was referenced only from a nested
      function, we will not have initialized it yet.  Do that now.  */
   if (arg_pointer_save_area && ! cfun->arg_pointer_save_area_init)
@@ -4402,31 +4257,14 @@ expand_function_end (void)
      is computed.  */
   clobber_after = get_last_insn ();
 
-  /* Output the label for the actual return from the function,
-     if one is expected.  This happens either because a function epilogue
-     is used instead of a return instruction, or because a return was done
-     with a goto in order to run local cleanups, or because of pcc-style
-     structure returning.  */
-  if (return_label)
-    emit_label (return_label);
+  /* Output the label for the actual return from the function.  */
+  emit_label (return_label);
 
   /* Let except.c know where it should emit the call to unregister
      the function context for sjlj exceptions.  */
   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.  */
@@ -4442,8 +4280,7 @@ expand_function_end (void)
          rtx real_decl_rtl = current_function_return_rtx;
 
          /* This should be set in assign_parms.  */
-         if (! REG_FUNCTION_VALUE_P (real_decl_rtl))
-           abort ();
+         gcc_assert (REG_FUNCTION_VALUE_P (real_decl_rtl));
 
          /* If this is a BLKmode structure being returned in registers,
             then use the mode computed in expand_return.  Note that if
@@ -4452,10 +4289,22 @@ expand_function_end (void)
          if (GET_MODE (real_decl_rtl) == BLKmode)
            PUT_MODE (real_decl_rtl, GET_MODE (decl_rtl));
 
+         /* If a non-BLKmode return value should be padded at the least
+            significant end of the register, shift it left by the appropriate
+            amount.  BLKmode results are handled using the group load/store
+            machinery.  */
+         if (TYPE_MODE (TREE_TYPE (decl_result)) != BLKmode
+             && targetm.calls.return_in_msb (TREE_TYPE (decl_result)))
+           {
+             emit_move_insn (gen_rtx_REG (GET_MODE (decl_rtl),
+                                          REGNO (real_decl_rtl)),
+                             decl_rtl);
+             shift_return_value (GET_MODE (decl_rtl), true, real_decl_rtl);
+           }
          /* If a named return value dumped decl_return to memory, then
             we may need to re-do the PROMOTE_MODE signed/unsigned
             extension.  */
-         if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
+         else if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
            {
              int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
 
@@ -4491,17 +4340,22 @@ expand_function_end (void)
   if (current_function_returns_struct
       || current_function_returns_pcc_struct)
     {
-      rtx value_address
-       = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+      rtx value_address = DECL_RTL (DECL_RESULT (current_function_decl));
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
+      rtx outgoing;
+
+      if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
+       type = TREE_TYPE (type);
+      else
+       value_address = XEXP (value_address, 0);
+
 #ifdef FUNCTION_OUTGOING_VALUE
-      rtx outgoing
-       = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
-                                  current_function_decl);
+      outgoing = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
+                                         current_function_decl);
 #else
-      rtx outgoing
-       = FUNCTION_VALUE (build_pointer_type (type), current_function_decl);
-#endif
+      outgoing = FUNCTION_VALUE (build_pointer_type (type),
+                                current_function_decl);
+#endif 
 
       /* Mark this as a function return value so integrate will delete the
         assignment and USE below when inlining this function.  */
@@ -4524,20 +4378,31 @@ expand_function_end (void)
 
   /* Emit the actual code to clobber return register.  */
   {
-    rtx seq, after;
+    rtx seq;
 
     start_sequence ();
     clobber_return_register ();
+    expand_naked_return ();
     seq = get_insns ();
     end_sequence ();
 
-    after = emit_insn_after (seq, clobber_after);
+    emit_insn_after (seq, clobber_after);
   }
 
-  /* Output the label for the naked return from the function, if one is
-     expected.  This is currently used only by __builtin_return.  */
-  if (naked_return_label)
-    emit_label (naked_return_label);
+  /* 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
@@ -4570,7 +4435,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 ();
     }
 
@@ -4677,34 +4542,35 @@ emit_return_into_block (basic_block bb, rtx line_note)
 
 #if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
 
-/* These functions convert the epilogue into a variant that does not modify the
-   stack pointer.  This is used in cases where a function returns an object
-   whose size is not known until it is computed.  The called function leaves the
-   object on the stack, leaves the stack depressed, and returns a pointer to
-   the object.
-
-   What we need to do is track all modifications and references to the stack
-   pointer, deleting the modifications and changing the references to point to
-   the location the stack pointer would have pointed to had the modifications
-   taken place.
-
-   These functions need to be portable so we need to make as few assumptions
-   about the epilogue as we can.  However, the epilogue basically contains
-   three things: instructions to reset the stack pointer, instructions to
-   reload registers, possibly including the frame pointer, and an
-   instruction to return to the caller.
-
-   If we can't be sure of what a relevant epilogue insn is doing, we abort.
-   We also make no attempt to validate the insns we make since if they are
-   invalid, we probably can't do anything valid.  The intent is that these
-   routines get "smarter" as more and more machines start to use them and
-   they try operating on different epilogues.
-
-   We use the following structure to track what the part of the epilogue that
-   we've already processed has done.  We keep two copies of the SP equivalence,
-   one for use during the insn we are processing and one for use in the next
-   insn.  The difference is because one part of a PARALLEL may adjust SP
-   and the other may use it.  */
+/* These functions convert the epilogue into a variant that does not
+   modify the stack pointer.  This is used in cases where a function
+   returns an object whose size is not known until it is computed.
+   The called function leaves the object on the stack, leaves the
+   stack depressed, and returns a pointer to the object.
+
+   What we need to do is track all modifications and references to the
+   stack pointer, deleting the modifications and changing the
+   references to point to the location the stack pointer would have
+   pointed to had the modifications taken place.
+
+   These functions need to be portable so we need to make as few
+   assumptions about the epilogue as we can.  However, the epilogue
+   basically contains three things: instructions to reset the stack
+   pointer, instructions to reload registers, possibly including the
+   frame pointer, and an instruction to return to the caller.
+
+   We must be sure of what a relevant epilogue insn is doing.  We also
+   make no attempt to validate the insns we make since if they are
+   invalid, we probably can't do anything valid.  The intent is that
+   these routines get "smarter" as more and more machines start to use
+   them and they try operating on different epilogues.
+
+   We use the following structure to track what the part of the
+   epilogue that we've already processed has done.  We keep two copies
+   of the SP equivalence, one for use during the insn we are
+   processing and one for use in the next insn.  The difference is
+   because one part of a PARALLEL may adjust SP and the other may use
+   it.  */
 
 struct epi_info
 {
@@ -4796,19 +4662,27 @@ keep_stack_depressed (rtx insns)
              insn = next;
              continue;
            }
-         else if (MEM_P (retaddr)
-                  && REG_P (XEXP (retaddr, 0)))
-           base = gen_rtx_REG (Pmode, REGNO (XEXP (retaddr, 0))), offset = 0;
-         else if (MEM_P (retaddr)
-                  && GET_CODE (XEXP (retaddr, 0)) == PLUS
-                  && REG_P (XEXP (XEXP (retaddr, 0), 0))
-                  && GET_CODE (XEXP (XEXP (retaddr, 0), 1)) == CONST_INT)
+         else
            {
-             base = gen_rtx_REG (Pmode, REGNO (XEXP (XEXP (retaddr, 0), 0)));
-             offset = INTVAL (XEXP (XEXP (retaddr, 0), 1));
+             rtx ret_ptr;
+             gcc_assert (MEM_P (retaddr));
+
+             ret_ptr = XEXP (retaddr, 0);
+             
+             if (REG_P (ret_ptr))
+               {
+                 base = gen_rtx_REG (Pmode, REGNO (ret_ptr));
+                 offset = 0;
+               }
+             else
+               {
+                 gcc_assert (GET_CODE (ret_ptr) == PLUS
+                             && REG_P (XEXP (ret_ptr, 0))
+                             && GET_CODE (XEXP (ret_ptr, 1)) == CONST_INT);
+                 base = gen_rtx_REG (Pmode, REGNO (XEXP (ret_ptr, 0)));
+                 offset = INTVAL (XEXP (ret_ptr, 1));
+               }
            }
-         else
-           abort ();
 
          /* If the base of the location containing the return pointer
             is SP, we must update it with the replacement address.  Otherwise,
@@ -4843,8 +4717,7 @@ keep_stack_depressed (rtx insns)
                    && info.const_equiv[regno] == 0)
                  break;
 
-             if (regno == FIRST_PSEUDO_REGISTER)
-               abort ();
+             gcc_assert (regno < FIRST_PSEUDO_REGISTER);
 
              reg = gen_rtx_REG (Pmode, regno);
              emit_move_insn (reg, retaddr);
@@ -4856,10 +4729,8 @@ keep_stack_depressed (rtx insns)
 
          /* Show the SET in the above insn is a RETURN.  */
          jump_set = single_set (jump_insn);
-         if (jump_set == 0)
-           abort ();
-         else
-           SET_IS_RETURN_P (jump_set) = 1;
+         gcc_assert (jump_set);
+         SET_IS_RETURN_P (jump_set) = 1;
        }
 
       /* If SP is not mentioned in the pattern and its equivalent register, if
@@ -4874,11 +4745,13 @@ keep_stack_depressed (rtx insns)
               && (info.sp_equiv_reg == stack_pointer_rtx
                   || !reg_set_p (info.sp_equiv_reg, insn)))
        {
-         if (! validate_replace_rtx (stack_pointer_rtx,
-                                     plus_constant (info.sp_equiv_reg,
-                                                    info.sp_offset),
-                                     insn))
-           abort ();
+         int changed;
+
+         changed = validate_replace_rtx (stack_pointer_rtx,
+                                         plus_constant (info.sp_equiv_reg,
+                                                        info.sp_offset),
+                                         insn);
+         gcc_assert (changed);
 
          add_insn (insn);
        }
@@ -4915,24 +4788,25 @@ static void
 handle_epilogue_set (rtx set, struct epi_info *p)
 {
   /* First handle the case where we are setting SP.  Record what it is being
-     set from.  If unknown, abort.  */
+     set from, which we must be able to determine  */
   if (reg_set_p (stack_pointer_rtx, set))
     {
-      if (SET_DEST (set) != stack_pointer_rtx)
-       abort ();
+      gcc_assert (SET_DEST (set) == stack_pointer_rtx);
 
       if (GET_CODE (SET_SRC (set)) == PLUS)
        {
          p->new_sp_equiv_reg = XEXP (SET_SRC (set), 0);
          if (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
            p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1));
-         else if (REG_P (XEXP (SET_SRC (set), 1))
-                  && REGNO (XEXP (SET_SRC (set), 1)) < FIRST_PSEUDO_REGISTER
-                  && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))] != 0)
-           p->new_sp_offset
-             = INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
          else
-           abort ();
+           {
+             gcc_assert (REG_P (XEXP (SET_SRC (set), 1))
+                         && (REGNO (XEXP (SET_SRC (set), 1))
+                             < FIRST_PSEUDO_REGISTER)
+                         && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
+             p->new_sp_offset
+               = INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
+           }
        }
       else
        p->new_sp_equiv_reg = SET_SRC (set), p->new_sp_offset = 0;
@@ -4944,33 +4818,31 @@ handle_epilogue_set (rtx set, struct epi_info *p)
          p->new_sp_offset += p->sp_offset;
        }
 
-      if (p->new_sp_equiv_reg == 0 || !REG_P (p->new_sp_equiv_reg))
-       abort ();
+      gcc_assert (p->new_sp_equiv_reg && REG_P (p->new_sp_equiv_reg));
 
       return;
     }
 
-  /* Next handle the case where we are setting SP's equivalent register.
-     If we already have a value to set it to, abort.  We could update, but
-     there seems little point in handling that case.  Note that we have
-     to allow for the case where we are setting the register set in
-     the previous part of a PARALLEL inside a single insn.  But use the
-     old offset for any updates within this insn.  We must allow for the case
-     where the register is being set in a different (usually wider) mode than
-     Pmode).  */
+  /* Next handle the case where we are setting SP's equivalent
+     register.  We must not already have a value to set it to.  We
+     could update, but there seems little point in handling that case.
+     Note that we have to allow for the case where we are setting the
+     register set in the previous part of a PARALLEL inside a single
+     insn.  But use the old offset for any updates within this insn.
+     We must allow for the case where the register is being set in a
+     different (usually wider) mode than Pmode).  */
   else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set))
     {
-      if (p->equiv_reg_src != 0
-         || !REG_P (p->new_sp_equiv_reg)
-         || !REG_P (SET_DEST (set))
-         || GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) > BITS_PER_WORD
-         || REGNO (p->new_sp_equiv_reg) != REGNO (SET_DEST (set)))
-       abort ();
-      else
-       p->equiv_reg_src
-         = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
-                                 plus_constant (p->sp_equiv_reg,
-                                                p->sp_offset));
+      gcc_assert (!p->equiv_reg_src
+                 && REG_P (p->new_sp_equiv_reg)
+                 && REG_P (SET_DEST (set))
+                 && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set)))
+                     <= BITS_PER_WORD)
+                 && REGNO (p->new_sp_equiv_reg) == REGNO (SET_DEST (set)));
+      p->equiv_reg_src
+       = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
+                               plus_constant (p->sp_equiv_reg,
+                                              p->sp_offset));
     }
 
   /* Otherwise, replace any references to SP in the insn to its new value
@@ -5063,6 +4935,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
 #if defined (HAVE_epilogue) || defined(HAVE_return)
   rtx epilogue_end = NULL_RTX;
 #endif
+  edge_iterator ei;
 
 #ifdef HAVE_prologue
   if (HAVE_prologue)
@@ -5082,17 +4955,16 @@ 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.  */
-      if (!ENTRY_BLOCK_PTR->succ || ENTRY_BLOCK_PTR->succ->succ_next)
-       abort ();
+      gcc_assert (single_succ_p (ENTRY_BLOCK_PTR));
 
-      insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
+      insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
       inserted = 1;
     }
 #endif
 
   /* If the exit block has no non-fake predecessors, we don't need
      an epilogue.  */
-  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
     if ((e->flags & EDGE_FAKE) == 0)
       break;
   if (e == NULL)
@@ -5108,10 +4980,9 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
         emit (conditional) return instructions.  */
 
       basic_block last;
-      edge e_next;
       rtx label;
 
-      for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
        if (e->flags & EDGE_FALLTHRU)
          break;
       if (e == NULL)
@@ -5129,6 +5000,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
 
       if (BB_HEAD (last) == label && LABEL_P (label))
        {
+         edge_iterator ei2;
          rtx epilogue_line_note = NULL_RTX;
 
          /* Locate the line number associated with the closing brace,
@@ -5142,18 +5014,23 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
                break;
              }
 
-         for (e = last->pred; e; e = e_next)
+         for (ei2 = ei_start (last->preds); (e = ei_safe_edge (ei2)); )
            {
              basic_block bb = e->src;
              rtx jump;
 
-             e_next = e->pred_next;
              if (bb == ENTRY_BLOCK_PTR)
-               continue;
+               {
+                 ei_next (&ei2);
+                 continue;
+               }
 
              jump = BB_END (bb);
              if (!JUMP_P (jump) || JUMP_LABEL (jump) != label)
-               continue;
+               {
+                 ei_next (&ei2);
+                 continue;
+               }
 
              /* If we have an unconditional jump, we can replace that
                 with a simple return instruction.  */
@@ -5168,16 +5045,25 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
              else if (condjump_p (jump))
                {
                  if (! redirect_jump (jump, 0, 0))
-                   continue;
+                   {
+                     ei_next (&ei2);
+                     continue;
+                   }
 
                  /* 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 (bb->succ->succ_next == NULL)
-                   continue;
+                 if (single_succ_p (bb))
+                   {
+                     ei_next (&ei2);
+                     continue;
+                   }
                }
              else
-               continue;
+               {
+                 ei_next (&ei2);
+                 continue;
+               }
 
              /* Fix up the CFG for the successful change we just made.  */
              redirect_edge_succ (e, EXIT_BLOCK_PTR);
@@ -5189,7 +5075,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);
-         last->succ->flags &= ~EDGE_FALLTHRU;
+         single_succ_edge (last)->flags &= ~EDGE_FALLTHRU;
          goto epilogue_done;
        }
     }
@@ -5199,7 +5085,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
      There really shouldn't be a mixture -- either all should have
      been converted or none, however...  */
 
-  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
     if (e->flags & EDGE_FALLTHRU)
       break;
   if (e == NULL)
@@ -5247,7 +5133,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
          use return.  Inserting a jump 'by hand' is extremely messy, so
         we take advantage of cfg_layout_finalize using
        fixup_fallthru_exit_predecessor.  */
-      cfg_layout_initialize ();
+      cfg_layout_initialize (0);
       FOR_EACH_BB (cur_bb)
        if (cur_bb->index >= 0 && cur_bb->next_bb->index >= 0)
          cur_bb->rbi->next = cur_bb->next_bb;
@@ -5260,16 +5146,17 @@ epilogue_done:
 
 #ifdef HAVE_sibcall_epilogue
   /* Emit sibling epilogues before any sibling call sites.  */
-  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+  for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); )
     {
       basic_block bb = e->src;
       rtx insn = BB_END (bb);
-      rtx i;
-      rtx newinsn;
 
       if (!CALL_P (insn)
          || ! SIBLING_CALL_P (insn))
-       continue;
+       {
+         ei_next (&ei);
+         continue;
+       }
 
       start_sequence ();
       emit_insn (gen_sibcall_epilogue ());
@@ -5282,8 +5169,8 @@ 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