OSDN Git Service

* function.c (purge_addressof_1): Postpone insn in fewer cases.
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 669dd2e..6e52d7e 100644 (file)
@@ -1,6 +1,6 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -40,6 +40,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -53,9 +55,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "recog.h"
 #include "output.h"
 #include "basic-block.h"
-#include "obstack.h"
 #include "toplev.h"
-#include "hash.h"
+#include "hashtab.h"
 #include "ggc.h"
 #include "tm_p.h"
 #include "integrate.h"
@@ -69,13 +70,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
 #endif
 
+#ifndef STACK_ALIGNMENT_NEEDED
+#define STACK_ALIGNMENT_NEEDED 1
+#endif
+
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
    give the same symbol without quotes for an alternative entry point.  You
    must define both, or neither.  */
 #ifndef NAME__MAIN
 #define NAME__MAIN "__main"
-#define SYMBOL__MAIN __main
 #endif
 
 /* Round a value to the lowest integer less than it that is a multiple of
@@ -124,17 +128,12 @@ int current_function_uses_only_leaf_regs;
    post-instantiation libcalls.  */
 int virtuals_instantiated;
 
-/* Assign unique numbers to labels generated for profiling.  */
-static int profile_label_no;
+/* Assign unique numbers to labels generated for profiling, debugging, etc.  */
+static GTY(()) int funcdef_no;
 
 /* These variables hold pointers to functions to create and destroy
    target specific, per-function data structures.  */
-void (*init_machine_status) PARAMS ((struct function *));
-void (*free_machine_status) PARAMS ((struct function *));
-/* This variable holds a pointer to a function to register any
-   data items in the target specific, per-function data structure
-   that will need garbage collection.  */
-void (*mark_machine_status) PARAMS ((struct function *));
+struct machine_function * (*init_machine_status) PARAMS ((void));
 
 /* The FUNCTION_DECL for an inline function currently being expanded.  */
 tree inline_function_decl;
@@ -143,12 +142,12 @@ tree inline_function_decl;
 struct function *cfun = 0;
 
 /* These arrays record the INSN_UIDs of the prologue and epilogue insns.  */
-static varray_type prologue;
-static varray_type epilogue;
+static GTY(()) varray_type prologue;
+static GTY(()) varray_type epilogue;
 
 /* Array of INSN_UIDs to hold the INSN_UIDs for each sibcall epilogue
    in this function.  */
-static varray_type sibcall_epilogue;
+static GTY(()) varray_type sibcall_epilogue;
 \f
 /* In order to evaluate some expressions, such as function calls returning
    structures in memory, we need to temporarily allocate stack locations.
@@ -168,7 +167,7 @@ static varray_type sibcall_epilogue;
    level where they are defined.  They are marked a "kept" so that
    free_temp_slots will not free them.  */
 
-struct temp_slot
+struct temp_slot GTY(())
 {
   /* Points to next temporary slot.  */
   struct temp_slot *next;
@@ -188,13 +187,13 @@ struct temp_slot
   tree type;
   /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
   tree rtl_expr;
-  /* Non-zero if this temporary is currently in use.  */
+  /* Nonzero if this temporary is currently in use.  */
   char in_use;
-  /* Non-zero if this temporary has its address taken.  */
+  /* Nonzero if this temporary has its address taken.  */
   char addr_taken;
   /* Nesting level at which this slot is being used.  */
   int level;
-  /* Non-zero if this should survive a call to free_temp_slots.  */
+  /* Nonzero if this should survive a call to free_temp_slots.  */
   int keep;
   /* The offset of the slot from the frame_pointer, including extra space
      for alignment.  This info is for combine_temp_slots.  */
@@ -209,7 +208,7 @@ struct temp_slot
    maintain this list in case two operands of an insn were required to match;
    in that case we must ensure we use the same replacement.  */
 
-struct fixup_replacement
+struct fixup_replacement GTY(())
 {
   rtx old;
   rtx new;
@@ -218,9 +217,9 @@ struct fixup_replacement
 
 struct insns_for_mem_entry
 {
-  /* The KEY in HE will be a MEM.  */
-  struct hash_entry he;
-  /* These are the INSNS which reference the MEM.  */
+  /* A MEM.  */
+  rtx key;
+  /* These are the INSNs which reference the MEM.  */
   rtx insns;
 };
 
@@ -232,18 +231,18 @@ static struct temp_slot *find_temp_slot_from_address  PARAMS ((rtx));
 static void put_reg_into_stack PARAMS ((struct function *, rtx, tree,
                                         enum machine_mode, enum machine_mode,
                                         int, unsigned int, int,
-                                        struct hash_table *));
+                                        htab_t));
 static void schedule_fixup_var_refs PARAMS ((struct function *, rtx, tree,
                                             enum machine_mode,
-                                            struct hash_table *));
+                                            htab_t));
 static void fixup_var_refs     PARAMS ((rtx, enum machine_mode, int, rtx,
-                                        struct hash_table *));
+                                        htab_t));
 static struct fixup_replacement
   *find_fixup_replacement      PARAMS ((struct fixup_replacement **, rtx));
 static void fixup_var_refs_insns PARAMS ((rtx, rtx, enum machine_mode,
                                          int, int, rtx));
 static void fixup_var_refs_insns_with_hash
-                               PARAMS ((struct hash_table *, rtx,
+                               PARAMS ((htab_t, rtx,
                                         enum machine_mode, int, rtx));
 static void fixup_var_refs_insn PARAMS ((rtx, rtx, enum machine_mode,
                                         int, int, rtx));
@@ -262,10 +261,8 @@ static int instantiate_virtual_regs_1 PARAMS ((rtx *, rtx, int));
 static void delete_handlers    PARAMS ((void));
 static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
                                          struct args_size *));
-#ifndef ARGS_GROW_DOWNWARD
 static void pad_below          PARAMS ((struct args_size *, enum machine_mode,
                                         tree));
-#endif
 static rtx round_trampoline_addr PARAMS ((rtx));
 static rtx adjust_trampoline_addr PARAMS ((rtx));
 static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
@@ -283,29 +280,27 @@ static int contains               PARAMS ((rtx, varray_type));
 #ifdef HAVE_return
 static void emit_return_into_block PARAMS ((basic_block, rtx));
 #endif
-static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
-static bool purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
-                                         struct hash_table *));
+static void put_addressof_into_stack PARAMS ((rtx, htab_t));
+static bool purge_addressof_1 PARAMS ((rtx *, rtx, int, int, int, htab_t));
 static void purge_single_hard_subreg_set PARAMS ((rtx));
 #if defined(HAVE_epilogue) && defined(INCOMING_RETURN_ADDR_RTX)
 static rtx keep_stack_depressed PARAMS ((rtx));
 #endif
 static int is_addressof                PARAMS ((rtx *, void *));
-static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *,
-                                                        struct hash_table *,
-                                                        hash_table_key));
-static unsigned long insns_for_mem_hash PARAMS ((hash_table_key));
-static bool insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
+static hashval_t insns_for_mem_hash PARAMS ((const void *));
+static int insns_for_mem_comp PARAMS ((const void *, const void *));
 static int insns_for_mem_walk   PARAMS ((rtx *, void *));
-static void compute_insns_for_mem PARAMS ((rtx, rtx, struct hash_table *));
-static void mark_function_status PARAMS ((struct function *));
-static void maybe_mark_struct_function PARAMS ((void *));
+static void compute_insns_for_mem PARAMS ((rtx, rtx, htab_t));
 static void prepare_function_start PARAMS ((void));
 static void do_clobber_return_reg PARAMS ((rtx, void *));
 static void do_use_return_reg PARAMS ((rtx, void *));
+static void instantiate_virtual_regs_lossage PARAMS ((rtx));
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
-static struct function *outer_function_chain;
+static GTY(()) struct function *outer_function_chain;
+
+/* List of insns that were postponed by purge_addressof_1.  */
+static rtx postponed_insns;
 
 /* Given a function decl for a containing function,
    return the `struct function' for it.  */
@@ -436,8 +431,8 @@ free_after_parsing (f)
   /* f->varasm is used by code generation.  */
   /* f->eh->eh_return_stub_label is used by code generation.  */
 
-  (*lang_hooks.function.free) (f);
-  free_stmt_status (f);
+  (*lang_hooks.function.final) (f);
+  f->stmt = NULL;
 }
 
 /* Clear out all parts of the state in F that can safely be discarded
@@ -448,16 +443,11 @@ void
 free_after_compilation (f)
      struct function *f;
 {
-  free_eh_status (f);
-  free_expr_status (f);
-  free_emit_status (f);
-  free_varasm_status (f);
-
-  if (free_machine_status)
-    (*free_machine_status) (f);
-
-  if (f->x_parm_reg_stack_loc)
-    free (f->x_parm_reg_stack_loc);
+  f->eh = NULL;
+  f->expr = NULL;
+  f->emit = NULL;
+  f->varasm = NULL;
+  f->machine = NULL;
 
   f->x_temp_slots = NULL;
   f->arg_offset_rtx = NULL;
@@ -469,6 +459,8 @@ free_after_compilation (f)
   f->x_nonlocal_goto_stack_level = NULL;
   f->x_cleanup_label = NULL;
   f->x_return_label = NULL;
+  f->computed_goto_common_label = NULL;
+  f->computed_goto_common_reg = NULL;
   f->x_save_expr_regs = NULL;
   f->x_stack_slot_list = NULL;
   f->x_rtl_expr_chain = NULL;
@@ -581,16 +573,27 @@ assign_stack_local_1 (mode, size, align, function)
   frame_off = STARTING_FRAME_OFFSET % frame_alignment;
   frame_phase = frame_off ? frame_alignment - frame_off : 0;
 
-  /* Round frame offset to that alignment.
-     We must be careful here, since FRAME_OFFSET might be negative and
-     division with a negative dividend isn't as well defined as we might
-     like.  So we instead assume that ALIGNMENT is a power of two and
-     use logical operations which are unambiguous.  */
+  /* Round the frame offset to the specified alignment.  The default is
+     to always honor requests to align the stack but a port may choose to
+     do its own stack alignment by defining STACK_ALIGNMENT_NEEDED.  */
+  if (STACK_ALIGNMENT_NEEDED
+      || mode != BLKmode
+      || size != 0)
+    {
+      /*  We must be careful here, since FRAME_OFFSET might be negative and
+         division with a negative dividend isn't as well defined as we might
+         like.  So we instead assume that ALIGNMENT is a power of two and
+         use logical operations which are unambiguous.  */
 #ifdef FRAME_GROWS_DOWNWARD
-  function->x_frame_offset = FLOOR_ROUND (function->x_frame_offset - frame_phase, alignment) + frame_phase;
+      function->x_frame_offset
+       = (FLOOR_ROUND (function->x_frame_offset - frame_phase, alignment)
+          + frame_phase);
 #else
-  function->x_frame_offset = CEIL_ROUND (function->x_frame_offset - frame_phase, alignment) + frame_phase;
+      function->x_frame_offset
+       = (CEIL_ROUND (function->x_frame_offset - frame_phase, alignment)
+          + frame_phase);
 #endif
+    }
 
   /* On a big-endian machine, if we are allocating more space than we will use,
      use the least significant bytes of those that are allocated.  */
@@ -601,11 +604,14 @@ assign_stack_local_1 (mode, size, align, function)
      address relative to the frame pointer.  */
   if (function == cfun && virtuals_instantiated)
     addr = plus_constant (frame_pointer_rtx,
+                         trunc_int_for_mode
                          (frame_offset + bigend_correction
-                          + STARTING_FRAME_OFFSET));
+                          + STARTING_FRAME_OFFSET, Pmode));
   else
     addr = plus_constant (virtual_stack_vars_rtx,
-                         function->x_frame_offset + bigend_correction);
+                         trunc_int_for_mode
+                         (function->x_frame_offset + bigend_correction,
+                          Pmode));
 
 #ifndef FRAME_GROWS_DOWNWARD
   function->x_frame_offset += size;
@@ -657,6 +663,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
 {
   unsigned int align;
   struct temp_slot *p, *best_p = 0;
+  rtx slot;
 
   /* If SIZE is -1 it means that somebody tried to allocate a temporary
      of a variable size.  */
@@ -749,7 +756,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
        abort ();
       p->slot = assign_stack_local (mode,
                                    (mode == BLKmode
-                                    ? CEIL_ROUND (size, align / BITS_PER_UNIT)
+                                    ? CEIL_ROUND (size, (int) align / BITS_PER_UNIT)
                                     : size),
                                    align);
 
@@ -802,29 +809,27 @@ assign_stack_temp_for_type (mode, size, keep, type)
       p->keep = keep;
     }
 
-  /* We may be reusing an old slot, so clear any MEM flags that may have been
-     set from before.  */
-  RTX_UNCHANGING_P (p->slot) = 0;
-  MEM_IN_STRUCT_P (p->slot) = 0;
-  MEM_SCALAR_P (p->slot) = 0;
-  MEM_VOLATILE_P (p->slot) = 0;
-  set_mem_alias_set (p->slot, 0);
+
+  /* Create a new MEM rtx to avoid clobbering MEM flags of old slots.  */
+  slot = gen_rtx_MEM (mode, XEXP (p->slot, 0));
+  stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, slot, stack_slot_list);
 
   /* If we know the alias set for the memory that will be used, use
      it.  If there's no TYPE, then we don't know anything about the
      alias set for the memory.  */
-  set_mem_alias_set (p->slot, type ? get_alias_set (type) : 0);
-  set_mem_align (p->slot, align);
+  set_mem_alias_set (slot, type ? get_alias_set (type) : 0);
+  set_mem_align (slot, align);
 
   /* If a type is specified, set the relevant flags.  */
   if (type != 0)
     {
-      RTX_UNCHANGING_P (p->slot) = TYPE_READONLY (type);
-      MEM_VOLATILE_P (p->slot) = TYPE_VOLATILE (type);
-      MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type));
+      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));
     }
 
-  return p->slot;
+  return slot;
 }
 
 /* Allocate a temporary stack slot and record it for possible later
@@ -1272,46 +1277,6 @@ push_temp_slots ()
   temp_slot_level++;
 }
 
-/* Likewise, but save the new level as the place to allocate variables
-   for blocks.  */
-
-#if 0
-void
-push_temp_slots_for_block ()
-{
-  push_temp_slots ();
-
-  var_temp_slot_level = temp_slot_level;
-}
-
-/* Likewise, but save the new level as the place to allocate temporaries
-   for TARGET_EXPRs.  */
-
-void
-push_temp_slots_for_target ()
-{
-  push_temp_slots ();
-
-  target_temp_slot_level = temp_slot_level;
-}
-
-/* Set and get the value of target_temp_slot_level.  The only
-   permitted use of these functions is to save and restore this value.  */
-
-int
-get_target_temp_slot_level ()
-{
-  return target_temp_slot_level;
-}
-
-void
-set_target_temp_slot_level (level)
-     int level;
-{
-  target_temp_slot_level = level;
-}
-#endif
-
 /* Pop a temporary nesting level.  All slots in use in the current level
    are freed.  */
 
@@ -1341,12 +1306,16 @@ init_temp_slots ()
   target_temp_slot_level = 0;
 }
 \f
-/* Retroactively move an auto variable from a register to a stack slot.
-   This is done when an address-reference to the variable is seen.  */
+/* Retroactively move an auto variable from a register to a stack
+   slot.  This is done when an address-reference to the variable is
+   seen.  If RESCAN is true, all previously emitted instructions are
+   examined and modified to handle the fact that DECL is now
+   addressable.  */
 
 void
-put_var_into_stack (decl)
+put_var_into_stack (decl, rescan)
      tree decl;
+     int rescan;
 {
   rtx reg;
   enum machine_mode promoted_mode, decl_mode;
@@ -1421,7 +1390,7 @@ put_var_into_stack (decl)
         to put things in the stack for the sake of setjmp, try to keep it
         in a register until we know we actually need the address.  */
       if (can_use_addressof)
-       gen_mem_addressof (reg, decl);
+       gen_mem_addressof (reg, decl, rescan);
       else
        put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
                            decl_mode, volatilep, 0, usedp, 0);
@@ -1468,7 +1437,7 @@ put_var_into_stack (decl)
       /* Prevent sharing of rtl that might lose.  */
       if (GET_CODE (XEXP (reg, 0)) == PLUS)
        XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
-      if (usedp)
+      if (usedp && rescan)
        {
          schedule_fixup_var_refs (function, reg, TREE_TYPE (decl),
                                   promoted_mode, 0);
@@ -1497,7 +1466,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
      int volatile_p;
      unsigned int original_regno;
      int used_p;
-     struct hash_table *ht;
+     htab_t ht;
 {
   struct function *func = function ? function : cfun;
   rtx new = 0;
@@ -1545,7 +1514,7 @@ schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
      rtx reg;
      tree type;
      enum machine_mode promoted_mode;
-     struct hash_table *ht;
+     htab_t ht;
 {
   int unsigned_p = type ? TREE_UNSIGNED (type) : 0;
 
@@ -1571,7 +1540,7 @@ fixup_var_refs (var, promoted_mode, unsignedp, may_share, ht)
      rtx var;
      enum machine_mode promoted_mode;
      int unsignedp;
-     struct hash_table *ht;
+     htab_t ht;
      rtx may_share;
 {
   tree pending;
@@ -1707,17 +1676,18 @@ fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel, may_share)
 
 static void
 fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp, may_share)
-     struct hash_table *ht;
+     htab_t ht;
      rtx var;
      enum machine_mode promoted_mode;
      int unsignedp;
      rtx may_share;
 {
-  struct insns_for_mem_entry *ime
-    = (struct insns_for_mem_entry *) hash_lookup (ht, var,
-                                                 /*create=*/0, /*copy=*/0);
+  struct insns_for_mem_entry tmp;
+  struct insns_for_mem_entry *ime;
   rtx insn_list;
 
+  tmp.key = var;
+  ime = (struct insns_for_mem_entry *) htab_find (ht, &tmp);
   for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1))
     if (INSN_P (XEXP (insn_list, 0)))
       fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode,
@@ -1881,7 +1851,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel, no_share)
                  start_sequence ();
                  convert_move (replacements->new,
                                replacements->old, unsignedp);
-                 seq = gen_sequence ();
+                 seq = get_insns ();
                  end_sequence ();
                }
              else
@@ -1963,7 +1933,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share)
 
              start_sequence ();
              new_insn = emit_insn (gen_rtx_SET (VOIDmode, y, sub));
-             seq = gen_sequence ();
+             seq = get_insns ();
              end_sequence ();
 
              if (recog_memoized (new_insn) < 0)
@@ -1974,7 +1944,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share)
                  sub = force_operand (sub, y);
                  if (sub != y)
                    emit_insn (gen_move_insn (y, sub));
-                 seq = gen_sequence ();
+                 seq = get_insns ();
                  end_sequence ();
                }
 
@@ -2399,12 +2369,12 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share)
               copy SET_SRC (x) to SET_DEST (x) in some way.  So
               we generate the move and see whether it requires more
               than one insn.  If it does, we emit those insns and
-              delete INSN.  Otherwise, we an just replace the pattern
+              delete INSN.  Otherwise, we can just replace the pattern
               of INSN; we have already verified above that INSN has
               no other function that to do X.  */
 
            pat = gen_move_insn (SET_DEST (x), SET_SRC (x));
-           if (GET_CODE (pat) == SEQUENCE)
+           if (NEXT_INSN (pat) != NULL_RTX)
              {
                last = emit_insn_before (pat, insn);
 
@@ -2422,7 +2392,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share)
                delete_insn (last);
              }
            else
-             PATTERN (insn) = pat;
+             PATTERN (insn) = PATTERN (pat);
 
            return;
          }
@@ -2448,7 +2418,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share)
              return;
 
            pat = gen_move_insn (SET_DEST (x), SET_SRC (x));
-           if (GET_CODE (pat) == SEQUENCE)
+           if (NEXT_INSN (pat) != NULL_RTX)
              {
                last = emit_insn_before (pat, insn);
 
@@ -2466,7 +2436,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements, no_share)
                delete_insn (last);
              }
            else
-             PATTERN (insn) = pat;
+             PATTERN (insn) = PATTERN (pat);
 
            return;
          }
@@ -2557,7 +2527,7 @@ fixup_memory_subreg (x, insn, promoted_mode, uncritical)
   rtx mem = SUBREG_REG (x);
   rtx addr = XEXP (mem, 0);
   enum machine_mode mode = GET_MODE (x);
-  rtx result;
+  rtx result, seq;
 
   /* Paradoxical SUBREGs are usually invalid during RTL generation.  */
   if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (mem)) && ! uncritical)
@@ -2577,8 +2547,10 @@ fixup_memory_subreg (x, insn, promoted_mode, uncritical)
 
   start_sequence ();
   result = adjust_address (mem, mode, offset);
-  emit_insn_before (gen_sequence (), insn);
+  seq = get_insns ();
   end_sequence ();
+
+  emit_insn_before (seq, insn);
   return result;
 }
 
@@ -2668,7 +2640,7 @@ fixup_stack_1 (x, insn)
 
          start_sequence ();
          temp = copy_to_reg (ad);
-         seq = gen_sequence ();
+         seq = get_insns ();
          end_sequence ();
          emit_insn_before (seq, insn);
          return replace_equiv_address (x, temp);
@@ -2779,7 +2751,7 @@ optimize_bit_field (body, insn, equiv_mem)
          memref = adjust_address (memref, mode, offset);
          insns = get_insns ();
          end_sequence ();
-         emit_insns_before (insns, insn);
+         emit_insn_before (insns, insn);
 
          /* Store this memory reference where
             we found the bit field reference.  */
@@ -2847,7 +2819,7 @@ optimize_bit_field (body, insn, equiv_mem)
             special; just let the optimization be suppressed.  */
 
          if (apply_change_group () && seq)
-           emit_insns_before (seq, insn);
+           emit_insn_before (seq, insn);
        }
     }
 }
@@ -2905,15 +2877,19 @@ static int cfa_offset;
 #define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL)
 #endif
 
-/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just had its
-   address taken.  DECL is the decl or SAVE_EXPR for the object stored in the
-   register, for later use if we do need to force REG into the stack.  REG is
-   overwritten by the MEM like in put_reg_into_stack.  */
+/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just
+   had its address taken.  DECL is the decl or SAVE_EXPR for the
+   object stored in the register, for later use if we do need to force
+   REG into the stack.  REG is overwritten by the MEM like in
+   put_reg_into_stack.  RESCAN is true if previously emitted
+   instructions must be rescanned and modified now that the REG has
+   been transformed.  */
 
 rtx
-gen_mem_addressof (reg, decl)
+gen_mem_addressof (reg, decl, rescan)
      rtx reg;
      tree decl;
+     int rescan;
 {
   rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)),
                             REGNO (reg), decl);
@@ -2951,10 +2927,11 @@ gen_mem_addressof (reg, decl)
       if (DECL_P (decl) && decl_rtl == reg)
        SET_DECL_RTL (decl, reg);
 
-      if (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0))
+      if (rescan 
+         && (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0)))
        fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0);
     }
-  else
+  else if (rescan)
     fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
 
   return reg;
@@ -2979,7 +2956,7 @@ flush_addressof (decl)
 static void
 put_addressof_into_stack (r, ht)
      rtx r;
-     struct hash_table *ht;
+     htab_t ht;
 {
   tree decl, type;
   int volatile_p, used_p;
@@ -3024,14 +3001,15 @@ static rtx purge_addressof_replacements;
 /* Helper function for purge_addressof.  See if the rtx expression at *LOC
    in INSN needs to be changed.  If FORCE, always put any ADDRESSOFs into
    the stack.  If the function returns FALSE then the replacement could not
-   be made.  */
+   be made.  If MAY_POSTPONE is true and we would not put the addressof
+   to stack, postpone processing of the insn.  */
 
 static bool
-purge_addressof_1 (loc, insn, force, store, ht)
+purge_addressof_1 (loc, insn, force, store, may_postpone, ht)
      rtx *loc;
      rtx insn;
-     int force, store;
-     struct hash_table *ht;
+     int force, store, may_postpone;
+     htab_t ht;
 {
   rtx x;
   RTX_CODE code;
@@ -3053,8 +3031,10 @@ purge_addressof_1 (loc, insn, force, store, ht)
      memory.  */
   if (code == SET)
     {
-      result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
-      result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
+      result = purge_addressof_1 (&SET_DEST (x), insn, force, 1,
+                                 may_postpone, ht);
+      result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0,
+                                  may_postpone, ht);
       return result;
     }
   else if (code == ADDRESSOF)
@@ -3062,10 +3042,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
       rtx sub, insns;
 
       if (GET_CODE (XEXP (x, 0)) != MEM)
-       {
-         put_addressof_into_stack (x, ht);
-         return true;
-       }
+       put_addressof_into_stack (x, ht);
 
       /* We must create a copy of the rtx because it was created by
         overwriting a REG rtx which is always shared.  */
@@ -3075,12 +3052,20 @@ purge_addressof_1 (loc, insn, force, store, ht)
        return true;
 
       start_sequence ();
-      sub = force_operand (sub, NULL_RTX);
+
+      /* If SUB is a hard or virtual register, try it as a pseudo-register. 
+        Otherwise, perhaps SUB is an expression, so generate code to compute
+        it.  */
+      if (GET_CODE (sub) == REG && REGNO (sub) <= LAST_VIRTUAL_REGISTER)
+       sub = copy_to_reg (sub);
+      else
+       sub = force_operand (sub, NULL_RTX);
+
       if (! validate_change (insn, loc, sub, 0)
          && ! validate_replace_rtx (x, sub, insn))
        abort ();
 
-      insns = gen_sequence ();
+      insns = get_insns ();
       end_sequence ();
       emit_insn_before (insns, insn);
       return true;
@@ -3099,6 +3084,15 @@ purge_addressof_1 (loc, insn, force, store, ht)
        {
          int size_x, size_sub;
 
+         if (may_postpone)
+           {
+             /* Postpone for now, so that we do not emit bitfield arithmetics
+                unless there is some benefit from it.  */
+             if (!postponed_insns || XEXP (postponed_insns, 0) != insn)
+               postponed_insns = alloc_INSN_LIST (insn, postponed_insns);
+             return true;
+           }
+
          if (!insn)
            {
              /* When processing REG_NOTES look at the list of
@@ -3155,6 +3149,36 @@ purge_addressof_1 (loc, insn, force, store, ht)
                    return true;
                  }
 
+             /* When we are processing the REG_NOTES of the last instruction
+                of a libcall, there will be typically no replacements
+                for that insn; the replacements happened before, piecemeal
+                fashion.  OTOH we are not interested in the details of
+                this for the REG_EQUAL note, we want to know the big picture,
+                which can be succinctly described with a simple SUBREG.
+                Note that removing the REG_EQUAL note is not an option
+                on the last insn of a libcall, so we must do a replacement.  */
+             if (! purge_addressof_replacements
+                 && ! purge_bitfield_addressof_replacements)
+               {
+                 /* In compile/990107-1.c:7 compiled at -O1 -m1 for sh-elf,
+                    we got
+                    (mem:DI (addressof:SI (reg/v:DF 160) 159 0x401c8510)
+                     [0 S8 A32]), which can be expressed with a simple
+                    same-size subreg  */
+                 if ((GET_MODE_SIZE (GET_MODE (x))
+                      == GET_MODE_SIZE (GET_MODE (sub)))
+                     /* Again, invalid pointer casts (as in
+                        compile/990203-1.c) can require paradoxical
+                        subregs.  */
+                     || (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
+                         && (GET_MODE_SIZE (GET_MODE (x))
+                             > GET_MODE_SIZE (GET_MODE (sub)))))
+                   {
+                     *loc = gen_rtx_SUBREG (GET_MODE (x), sub, 0);
+                     return true;
+                   }
+                 /* ??? Are there other cases we should handle?  */
+               }
              /* Sometimes we may not be able to find the replacement.  For
                 example when the original insn was a MEM in a wider mode,
                 and the note is part of a sign extension of a narrowed
@@ -3168,10 +3192,16 @@ purge_addressof_1 (loc, insn, force, store, ht)
          size_x = GET_MODE_BITSIZE (GET_MODE (x));
          size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
 
+         /* Do not frob unchanging MEMs.  If a later reference forces the
+            pseudo to the stack, we can wind up with multiple writes to
+            an unchanging memory, which is invalid.  */
+         if (RTX_UNCHANGING_P (x) && size_x != size_sub)
+           ;
+
          /* Don't even consider working with paradoxical subregs,
             or the moral equivalent seen here.  */
-         if (size_x <= size_sub
-             && int_mode_for_mode (GET_MODE (sub)) != BLKmode)
+         else if (size_x <= size_sub
+                  && int_mode_for_mode (GET_MODE (sub)) != BLKmode)
            {
              /* Do a bitfield insertion to mirror what would happen
                 in memory.  */
@@ -3191,7 +3221,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
                      end_sequence ();
                      goto give_up;
                    }
-                 seq = gen_sequence ();
+                 seq = get_insns ();
                  end_sequence ();
                  emit_insn_before (seq, insn);
                  compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
@@ -3205,7 +3235,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
                     might have created.  */
                  unshare_all_rtl_again (get_insns ());
 
-                 seq = gen_sequence ();
+                 seq = get_insns ();
                  end_sequence ();
                  p = emit_insn_after (seq, insn);
                  if (NEXT_INSN (insn))
@@ -3230,7 +3260,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
                      goto give_up;
                    }
 
-                 seq = gen_sequence ();
+                 seq = get_insns ();
                  end_sequence ();
                  emit_insn_before (seq, insn);
                  compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
@@ -3282,59 +3312,45 @@ purge_addressof_1 (loc, insn, force, store, ht)
   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
     {
       if (*fmt == 'e')
-       result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0, ht);
+       result &= purge_addressof_1 (&XEXP (x, i), insn, force, 0,
+                                    may_postpone, ht);
       else if (*fmt == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
-         result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0, ht);
+         result &= purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0,
+                                      may_postpone, ht);
     }
 
   return result;
 }
 
-/* Return a new hash table entry in HT.  */
-
-static struct hash_entry *
-insns_for_mem_newfunc (he, ht, k)
-     struct hash_entry *he;
-     struct hash_table *ht;
-     hash_table_key k ATTRIBUTE_UNUSED;
-{
-  struct insns_for_mem_entry *ifmhe;
-  if (he)
-    return he;
-
-  ifmhe = ((struct insns_for_mem_entry *)
-          hash_allocate (ht, sizeof (struct insns_for_mem_entry)));
-  ifmhe->insns = NULL_RTX;
-
-  return &ifmhe->he;
-}
-
 /* Return a hash value for K, a REG.  */
 
-static unsigned long
+static hashval_t
 insns_for_mem_hash (k)
-     hash_table_key k;
+     const void * k;
 {
-  /* K is really a RTX.  Just use the address as the hash value.  */
-  return (unsigned long) k;
+  /* Use the address of the key for the hash value.  */
+  struct insns_for_mem_entry *m = (struct insns_for_mem_entry *) k;
+  return htab_hash_pointer (m->key);
 }
 
-/* Return non-zero if K1 and K2 (two REGs) are the same.  */
+/* Return nonzero if K1 and K2 (two REGs) are the same.  */
 
-static bool
+static int
 insns_for_mem_comp (k1, k2)
-     hash_table_key k1;
-     hash_table_key k2;
+     const void * k1;
+     const void * k2;
 {
-  return k1 == k2;
+  struct insns_for_mem_entry *m1 = (struct insns_for_mem_entry *) k1;
+  struct insns_for_mem_entry *m2 = (struct insns_for_mem_entry *) k2;
+  return m1->key == m2->key;
 }
 
 struct insns_for_mem_walk_info
 {
   /* The hash table that we are using to record which INSNs use which
      MEMs.  */
-  struct hash_table *ht;
+  htab_t ht;
 
   /* The INSN we are currently processing.  */
   rtx insn;
@@ -3356,18 +3372,26 @@ insns_for_mem_walk (r, data)
 {
   struct insns_for_mem_walk_info *ifmwi
     = (struct insns_for_mem_walk_info *) data;
+  struct insns_for_mem_entry tmp;
+  tmp.insns = NULL_RTX;
 
   if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
       && GET_CODE (XEXP (*r, 0)) == REG)
-    hash_lookup (ifmwi->ht, XEXP (*r, 0), /*create=*/1, /*copy=*/0);
+    {
+      PTR *e;
+      tmp.key = XEXP (*r, 0);
+      e = htab_find_slot (ifmwi->ht, &tmp, INSERT);
+      if (*e == NULL)
+       {
+         *e = ggc_alloc (sizeof (tmp));
+         memcpy (*e, &tmp, sizeof (tmp));
+       }
+    }
   else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
     {
-      /* Lookup this MEM in the hashtable, creating it if necessary.  */
-      struct insns_for_mem_entry *ifme
-       = (struct insns_for_mem_entry *) hash_lookup (ifmwi->ht,
-                                                     *r,
-                                                     /*create=*/0,
-                                                     /*copy=*/0);
+      struct insns_for_mem_entry *ifme;
+      tmp.key = *r;
+      ifme = (struct insns_for_mem_entry *) htab_find (ifmwi->ht, &tmp);
 
       /* If we have not already recorded this INSN, do so now.  Since
         we process the INSNs in order, we know that if we have
@@ -3387,7 +3411,7 @@ static void
 compute_insns_for_mem (insns, last_insn, ht)
      rtx insns;
      rtx last_insn;
-     struct hash_table *ht;
+     htab_t ht;
 {
   rtx insn;
   struct insns_for_mem_walk_info ifmwi;
@@ -3421,8 +3445,8 @@ void
 purge_addressof (insns)
      rtx insns;
 {
-  rtx insn;
-  struct hash_table ht;
+  rtx insn, tmp;
+  htab_t ht;
 
   /* When we actually purge ADDRESSOFs, we turn REGs into MEMs.  That
      requires a fixup pass over the instruction stream to correct
@@ -3431,23 +3455,21 @@ purge_addressof (insns)
      mentioned in very many instructions.  So, we speed up the process
      by pre-calculating which REGs occur in which INSNs; that allows
      us to perform the fixup passes much more quickly.  */
-  hash_table_init (&ht,
-                  insns_for_mem_newfunc,
-                  insns_for_mem_hash,
-                  insns_for_mem_comp);
-  compute_insns_for_mem (insns, NULL_RTX, &ht);
+  ht = htab_create_ggc (1000, insns_for_mem_hash, insns_for_mem_comp, NULL);
+  compute_insns_for_mem (insns, NULL_RTX, ht);
+
+  postponed_insns = NULL;
 
   for (insn = insns; insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
-       || GET_CODE (insn) == CALL_INSN)
+    if (INSN_P (insn))
       {
        if (! purge_addressof_1 (&PATTERN (insn), insn,
-                                asm_noperands (PATTERN (insn)) > 0, 0, &ht))
+                                asm_noperands (PATTERN (insn)) > 0, 0, 1, ht))
          /* If we could not replace the ADDRESSOFs in the insn,
             something is wrong.  */
          abort ();
 
-       if (! purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0, &ht))
+       if (! purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0, 0, ht))
          {
            /* If we could not replace the ADDRESSOFs in the insn's notes,
               we can just remove the offending notes instead.  */
@@ -3467,8 +3489,20 @@ purge_addressof (insns)
          }
       }
 
+  /* Process the postponed insns.  */
+  while (postponed_insns)
+    {
+      insn = XEXP (postponed_insns, 0);
+      tmp = postponed_insns;
+      postponed_insns = XEXP (postponed_insns, 1);
+      free_INSN_LIST_node (tmp);
+
+      if (! purge_addressof_1 (&PATTERN (insn), insn,
+                              asm_noperands (PATTERN (insn)) > 0, 0, 0, ht))
+       abort ();
+    }
+
   /* Clean up.  */
-  hash_table_free (&ht);
   purge_bitfield_addressof_replacements = 0;
   purge_addressof_replacements = 0;
 
@@ -3591,11 +3625,19 @@ instantiate_virtual_regs (fndecl, insns)
        || 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);
       }
 
   /* Instantiate the stack slots for the parm registers, for later use in
@@ -3670,7 +3712,7 @@ instantiate_decls_1 (let, valid_only)
 /* Subroutine of the preceding procedures: Given RTL representing a
    decl and the size of the object, do any instantiation required.
 
-   If VALID_ONLY is non-zero, it means that the RTL should only be
+   If VALID_ONLY is nonzero, it means that the RTL should only be
    changed if the new address is valid.  */
 
 static void
@@ -3763,6 +3805,22 @@ instantiate_new_reg (x, poffset)
   return new;
 }
 \f
+
+/* 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 (insn)
+     rtx insn;
+{
+  if (asm_noperands (PATTERN (insn)) >= 0)
+    {
+      error_for_asm (insn, "impossible constraint in `asm'");
+      delete_insn (insn);
+    }
+  else
+    abort ();
+}
 /* Given a pointer to a piece of rtx and an optional pointer to the
    containing object, instantiate any virtual registers present in it.
 
@@ -3799,6 +3857,10 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
   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);
 
   /* Check for some special cases.  */
@@ -3836,7 +3898,10 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
          /* The only valid sources here are PLUS or REG.  Just do
             the simplest possible thing to handle them.  */
          if (GET_CODE (src) != REG && GET_CODE (src) != PLUS)
-           abort ();
+           {
+             instantiate_virtual_regs_lossage (object);
+             return 1;
+           }
 
          start_sequence ();
          if (GET_CODE (src) != REG)
@@ -3847,12 +3912,12 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
          seq = get_insns ();
          end_sequence ();
 
-         emit_insns_before (seq, object);
+         emit_insn_before (seq, object);
          SET_DEST (x) = new;
 
          if (! validate_change (object, &SET_SRC (x), temp, 0)
              || ! extra_insns)
-           abort ();
+           instantiate_virtual_regs_lossage (object);
 
          return 1;
        }
@@ -3959,10 +4024,13 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
                  seq = get_insns ();
                  end_sequence ();
 
-                 emit_insns_before (seq, object);
+                 emit_insn_before (seq, object);
                  if (! validate_change (object, loc, temp, 0)
                      && ! validate_replace_rtx (x, temp, object))
-                   abort ();
+                   {
+                     instantiate_virtual_regs_lossage (object);
+                     return 1;
+                   }
                }
            }
 
@@ -4075,6 +4143,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
     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);
@@ -4113,10 +4183,10 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
              seq = get_insns ();
              end_sequence ();
 
-             emit_insns_before (seq, object);
+             emit_insn_before (seq, object);
              if (! validate_change (object, loc, temp, 0)
                  && ! validate_replace_rtx (x, temp, object))
-               abort ();
+               instantiate_virtual_regs_lossage (object);
            }
        }
 
@@ -4210,12 +4280,6 @@ delete_handlers ()
     }
 }
 \f
-int
-max_parm_reg_num ()
-{
-  return max_parm_reg;
-}
-
 /* Return the first insn following those generated by `assign_parms'.  */
 
 rtx
@@ -4226,24 +4290,6 @@ get_first_nonparm_insn ()
   return get_insns ();
 }
 
-/* Return the first NOTE_INSN_BLOCK_BEG note in the function.
-   Crash if there is none.  */
-
-rtx
-get_first_block_beg ()
-{
-  rtx searcher;
-  rtx insn = get_first_nonparm_insn ();
-
-  for (searcher = insn; searcher; searcher = NEXT_INSN (searcher))
-    if (GET_CODE (searcher) == NOTE
-       && NOTE_LINE_NUMBER (searcher) == NOTE_INSN_BLOCK_BEG)
-      return searcher;
-
-  abort ();    /* Invalid call to this function.  (See comments above.)  */
-  return NULL_RTX;
-}
-
 /* Return 1 if EXP is an aggregate type (or a value with aggregate type).
    This means a type for which function calls must pass an address to the
    function or get an address back from the function.
@@ -4316,17 +4362,6 @@ assign_parms (fndecl)
   rtx conversion_insns = 0;
   struct args_size alignment_pad;
 
-  /* Nonzero if the last arg is named `__builtin_va_alist',
-     which is used on some machines for old-fashioned non-ANSI varargs.h;
-     this should be stuck onto the stack as if it had arrived there.  */
-  int hide_last_arg
-    = (current_function_varargs
-       && fnargs
-       && (parm = tree_last (fnargs)) != 0
-       && DECL_NAME (parm)
-       && (! strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
-                    "__builtin_va_alist")));
-
   /* Nonzero if function takes extra anonymous args.
      This means the last named arg must be on the stack
      right before the anonymous ones.  */
@@ -4370,12 +4405,12 @@ assign_parms (fndecl)
     }
 
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
-  parm_reg_stack_loc = (rtx *) xcalloc (max_parm_reg, sizeof (rtx));
+  parm_reg_stack_loc = (rtx *) ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
 
 #ifdef INIT_CUMULATIVE_INCOMING_ARGS
   INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
 #else
-  INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0);
+  INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, fndecl);
 #endif
 
   /* We haven't yet found an argument that we must push and pretend the
@@ -4395,7 +4430,7 @@ assign_parms (fndecl)
 
       /* Set LAST_NAMED if this is last named arg before last
         anonymous args.  */
-      if (stdarg || current_function_varargs)
+      if (stdarg)
        {
          tree tem;
 
@@ -4423,11 +4458,6 @@ assign_parms (fndecl)
          continue;
        }
 
-      /* For varargs.h function, save info about regs and stack space
-        used by the individual args, not including the va_alist arg.  */
-      if (hide_last_arg && last_named)
-       current_function_args_info = args_so_far;
-
       /* Find mode of arg as it is passed, and mode of arg
         as it should be during execution of this function.  */
       passed_mode = TYPE_MODE (passed_type);
@@ -4468,6 +4498,15 @@ assign_parms (fndecl)
          passed_pointer = 1;
          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;
+         passed_pointer = 1;
+         passed_mode = nominal_mode = Pmode;
+       }
 
       promoted_mode = passed_mode;
 
@@ -4552,6 +4591,10 @@ assign_parms (fndecl)
                                                  offset_rtx));
 
        set_mem_attributes (stack_parm, parm, 1);
+
+       /* Set also REG_ATTRS if parameter was passed in a register.  */
+       if (entry_parm)
+         set_reg_attrs_for_parm (entry_parm, stack_parm);
       }
 
       /* If this parameter was passed both in registers and in the stack,
@@ -4575,6 +4618,12 @@ assign_parms (fndecl)
 
          if (nregs > 0)
            {
+#if defined (REG_PARM_STACK_SPACE) && !defined (MAYBE_REG_PARM_STACK_SPACE)
+             /* When REG_PARM_STACK_SPACE is nonzero, stack space for
+                split parameters was allocated by our caller, so we
+                won't be pushing it in the prolog.  */
+             if (REG_PARM_STACK_SPACE (fndecl) == 0)
+#endif
              current_function_pretend_args_size
                = (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
                   / (PARM_BOUNDARY / BITS_PER_UNIT)
@@ -4934,7 +4983,7 @@ assign_parms (fndecl)
                 but it's also rare and we need max_parm_reg to be
                 precisely correct.  */
              max_parm_reg = regno + 1;
-             new = (rtx *) xrealloc (parm_reg_stack_loc,
+             new = (rtx *) ggc_realloc (parm_reg_stack_loc,
                                      max_parm_reg * sizeof (rtx));
              memset ((char *) (new + old_max_parm_reg), 0,
                     (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
@@ -5025,7 +5074,7 @@ assign_parms (fndecl)
                 stack.  So, we go back to that sequence, just so that
                 the fixups will happen.  */
              push_to_sequence (conversion_insns);
-             put_var_into_stack (parm);
+             put_var_into_stack (parm, /*rescan=*/true);
              conversion_insns = get_insns ();
              end_sequence ();
            }
@@ -5079,39 +5128,32 @@ assign_parms (fndecl)
 
          SET_DECL_RTL (parm, stack_parm);
        }
+    }
 
-      /* If this "parameter" was the place where we are receiving the
-        function's incoming structure pointer, set up the result.  */
-      if (parm == function_result_decl)
-       {
-         tree result = DECL_RESULT (fndecl);
-         rtx addr = DECL_RTL (parm);
-         rtx x;
+  /* Output all parameter conversion instructions (possibly including calls)
+     now that all parameters have been copied out of hard registers.  */
+  emit_insn (conversion_insns);
 
+  /* If we are receiving a struct value address as the first argument, set up
+     the RTL for the function result. As this might require code to convert
+     the transmitted address to Pmode, we do this here to ensure that possible
+     preliminary conversions of the address have been emitted already.  */
+  if (function_result_decl)
+    {
+      tree result = DECL_RESULT (fndecl);
+      rtx addr = DECL_RTL (function_result_decl);
+      rtx x;
+      
 #ifdef POINTERS_EXTEND_UNSIGNED
-         if (GET_MODE (addr) != Pmode)
-           addr = convert_memory_address (Pmode, addr);
+      if (GET_MODE (addr) != Pmode)
+       addr = convert_memory_address (Pmode, addr);
 #endif
-
-         x = gen_rtx_MEM (DECL_MODE (result), addr);
-         set_mem_attributes (x, result, 1);
-         SET_DECL_RTL (result, x);
-       }
-
-      if (GET_CODE (DECL_RTL (parm)) == REG)
-       REGNO_DECL (REGNO (DECL_RTL (parm))) = parm;
-      else if (GET_CODE (DECL_RTL (parm)) == CONCAT)
-       {
-         REGNO_DECL (REGNO (XEXP (DECL_RTL (parm), 0))) = parm;
-         REGNO_DECL (REGNO (XEXP (DECL_RTL (parm), 1))) = parm;
-       }
-
+      
+      x = gen_rtx_MEM (DECL_MODE (result), addr);
+      set_mem_attributes (x, result, 1);
+      SET_DECL_RTL (result, x);
     }
 
-  /* Output all parameter conversion instructions (possibly including calls)
-     now that all parameters have been copied out of hard registers.  */
-  emit_insns (conversion_insns);
-
   last_parm_insn = get_last_insn ();
 
   current_function_args_size = stack_args_size.constant;
@@ -5151,8 +5193,7 @@ assign_parms (fndecl)
   /* For stdarg.h function, save info about
      regs and stack space used by the named args.  */
 
-  if (!hide_last_arg)
-    current_function_args_info = args_so_far;
+  current_function_args_info = args_so_far;
 
   /* Set the rtx used for the function return value.  Put this in its
      own variable so any optimizers that need this information don't have
@@ -5242,7 +5283,7 @@ promoted_input_arg (regno, pmode, punsignedp)
    The starting offset and size for this parm are returned in *OFFSET_PTR
    and *ARG_SIZE_PTR, respectively.
 
-   IN_REGS is non-zero if the argument will be passed in registers.  It will
+   IN_REGS is nonzero if the argument will be passed in registers.  It will
    never be set if REG_PARM_STACK_SPACE is not defined.
 
    FNDECL is the function in which the argument was defined.
@@ -5280,6 +5321,9 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
   enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
   int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
+#ifdef ARGS_GROW_DOWNWARD
+  tree s2 = sizetree;
+#endif
 
 #ifdef REG_PARM_STACK_SPACE
   /* If we have found a stack parm before we reach the end of the
@@ -5325,13 +5369,20 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
       offset_ptr->constant = -initial_offset_ptr->constant;
       offset_ptr->var = 0;
     }
+
   if (where_pad != none
       && (!host_integerp (sizetree, 1)
          || (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
-    sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
-  SUB_PARM_SIZE (*offset_ptr, sizetree);
-  if (where_pad != downward)
+    s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
+  SUB_PARM_SIZE (*offset_ptr, s2);
+
+  if (!in_regs
+#ifdef REG_PARM_STACK_SPACE
+      || REG_PARM_STACK_SPACE (fndecl) > 0
+#endif
+     )
     pad_to_arg_alignment (offset_ptr, boundary, alignment_pad);
+
   if (initial_offset_ptr->var)
     arg_size_ptr->var = size_binop (MINUS_EXPR,
                                    size_binop (MINUS_EXPR,
@@ -5343,6 +5394,13 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     arg_size_ptr->constant = (-initial_offset_ptr->constant
                              - offset_ptr->constant);
 
+  /* Pad_below needs the pre-rounded size to know how much to pad below.
+     We only pad parameters which are not in registers as they have their
+     padding done elsewhere.  */
+  if (where_pad == downward
+      && !in_regs)
+    pad_below (offset_ptr, passed_mode, sizetree);
+
 #else /* !ARGS_GROW_DOWNWARD */
   if (!in_regs
 #ifdef REG_PARM_STACK_SPACE
@@ -5428,7 +5486,6 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
     }
 }
 
-#ifndef ARGS_GROW_DOWNWARD
 static void
 pad_below (offset_ptr, passed_mode, sizetree)
      struct args_size *offset_ptr;
@@ -5456,7 +5513,6 @@ pad_below (offset_ptr, passed_mode, sizetree)
        }
     }
 }
-#endif
 \f
 /* Walk the tree of blocks describing the binding levels within a function
    and warn about uninitialized variables.
@@ -5547,7 +5603,7 @@ setjmp_protect (block)
            ||
 #endif
            ! DECL_REGISTER (decl)))
-      put_var_into_stack (decl);
+      put_var_into_stack (decl, /*rescan=*/true);
   for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
     setjmp_protect (sub);
 }
@@ -5574,7 +5630,7 @@ setjmp_protect_args ()
            ||
 #endif
            ! DECL_REGISTER (decl)))
-      put_var_into_stack (decl);
+      put_var_into_stack (decl, /*rescan=*/true);
 }
 \f
 /* Return the context-pointer register corresponding to DECL,
@@ -5733,12 +5789,8 @@ trampoline_address (function)
 #else
   /* If rounding needed, allocate extra space
      to ensure we have TRAMPOLINE_SIZE bytes left after rounding up.  */
-#ifdef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_REAL_SIZE \
   (TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1)
-#else
-#define TRAMPOLINE_REAL_SIZE (TRAMPOLINE_SIZE)
-#endif
   tramp = assign_stack_local_1 (BLKmode, TRAMPOLINE_REAL_SIZE, 0,
                                fp ? fp : cfun);
 #endif
@@ -5773,7 +5825,6 @@ static rtx
 round_trampoline_addr (tramp)
      rtx tramp;
 {
-#ifdef TRAMPOLINE_ALIGNMENT
   /* Round address up to desired boundary.  */
   rtx temp = gen_reg_rtx (Pmode);
   rtx addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
@@ -5783,7 +5834,7 @@ round_trampoline_addr (tramp)
                               temp, 0, OPTAB_LIB_WIDEN);
   tramp = expand_simple_binop (Pmode, AND, temp, mask,
                               temp, 0, OPTAB_LIB_WIDEN);
-#endif
+
   return tramp;
 }
 
@@ -5936,8 +5987,6 @@ reorder_blocks ()
 
   /* Remove deleted blocks from the block fragment chains.  */
   reorder_fix_fragments (block);
-
-  VARRAY_FREE (block_stack);
 }
 
 /* Helper function for reorder_blocks.  Reset TREE_ASM_WRITTEN.  */
@@ -5991,10 +6040,16 @@ reorder_blocks_1 (insns, current_block, p_block_stack)
 
              BLOCK_SUBBLOCKS (block) = 0;
              TREE_ASM_WRITTEN (block) = 1;
-             BLOCK_SUPERCONTEXT (block) = current_block;
-             BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
-             BLOCK_SUBBLOCKS (current_block) = block;
-             current_block = block;
+             /* When there's only one block for the entire function,
+                current_block == block and we mustn't do this, it
+                will cause infinite recursion.  */
+             if (block != current_block)
+               {
+                 BLOCK_SUPERCONTEXT (block) = current_block;
+                 BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
+                 BLOCK_SUBBLOCKS (current_block) = block;
+                 current_block = block;
+               }
              VARRAY_PUSH_TREE (*p_block_stack, block);
            }
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
@@ -6142,7 +6197,7 @@ get_block_vector (block, n_blocks_p)
   return block_vector;
 }
 
-static int next_block_index = 2;
+static GTY(()) int next_block_index = 2;
 
 /* Set BLOCK_NUMBER for all the blocks in FN.  */
 
@@ -6260,6 +6315,8 @@ prepare_function_start ()
   current_function_calls_longjmp = 0;
 
   current_function_calls_alloca = 0;
+  current_function_calls_eh_return = 0;
+  current_function_calls_constant_p = 0;
   current_function_contains_functions = 0;
   current_function_is_leaf = 0;
   current_function_nothrow = 0;
@@ -6306,8 +6363,7 @@ prepare_function_start ()
   /* Indicate we have no need of a frame pointer yet.  */
   frame_pointer_needed = 0;
 
-  /* By default assume not varargs or stdarg.  */
-  current_function_varargs = 0;
+  /* By default assume not stdarg.  */
   current_function_stdarg = 0;
 
   /* We haven't made any trampolines for this function yet.  */
@@ -6318,15 +6374,17 @@ prepare_function_start ()
 
   current_function_outgoing_args_size = 0;
 
-  cfun->arc_profile = profile_arc_flag || flag_test_coverage;
+  current_function_funcdef_no = funcdef_no++;
 
   cfun->arc_profile = profile_arc_flag || flag_test_coverage;
 
   cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
 
+  cfun->max_jumptable_ents = 0;
+
   (*lang_hooks.function.init) (cfun);
   if (init_machine_status)
-    (*init_machine_status) (cfun);
+    cfun->machine = (*init_machine_status) ();
 }
 
 /* Initialize the rtl expansion mechanism so that we can do simple things
@@ -6405,15 +6463,6 @@ init_function_for_compilation ()
   VARRAY_GROW (sibcall_epilogue, 0);
 }
 
-/* Indicate that the current function uses extra args
-   not explicitly mentioned in the argument list in any fashion.  */
-
-void
-mark_varargs ()
-{
-  current_function_varargs = 1;
-}
-
 /* Expand a call to __main at the beginning of a possible main function.  */
 
 #if defined(INIT_SECTION_ASM_OP) && !defined(INVOKE__main)
@@ -6447,7 +6496,7 @@ expand_main_function ()
       /* Enlist allocate_dynamic_stack_space to pick up the pieces.  */
       tmp = force_reg (Pmode, const0_rtx);
       allocate_dynamic_stack_space (tmp, NULL_RTX, BIGGEST_ALIGNMENT);
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
 
       for (tmp = get_last_insn (); tmp; tmp = PREV_INSN (tmp))
@@ -6461,13 +6510,10 @@ expand_main_function ()
 #endif
 
 #ifndef HAS_INIT_SECTION
-  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), LCT_NORMAL,
-                    VOIDmode, 0);
+  emit_library_call (init_one_libfunc (NAME__MAIN), LCT_NORMAL, VOIDmode, 0);
 #endif
 }
 \f
-extern struct obstack permanent_obstack;
-
 /* 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
@@ -6596,18 +6642,17 @@ expand_function_start (subr, parms_have_cleanups)
                               subr, 1);
 
       /* Structures that are returned in registers are not aggregate_value_p,
-        so we may see a PARALLEL.  Don't play pseudo games with this.  */
-      if (! REG_P (hard_reg))
-       SET_DECL_RTL (DECL_RESULT (subr), hard_reg);
+        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));
       else
-       {
-         /* Create the pseudo.  */
-         SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+       abort ();
 
-         /* Needed because we may need to move this to memory
-            in case it's a named return value whose address is taken.  */
-         DECL_REGISTER (DECL_RESULT (subr)) = 1;
-       }
+      /* Set DECL_REGISTER flag so that expand_function_end will copy the
+        result to the real return register(s).  */
+      DECL_REGISTER (DECL_RESULT (subr)) = 1;
     }
 
   /* Initialize rtx for parameters and local variables.
@@ -6695,9 +6740,8 @@ expand_function_start (subr, parms_have_cleanups)
 
   if (current_function_profile)
     {
-      current_function_profile_label_no = profile_label_no++;
 #ifdef PROFILE_HOOK
-      PROFILE_HOOK (current_function_profile_label_no);
+      PROFILE_HOOK (current_function_funcdef_no);
 #endif
     }
 
@@ -6797,6 +6841,8 @@ use_return_register ()
   diddle_return_value (do_use_return_reg, NULL);
 }
 
+static GTY(()) rtx initial_trampoline;
+
 /* Generate RTL for the end of the current function.
    FILENAME and LINE are the current position in the source file.
 
@@ -6812,10 +6858,6 @@ expand_function_end (filename, line, end_bindings)
   tree link;
   rtx clobber_after;
 
-#ifdef TRAMPOLINE_TEMPLATE
-  static rtx initial_trampoline;
-#endif
-
   finish_expr_for_function ();
 
   /* If arg_pointer_save_area was referenced only from a nested
@@ -6854,8 +6896,6 @@ expand_function_end (filename, line, end_bindings)
          initial_trampoline
            = gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
          set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
-
-         ggc_add_rtx_root (&initial_trampoline, 1);
        }
 #endif
 
@@ -6865,14 +6905,14 @@ expand_function_end (filename, line, end_bindings)
 #ifdef TRAMPOLINE_TEMPLATE
       blktramp = replace_equiv_address (initial_trampoline, tramp);
       emit_block_move (blktramp, initial_trampoline,
-                      GEN_INT (TRAMPOLINE_SIZE));
+                      GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
 #endif
       INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
       seq = get_insns ();
       end_sequence ();
 
       /* Put those insns at entry to the containing function (this one).  */
-      emit_insns_before (seq, tail_recursion_reentry);
+      emit_insn_before (seq, tail_recursion_reentry);
     }
 
   /* If we are doing stack checking and this function makes calls,
@@ -6890,15 +6930,16 @@ expand_function_end (filename, line, end_bindings)
                               GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
            seq = get_insns ();
            end_sequence ();
-           emit_insns_before (seq, tail_recursion_reentry);
+           emit_insn_before (seq, tail_recursion_reentry);
            break;
          }
     }
 
   /* Warn about unused parms if extra warnings were specified.  */
-  /* Either ``-W -Wunused'' or ``-Wunused-parameter'' enables this
+  /* Either ``-Wextra -Wunused'' or ``-Wunused-parameter'' enables this
      warning.  WARN_UNUSED_PARAMETER is negative when set by
-     -Wunused.  */
+     -Wunused.  Note that -Wall implies -Wunused, so ``-Wall -Wextra'' will
+     also give these warnings.  */
   if (warn_unused_parameter > 0
       || (warn_unused_parameter < 0 && extra_warnings))
     {
@@ -7040,8 +7081,16 @@ expand_function_end (filename, line, end_bindings)
              convert_move (real_decl_rtl, decl_rtl, unsignedp);
            }
          else if (GET_CODE (real_decl_rtl) == PARALLEL)
-           emit_group_load (real_decl_rtl, decl_rtl,
-                            int_size_in_bytes (TREE_TYPE (decl_result)));
+           {
+             /* If expand_function_start has created a PARALLEL for decl_rtl,
+                move the result to the real return registers.  Otherwise, do
+                a group load from decl_rtl for a named return.  */
+             if (GET_CODE (decl_rtl) == PARALLEL)
+               emit_group_move (real_decl_rtl, decl_rtl);
+             else
+               emit_group_load (real_decl_rtl, decl_rtl,
+                                int_size_in_bytes (TREE_TYPE (decl_result)));
+           }
          else
            emit_move_insn (real_decl_rtl, decl_rtl);
        }
@@ -7096,7 +7145,7 @@ expand_function_end (filename, line, end_bindings)
 
     start_sequence ();
     clobber_return_register ();
-    seq = gen_sequence ();
+    seq = get_insns ();
     end_sequence ();
 
     after = emit_insn_after (seq, clobber_after);
@@ -7142,7 +7191,7 @@ get_arg_pointer_save_area (f)
         have to check it and fix it if necessary.  */
       start_sequence ();
       emit_move_insn (validize_mem (ret), virtual_incoming_args_rtx);
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
 
       push_topmost_sequence ();
@@ -7153,35 +7202,38 @@ get_arg_pointer_save_area (f)
   return ret;
 }
 \f
-/* Extend a vector that records the INSN_UIDs of INSNS (either a
-   sequence or a single insn).  */
+/* Extend a vector that records the INSN_UIDs of INSNS
+   (a list of one or more insns).  */
 
 static void
 record_insns (insns, vecp)
      rtx insns;
      varray_type *vecp;
 {
-  if (GET_CODE (insns) == SEQUENCE)
-    {
-      int len = XVECLEN (insns, 0);
-      int i = VARRAY_SIZE (*vecp);
+  int i, len;
+  rtx tmp;
 
-      VARRAY_GROW (*vecp, i + len);
-      while (--len >= 0)
-       {
-         VARRAY_INT (*vecp, i) = INSN_UID (XVECEXP (insns, 0, len));
-         ++i;
-       }
+  tmp = insns;
+  len = 0;
+  while (tmp != NULL_RTX)
+    {
+      len++;
+      tmp = NEXT_INSN (tmp);
     }
-  else
+
+  i = VARRAY_SIZE (*vecp);
+  VARRAY_GROW (*vecp, i + len);
+  tmp = insns;
+  while (tmp != NULL_RTX)
     {
-      int i = VARRAY_SIZE (*vecp);
-      VARRAY_GROW (*vecp, i + 1);
-      VARRAY_INT (*vecp, i) = INSN_UID (insns);
+      VARRAY_INT (*vecp, i) = INSN_UID (tmp);
+      i++;
+      tmp = NEXT_INSN (tmp);
     }
 }
 
-/* Determine how many INSN_UIDs in VEC are part of INSN.  */
+/* Determine how many INSN_UIDs in VEC are part of INSN.  Because we can
+   be running after reorg, SEQUENCE rtl is possible.  */
 
 static int
 contains (insn, vec)
@@ -7238,10 +7290,7 @@ emit_return_into_block (bb, line_note)
      basic_block bb;
      rtx line_note;
 {
-  rtx p, end;
-
-  p = NEXT_INSN (bb->end);
-  end = emit_jump_insn_after (gen_return (), bb->end);
+  emit_jump_insn_after (gen_return (), bb->end);
   if (line_note)
     emit_line_note_after (NOTE_SOURCE_FILE (line_note),
                          NOTE_LINE_NUMBER (line_note), PREV_INSN (bb->end));
@@ -7293,20 +7342,21 @@ struct epi_info
 static void handle_epilogue_set PARAMS ((rtx, struct epi_info *));
 static void emit_equiv_load PARAMS ((struct epi_info *));
 
-/* Modify SEQ, a SEQUENCE that is part of the epilogue, to no modifications
-   to the stack pointer.  Return the new sequence.  */
+/* Modify INSN, a list of one or more insns that is part of the epilogue, to
+   no modifications to the stack pointer.  Return the new list of insns.  */
 
 static rtx
-keep_stack_depressed (seq)
-     rtx seq;
+keep_stack_depressed (insns)
+     rtx insns;
 {
-  int i, j;
+  int j;
   struct epi_info info;
+  rtx insn, next;
 
   /* If the epilogue is just a single instruction, it ust be OK as is.  */
 
-  if (GET_CODE (seq) != SEQUENCE)
-    return seq;
+  if (NEXT_INSN (insns) == NULL_RTX)
+    return insns;
 
   /* Otherwise, start a sequence, initialize the information we have, and
      process all the insns we were given.  */
@@ -7316,13 +7366,16 @@ keep_stack_depressed (seq)
   info.sp_offset = 0;
   info.equiv_reg_src = 0;
 
-  for (i = 0; i < XVECLEN (seq, 0); i++)
+  insn = insns;
+  next = NULL_RTX;
+  while (insn != NULL_RTX)
     {
-      rtx insn = XVECEXP (seq, 0, i);
+      next = NEXT_INSN (insn);
 
       if (!INSN_P (insn))
        {
          add_insn (insn);
+         insn = next;
          continue;
        }
 
@@ -7358,6 +7411,7 @@ keep_stack_depressed (seq)
            {
              emit_equiv_load (&info);
              add_insn (insn);
+             insn = next;
              continue;
            }
          else if (GET_CODE (retaddr) == MEM
@@ -7458,11 +7512,13 @@ keep_stack_depressed (seq)
 
       info.sp_equiv_reg = info.new_sp_equiv_reg;
       info.sp_offset = info.new_sp_offset;
+
+      insn = next;
     }
 
-  seq = gen_sequence ();
+  insns = get_insns ();
   end_sequence ();
-  return seq;
+  return insns;
 }
 
 /* SET is a SET from an insn in the epilogue.  P is a pointer to the epi_info
@@ -7577,12 +7633,10 @@ thread_prologue_and_epilogue_insns (f)
       emit_insn (seq);
 
       /* Retain a map of the prologue insns.  */
-      if (GET_CODE (seq) != SEQUENCE)
-       seq = get_insns ();
       record_insns (seq, &prologue);
       prologue_end = emit_note (NULL, NOTE_INSN_PROLOGUE_END);
 
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
 
       /* Can't deal with multiple successors of the entry block
@@ -7673,19 +7727,8 @@ thread_prologue_and_epilogue_insns (f)
                 that with a conditional return instruction.  */
              else if (condjump_p (jump))
                {
-                 rtx ret, *loc;
-
-                 ret = SET_SRC (PATTERN (jump));
-                 if (GET_CODE (XEXP (ret, 1)) == LABEL_REF)
-                   loc = &XEXP (ret, 1);
-                 else
-                   loc = &XEXP (ret, 2);
-                 ret = gen_rtx_RETURN (VOIDmode);
-
-                 if (! validate_change (jump, loc, ret, 0))
+                 if (! redirect_jump (jump, 0, 0))
                    continue;
-                 if (JUMP_LABEL (jump))
-                   LABEL_NUSES (JUMP_LABEL (jump))--;
 
                  /* If this block has only one successor, it both jumps
                     and falls through to the fallthru block, so we can't
@@ -7741,11 +7784,9 @@ thread_prologue_and_epilogue_insns (f)
       emit_jump_insn (seq);
 
       /* Retain a map of the epilogue insns.  */
-      if (GET_CODE (seq) != SEQUENCE)
-       seq = get_insns ();
       record_insns (seq, &epilogue);
 
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
 
       insert_insn_on_edge (seq, e);
@@ -7771,16 +7812,17 @@ epilogue_done:
        continue;
 
       start_sequence ();
-      seq = gen_sibcall_epilogue ();
+      emit_insn (gen_sibcall_epilogue ());
+      seq = get_insns ();
       end_sequence ();
 
+      /* Retain a map of the epilogue insns.  Used in life analysis to
+        avoid getting rid of sibcall epilogue insns.  Do this before we
+        actually emit the sequence.  */
+      record_insns (seq, &sibcall_epilogue);
+
       i = PREV_INSN (insn);
       newinsn = emit_insn_before (seq, insn);
-
-      /* Retain a map of the epilogue insns.  Used in life analysis to
-        avoid getting rid of sibcall epilogue insns.  */
-      record_insns (GET_CODE (seq) == SEQUENCE
-                   ? seq : newinsn, &sibcall_epilogue);
     }
 #endif
 
@@ -7796,7 +7838,7 @@ epilogue_done:
         note before the end of the first basic block, if there isn't
         one already there.
 
-        ??? This behaviour is completely broken when dealing with
+        ??? This behavior is completely broken when dealing with
         multiple entry functions.  We simply place the note always
         into first basic block and let alternate entry points
         to be missed.
@@ -7893,8 +7935,6 @@ reposition_prologue_and_epilogue_notes (f)
 
       if (last)
        {
-         rtx next;
-
          /* Find the prologue-end note if we haven't already, and
             move it to just after the last prologue insn.  */
          if (note == 0)
@@ -7905,8 +7945,6 @@ reposition_prologue_and_epilogue_notes (f)
                  break;
            }
 
-         next = NEXT_INSN (note);
-
          /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note.  */
          if (GET_CODE (last) == CODE_LABEL)
            last = NEXT_INSN (last);
@@ -7955,121 +7993,14 @@ reposition_prologue_and_epilogue_notes (f)
 #endif /* HAVE_prologue or HAVE_epilogue */
 }
 
-/* Mark P for GC.  */
-
-static void
-mark_function_status (p)
-     struct function *p;
-{
-  struct var_refs_queue *q;
-  struct temp_slot *t;
-  int i;
-  rtx *r;
-
-  if (p == 0)
-    return;
-
-  ggc_mark_rtx (p->arg_offset_rtx);
-
-  if (p->x_parm_reg_stack_loc)
-    for (i = p->x_max_parm_reg, r = p->x_parm_reg_stack_loc;
-        i > 0; --i, ++r)
-      ggc_mark_rtx (*r);
-
-  ggc_mark_rtx (p->return_rtx);
-  ggc_mark_rtx (p->x_cleanup_label);
-  ggc_mark_rtx (p->x_return_label);
-  ggc_mark_rtx (p->x_save_expr_regs);
-  ggc_mark_rtx (p->x_stack_slot_list);
-  ggc_mark_rtx (p->x_parm_birth_insn);
-  ggc_mark_rtx (p->x_tail_recursion_label);
-  ggc_mark_rtx (p->x_tail_recursion_reentry);
-  ggc_mark_rtx (p->internal_arg_pointer);
-  ggc_mark_rtx (p->x_arg_pointer_save_area);
-  ggc_mark_tree (p->x_rtl_expr_chain);
-  ggc_mark_rtx (p->x_last_parm_insn);
-  ggc_mark_tree (p->x_context_display);
-  ggc_mark_tree (p->x_trampoline_list);
-  ggc_mark_rtx (p->epilogue_delay_list);
-  ggc_mark_rtx (p->x_clobber_return_insn);
-
-  for (t = p->x_temp_slots; t != 0; t = t->next)
-    {
-      ggc_mark (t);
-      ggc_mark_rtx (t->slot);
-      ggc_mark_rtx (t->address);
-      ggc_mark_tree (t->rtl_expr);
-      ggc_mark_tree (t->type);
-    }
-
-  for (q = p->fixup_var_refs_queue; q != 0; q = q->next)
-    {
-      ggc_mark (q);
-      ggc_mark_rtx (q->modified);
-    }
-
-  ggc_mark_rtx (p->x_nonlocal_goto_handler_slots);
-  ggc_mark_rtx (p->x_nonlocal_goto_handler_labels);
-  ggc_mark_rtx (p->x_nonlocal_goto_stack_level);
-  ggc_mark_tree (p->x_nonlocal_labels);
-
-  mark_hard_reg_initial_vals (p);
-}
-
-/* Mark the struct function pointed to by *ARG for GC, if it is not
-   NULL.  This is used to mark the current function and the outer
-   function chain.  */
-
-static void
-maybe_mark_struct_function (arg)
-     void *arg;
-{
-  struct function *f = *(struct function **) arg;
-
-  if (f == 0)
-    return;
-
-  ggc_mark_struct_function (f);
-}
-
-/* Mark a struct function * for GC.  This is called from ggc-common.c.  */
-
-void
-ggc_mark_struct_function (f)
-     struct function *f;
-{
-  ggc_mark (f);
-  ggc_mark_tree (f->decl);
-
-  mark_function_status (f);
-  mark_eh_status (f->eh);
-  mark_stmt_status (f->stmt);
-  mark_expr_status (f->expr);
-  mark_emit_status (f->emit);
-  mark_varasm_status (f->varasm);
-
-  if (mark_machine_status)
-    (*mark_machine_status) (f);
-  (*lang_hooks.function.mark) (f);
-
-  if (f->original_arg_vector)
-    ggc_mark_rtvec ((rtvec) f->original_arg_vector);
-  if (f->original_decl_initial)
-    ggc_mark_tree (f->original_decl_initial);
-  if (f->outer)
-    ggc_mark_struct_function (f->outer);
-}
-
 /* Called once, at initialization, to initialize function.c.  */
 
 void
 init_function_once ()
 {
-  ggc_add_root (&cfun, 1, sizeof cfun, maybe_mark_struct_function);
-  ggc_add_root (&outer_function_chain, 1, sizeof outer_function_chain,
-               maybe_mark_struct_function);
-
   VARRAY_INT_INIT (prologue, 0, "prologue");
   VARRAY_INT_INIT (epilogue, 0, "epilogue");
   VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue");
 }
+
+#include "gt-function.h"