OSDN Git Service

2004-03-01 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 51beeef..623f78c 100644 (file)
@@ -1,6 +1,6 @@
-/* Expands front end tree to back end RTL for GNU C-Compiler
+/* 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 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -40,12 +40,15 @@ 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"
 #include "except.h"
 #include "function.h"
 #include "expr.h"
+#include "optabs.h"
 #include "libfuncs.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -53,12 +56,13 @@ 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"
+#include "langhooks.h"
+#include "target.h"
 
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
@@ -68,13 +72,18 @@ 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
+
+#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
+
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
    give the same symbol without quotes for an alternative entry point.  You
    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
@@ -123,21 +132,15 @@ int current_function_uses_only_leaf_regs;
    post-instantiation libcalls.  */
 int virtuals_instantiated;
 
+/* Nonzero if at least one trampoline has been created.  */
+int trampolines_created;
+
+/* 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 *));
-
-/* Likewise, but for language-specific data.  */
-void (*init_lang_status) PARAMS ((struct function *));
-void (*save_lang_status) PARAMS ((struct function *));
-void (*restore_lang_status) PARAMS ((struct function *));
-void (*mark_lang_status) PARAMS ((struct function *));
-void (*free_lang_status) PARAMS ((struct function *));
+struct machine_function * (*init_machine_status) (void);
 
 /* The FUNCTION_DECL for an inline function currently being expanded.  */
 tree inline_function_decl;
@@ -146,12 +149,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.
@@ -171,7 +174,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;
@@ -181,7 +184,7 @@ struct temp_slot
      slot above.  May be an EXPR_LIST if multiple addresses exist.  */
   rtx address;
   /* The alignment (in bits) of the slot.  */
-  int align;
+  unsigned int align;
   /* The size, in units, of the slot.  */
   HOST_WIDE_INT size;
   /* The type of the object in the slot, or zero if it doesn't correspond
@@ -191,13 +194,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.  */
@@ -212,7 +215,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;
@@ -221,101 +224,87 @@ 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;
 };
 
 /* Forward declarations.  */
 
-static rtx assign_stack_local_1 PARAMS ((enum machine_mode, HOST_WIDE_INT,
-                                        int, struct function *));
-static rtx assign_stack_temp_for_type PARAMS ((enum machine_mode,
-                                              HOST_WIDE_INT, int, tree));
-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 *));
-static void schedule_fixup_var_refs PARAMS ((struct function *, rtx, tree,
-                                            enum machine_mode,
-                                            struct hash_table *));
-static void fixup_var_refs     PARAMS ((rtx, enum machine_mode, int,
-                                        struct hash_table *));
+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 put_reg_into_stack (struct function *, rtx, tree, enum machine_mode,
+                               enum machine_mode, int, unsigned int, int, htab_t);
+static void schedule_fixup_var_refs (struct function *, rtx, tree, enum machine_mode,
+                                    htab_t);
+static void fixup_var_refs (rtx, enum machine_mode, int, rtx, 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));
-static void fixup_var_refs_insns_with_hash
-                               PARAMS ((struct hash_table *, rtx,
-                                        enum machine_mode, int));
-static void fixup_var_refs_insn PARAMS ((rtx, rtx, enum machine_mode,
-                                        int, int));
-static void fixup_var_refs_1   PARAMS ((rtx, enum machine_mode, rtx *, rtx,
-                                        struct fixup_replacement **));
-static rtx fixup_memory_subreg PARAMS ((rtx, rtx, int));
-static rtx walk_fixup_memory_subreg  PARAMS ((rtx, rtx, int));
-static rtx fixup_stack_1       PARAMS ((rtx, rtx));
-static void optimize_bit_field PARAMS ((rtx, rtx, rtx *));
-static void instantiate_decls  PARAMS ((tree, int));
-static void instantiate_decls_1        PARAMS ((tree, int));
-static void instantiate_decl   PARAMS ((rtx, HOST_WIDE_INT, int));
-static rtx instantiate_new_reg PARAMS ((rtx, HOST_WIDE_INT *));
-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 *));
-static void reorder_blocks_0   PARAMS ((tree));
-static void reorder_blocks_1   PARAMS ((rtx, tree, varray_type *));
-static void reorder_fix_fragments PARAMS ((tree));
-static tree blocks_nreverse    PARAMS ((tree));
-static int all_blocks          PARAMS ((tree, tree *));
-static tree *get_block_vector   PARAMS ((tree, int *));
-/* We always define `record_insns' even if its not used so that we
+  *find_fixup_replacement (struct fixup_replacement **, rtx);
+static void fixup_var_refs_insns (rtx, rtx, enum machine_mode, int, int, rtx);
+static void fixup_var_refs_insns_with_hash (htab_t, rtx, enum machine_mode, int, rtx);
+static void fixup_var_refs_insn (rtx, rtx, enum machine_mode, int, int, rtx);
+static void fixup_var_refs_1 (rtx, enum machine_mode, rtx *, rtx,
+                             struct fixup_replacement **, rtx);
+static rtx fixup_memory_subreg (rtx, rtx, enum machine_mode, int);
+static rtx walk_fixup_memory_subreg (rtx, rtx, enum machine_mode, int);
+static rtx fixup_stack_1 (rtx, rtx);
+static void optimize_bit_field (rtx, rtx, 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 delete_handlers (void);
+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 rtx round_trampoline_addr (rtx);
+static rtx adjust_trampoline_addr (rtx);
+static tree *identify_blocks_1 (rtx, tree *, tree *, tree *);
+static void reorder_blocks_0 (tree);
+static void reorder_blocks_1 (rtx, tree, varray_type *);
+static void reorder_fix_fragments (tree);
+static tree blocks_nreverse (tree);
+static int all_blocks (tree, tree *);
+static tree *get_block_vector (tree, int *);
+extern tree debug_find_var_in_block_tree (tree, tree);
+/* We always define `record_insns' even if it's not used so that we
    can always export `prologue_epilogue_contains'.  */
-static void record_insns       PARAMS ((rtx, varray_type *)) ATTRIBUTE_UNUSED;
-static int contains            PARAMS ((rtx, varray_type));
+static void record_insns (rtx, varray_type *) ATTRIBUTE_UNUSED;
+static int contains (rtx, varray_type);
 #ifdef HAVE_return
-static void emit_return_into_block PARAMS ((basic_block, rtx));
+static void emit_return_into_block (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 purge_single_hard_subreg_set PARAMS ((rtx));
-#ifdef HAVE_epilogue
-static void keep_stack_depressed PARAMS ((rtx));
+static void put_addressof_into_stack (rtx, htab_t);
+static bool purge_addressof_1 (rtx *, rtx, int, int, int, htab_t);
+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 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 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 prepare_function_start PARAMS ((void));
-static void do_clobber_return_reg PARAMS ((rtx, void *));
-static void do_use_return_reg PARAMS ((rtx, void *));
+static int is_addressof (rtx *, void *);
+static hashval_t insns_for_mem_hash (const void *);
+static int insns_for_mem_comp (const void *, const void *);
+static int insns_for_mem_walk (rtx *, void *);
+static void compute_insns_for_mem (rtx, rtx, htab_t);
+static void prepare_function_start (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 tree split_complex_args (tree);
+static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED;
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
-static struct function *outer_function_chain;
+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.  */
 
 struct function *
-find_function_data (decl)
-     tree decl;
+find_function_data (tree decl)
 {
   struct function *p;
 
@@ -328,13 +317,12 @@ find_function_data (decl)
 
 /* Save the current context for compilation of a nested function.
    This is called from language-specific code.  The caller should use
-   the save_lang_status callback to save any language-specific state,
+   the enter_nested langhook to save any language-specific state,
    since this function knows only about language-independent
    variables.  */
 
 void
-push_function_context_to (context)
-     tree context;
+push_function_context_to (tree context)
 {
   struct function *p;
 
@@ -357,14 +345,13 @@ push_function_context_to (context)
   outer_function_chain = p;
   p->fixup_var_refs_queue = 0;
 
-  if (save_lang_status)
-    (*save_lang_status) (p);
+  (*lang_hooks.function.enter_nested) (p);
 
   cfun = 0;
 }
 
 void
-push_function_context ()
+push_function_context (void)
 {
   push_function_context_to (current_function_decl);
 }
@@ -373,8 +360,7 @@ push_function_context ()
    This function is called from language-specific code.  */
 
 void
-pop_function_context_from (context)
-     tree context ATTRIBUTE_UNUSED;
+pop_function_context_from (tree context ATTRIBUTE_UNUSED)
 {
   struct function *p = outer_function_chain;
   struct var_refs_queue *queue;
@@ -386,16 +372,32 @@ pop_function_context_from (context)
   reg_renumber = 0;
 
   restore_emit_status (p);
-  restore_varasm_status (p);
 
-  if (restore_lang_status)
-    (*restore_lang_status) (p);
+  (*lang_hooks.function.leave_nested) (p);
+
+  /* Finish doing put_var_into_stack for any of our variables which became
+     addressable during the nested function.  If only one entry has to be
+     fixed up, just do that one.  Otherwise, first make a list of MEMs that
+     are not to be unshared.  */
+  if (p->fixup_var_refs_queue == 0)
+    ;
+  else if (p->fixup_var_refs_queue->next == 0)
+    fixup_var_refs (p->fixup_var_refs_queue->modified,
+                   p->fixup_var_refs_queue->promoted_mode,
+                   p->fixup_var_refs_queue->unsignedp,
+                   p->fixup_var_refs_queue->modified, 0);
+  else
+    {
+      rtx list = 0;
+
+      for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
+       list = gen_rtx_EXPR_LIST (VOIDmode, queue->modified, list);
 
-  /* Finish doing put_var_into_stack for any of our variables
-     which became addressable during the nested function.  */
-  for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
-    fixup_var_refs (queue->modified, queue->promoted_mode,
-                   queue->unsignedp, 0);
+      for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
+       fixup_var_refs (queue->modified, queue->promoted_mode,
+                       queue->unsignedp, list, 0);
+
+    }
 
   p->fixup_var_refs_queue = 0;
 
@@ -406,7 +408,7 @@ pop_function_context_from (context)
 }
 
 void
-pop_function_context ()
+pop_function_context (void)
 {
   pop_function_context_from (current_function_decl);
 }
@@ -416,17 +418,15 @@ pop_function_context ()
    garbage collection reclaim the memory.  */
 
 void
-free_after_parsing (f)
-     struct function *f;
+free_after_parsing (struct function *f)
 {
   /* f->expr->forced_labels is used by code generation.  */
   /* f->emit->regno_reg_rtx is used by code generation.  */
   /* f->varasm is used by code generation.  */
   /* f->eh->eh_return_stub_label is used by code generation.  */
 
-  if (free_lang_status)
-    (*free_lang_status) (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
@@ -434,19 +434,13 @@ free_after_parsing (f)
    reclaim the memory.  */
 
 void
-free_after_compilation (f)
-     struct function *f;
+free_after_compilation (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;
@@ -458,6 +452,9 @@ free_after_compilation (f)
   f->x_nonlocal_goto_stack_level = NULL;
   f->x_cleanup_label = NULL;
   f->x_return_label = NULL;
+  f->x_naked_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;
@@ -485,8 +482,7 @@ free_after_compilation (f)
    the caller may have to do that.  */
 
 HOST_WIDE_INT
-get_func_frame_size (f)
-     struct function *f;
+get_func_frame_size (struct function *f)
 {
 #ifdef FRAME_GROWS_DOWNWARD
   return -f->x_frame_offset;
@@ -499,7 +495,7 @@ get_func_frame_size (f)
    This size counts from zero.  It is not rounded to PREFERRED_STACK_BOUNDARY;
    the caller may have to do that.  */
 HOST_WIDE_INT
-get_frame_size ()
+get_frame_size (void)
 {
   return get_func_frame_size (cfun);
 }
@@ -517,15 +513,13 @@ get_frame_size ()
    FUNCTION specifies the function to allocate in.  */
 
 static rtx
-assign_stack_local_1 (mode, size, align, function)
-     enum machine_mode mode;
-     HOST_WIDE_INT size;
-     int align;
-     struct function *function;
+assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align,
+                     struct function *function)
 {
   rtx x, addr;
   int bigend_correction = 0;
   int alignment;
+  int frame_off, frame_alignment, frame_phase;
 
   if (align == 0)
     {
@@ -538,7 +532,7 @@ assign_stack_local_1 (mode, size, align, function)
 
       /* Allow the target to (possibly) increase the alignment of this
         stack slot.  */
-      type = type_for_mode (mode, 0);
+      type = (*lang_hooks.types.type_for_mode) (mode, 0);
       if (type)
        alignment = LOCAL_ALIGNMENT (type, alignment);
 
@@ -563,16 +557,33 @@ assign_stack_local_1 (mode, size, align, function)
   if (function->stack_alignment_needed < alignment * BITS_PER_UNIT)
     function->stack_alignment_needed = alignment * BITS_PER_UNIT;
 
-  /* 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.  */
+  /* Calculate how many bytes the start of local variables is off from
+     stack alignment.  */
+  frame_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+  frame_off = STARTING_FRAME_OFFSET % frame_alignment;
+  frame_phase = frame_off ? frame_alignment - frame_off : 0;
+
+  /* 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, alignment);
+      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, alignment);
+      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.  */
@@ -583,11 +594,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;
@@ -605,10 +619,7 @@ assign_stack_local_1 (mode, size, align, function)
    current function.  */
 
 rtx
-assign_stack_local (mode, size, align)
-     enum machine_mode mode;
-     HOST_WIDE_INT size;
-     int align;
+assign_stack_local (enum machine_mode mode, HOST_WIDE_INT size, int align)
 {
   return assign_stack_local_1 (mode, size, align, cfun);
 }
@@ -630,15 +641,13 @@ assign_stack_local (mode, size, align)
 
    TYPE is the type that will be used for the stack slot.  */
 
-static rtx
-assign_stack_temp_for_type (mode, size, keep, type)
-     enum machine_mode mode;
-     HOST_WIDE_INT size;
-     int keep;
-     tree type;
+rtx
+assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep,
+                           tree type)
 {
-  int align;
+  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.  */
@@ -651,7 +660,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
     align = GET_MODE_ALIGNMENT (mode);
 
   if (! type)
-    type = type_for_mode (mode, 0);
+    type = (*lang_hooks.types.type_for_mode) (mode, 0);
 
   if (type)
     align = LOCAL_ALIGNMENT (type, align);
@@ -687,7 +696,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
 
          if (best_p->size - rounded_size >= alignment)
            {
-             p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
+             p = ggc_alloc (sizeof (struct temp_slot));
              p->in_use = p->addr_taken = 0;
              p->size = best_p->size - rounded_size;
              p->base_offset = best_p->base_offset + rounded_size;
@@ -718,7 +727,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
     {
       HOST_WIDE_INT frame_offset_old = frame_offset;
 
-      p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
+      p = ggc_alloc (sizeof (struct temp_slot));
 
       /* We are passing an explicit alignment request to assign_stack_local.
         One side effect of that is assign_stack_local will not round SIZE
@@ -728,10 +737,10 @@ assign_stack_temp_for_type (mode, size, keep, type)
         and round it now.  We also make sure ALIGNMENT is at least
         BIGGEST_ALIGNMENT.  */
       if (mode == BLKmode && align < BIGGEST_ALIGNMENT)
-       abort();
+       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);
 
@@ -784,42 +793,42 @@ 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;
+
+  /* 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_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
    reuse.  First three arguments are same as in preceding function.  */
 
 rtx
-assign_stack_temp (mode, size, keep)
-     enum machine_mode mode;
-     HOST_WIDE_INT size;
-     int keep;
+assign_stack_temp (enum machine_mode mode, HOST_WIDE_INT size, int keep)
 {
   return assign_stack_temp_for_type (mode, size, keep, NULL_TREE);
 }
 \f
-/* Assign a temporary of given TYPE.
+/* Assign a temporary.
+   If TYPE_OR_DECL is a decl, then we are doing it on behalf of the decl
+   and so that should be used in error messages.  In either case, we
+   allocate of the given type.
    KEEP is as for assign_stack_temp.
    MEMORY_REQUIRED is 1 if the result must be addressable stack memory;
    it is 0 if a register is OK.
@@ -827,15 +836,23 @@ assign_stack_temp (mode, size, keep)
    to wider modes.  */
 
 rtx
-assign_temp (type, keep, memory_required, dont_promote)
-     tree type;
-     int keep;
-     int memory_required;
-     int dont_promote ATTRIBUTE_UNUSED;
+assign_temp (tree type_or_decl, int keep, int memory_required,
+            int dont_promote ATTRIBUTE_UNUSED)
 {
-  enum machine_mode mode = TYPE_MODE (type);
+  tree type, decl;
+  enum machine_mode mode;
+#ifndef PROMOTE_FOR_CALL_ONLY
+  int unsignedp;
+#endif
+
+  if (DECL_P (type_or_decl))
+    decl = type_or_decl, type = TREE_TYPE (decl);
+  else
+    decl = NULL, type = type_or_decl;
+
+  mode = TYPE_MODE (type);
 #ifndef PROMOTE_FOR_CALL_ONLY
-  int unsignedp = TREE_UNSIGNED (type);
+  unsignedp = TREE_UNSIGNED (type);
 #endif
 
   if (mode == BLKmode || memory_required)
@@ -857,6 +874,17 @@ assign_temp (type, keep, memory_required, dont_promote)
          && host_integerp (TYPE_ARRAY_MAX_SIZE (type), 1))
        size = tree_low_cst (TYPE_ARRAY_MAX_SIZE (type), 1);
 
+      /* 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.  */
+      if (decl && size == -1
+         && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST)
+       {
+         error ("%Jsize of variable '%D' is too large", decl, decl);
+         size = 1;
+       }
+
       tmp = assign_stack_temp_for_type (mode, size, keep, type);
       return tmp;
     }
@@ -876,7 +904,7 @@ assign_temp (type, keep, memory_required, dont_promote)
    problems in this case.  */
 
 void
-combine_temp_slots ()
+combine_temp_slots (void)
 {
   struct temp_slot *p, *q;
   struct temp_slot *prev_p, *prev_q;
@@ -888,7 +916,7 @@ combine_temp_slots ()
     return;
 
   /* If there are a lot of temp slots, don't do anything unless
-     high levels of optimizaton.  */
+     high levels of optimization.  */
   if (! flag_expensive_optimizations)
     for (p = temp_slots, num_slots = 0; p; p = p->next, num_slots++)
       if (num_slots > 100 || (num_slots > 10 && optimize == 0))
@@ -942,8 +970,7 @@ combine_temp_slots ()
 /* Find the temp slot corresponding to the object at address X.  */
 
 static struct temp_slot *
-find_temp_slot_from_address (x)
-     rtx x;
+find_temp_slot_from_address (rtx x)
 {
   struct temp_slot *p;
   rtx next;
@@ -984,8 +1011,7 @@ find_temp_slot_from_address (x)
    that previously was known by OLD.  */
 
 void
-update_temp_slot_address (old, new)
-     rtx old, new;
+update_temp_slot_address (rtx old, rtx new)
 {
   struct temp_slot *p;
 
@@ -1041,8 +1067,7 @@ update_temp_slot_address (old, new)
    address was taken.  */
 
 void
-mark_temp_addr_taken (x)
-     rtx x;
+mark_temp_addr_taken (rtx x)
 {
   struct temp_slot *p;
 
@@ -1069,8 +1094,7 @@ mark_temp_addr_taken (x)
    returns a value in memory.  */
 
 void
-preserve_temp_slots (x)
-     rtx x;
+preserve_temp_slots (rtx x)
 {
   struct temp_slot *p = 0;
 
@@ -1138,8 +1162,7 @@ preserve_temp_slots (x)
    RTL_EXPR.  */
 
 void
-preserve_rtl_expr_result (x)
-     rtx x;
+preserve_rtl_expr_result (rtx x)
 {
   struct temp_slot *p;
 
@@ -1168,7 +1191,7 @@ preserve_rtl_expr_result (x)
    worthwhile.  */
 
 void
-free_temp_slots ()
+free_temp_slots (void)
 {
   struct temp_slot *p;
 
@@ -1183,8 +1206,7 @@ free_temp_slots ()
 /* Free all temporary slots used in T, an RTL_EXPR node.  */
 
 void
-free_temps_for_rtl_expr (t)
-     tree t;
+free_temps_for_rtl_expr (tree t)
 {
   struct temp_slot *p;
 
@@ -1208,7 +1230,7 @@ free_temps_for_rtl_expr (t)
    for reuse until the current level is exited.  */
 
 void
-mark_all_temps_used ()
+mark_all_temps_used (void)
 {
   struct temp_slot *p;
 
@@ -1222,56 +1244,16 @@ mark_all_temps_used ()
 /* Push deeper into the nesting level for stack temporaries.  */
 
 void
-push_temp_slots ()
+push_temp_slots (void)
 {
   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.  */
 
 void
-pop_temp_slots ()
+pop_temp_slots (void)
 {
   struct temp_slot *p;
 
@@ -1287,7 +1269,7 @@ pop_temp_slots ()
 /* Initialize temporary slots.  */
 
 void
-init_temp_slots ()
+init_temp_slots (void)
 {
   /* We have not allocated any temporaries yet.  */
   temp_slots = 0;
@@ -1296,12 +1278,14 @@ 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)
-     tree decl;
+put_var_into_stack (tree decl, int rescan)
 {
   rtx reg;
   enum machine_mode promoted_mode, decl_mode;
@@ -1315,8 +1299,8 @@ put_var_into_stack (decl)
   context = decl_function_context (decl);
 
   /* Get the current rtl used for this object and its original mode.  */
-  reg = (TREE_CODE (decl) == SAVE_EXPR 
-        ? SAVE_EXPR_RTL (decl) 
+  reg = (TREE_CODE (decl) == SAVE_EXPR
+        ? SAVE_EXPR_RTL (decl)
         : DECL_RTL_IF_SET (decl));
 
   /* No need to do anything if decl has no rtx yet
@@ -1341,8 +1325,9 @@ put_var_into_stack (decl)
       if (function->decl == context)
        break;
 
-  /* If this is a variable-size object with a pseudo to address it,
-     put that pseudo into the stack, if the var is nonlocal.  */
+  /* If this is a variable-sized object or a structure passed by invisible
+     reference, with a pseudo to address it, put that pseudo into the stack
+     if the var is non-local.  */
   if (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)
       && GET_CODE (reg) == MEM
       && GET_CODE (XEXP (reg, 0)) == REG
@@ -1352,8 +1337,12 @@ put_var_into_stack (decl)
       decl_mode = promoted_mode = GET_MODE (reg);
     }
 
+  /* If this variable lives in the current function and we don't need to put it
+     in the stack for the sake of setjmp or the non-locality, try to keep it in
+     a register until we know we actually need the address.  */
   can_use_addressof
     = (function == 0
+       && ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl))
        && optimize > 0
        /* FIXME make it work for promoted modes too */
        && decl_mode == promoted_mode
@@ -1372,11 +1361,8 @@ put_var_into_stack (decl)
 
   if (GET_CODE (reg) == REG)
     {
-      /* If this variable lives in the current function and we don't need
-        to put things in the stack for the sake of setjmp, try to keep it
-        in a register until we know we actually need the address.  */
       if (can_use_addressof)
-       gen_mem_addressof (reg, decl);
+       gen_mem_addressof (reg, decl, rescan);
       else
        put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
                            decl_mode, volatilep, 0, usedp, 0);
@@ -1389,7 +1375,7 @@ put_var_into_stack (decl)
         to the whole CONCAT, lest we do double fixups for the latter
         references.  */
       enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
-      tree part_type = type_for_mode (part_mode, 0);
+      tree part_type = (*lang_hooks.types.type_for_mode) (part_mode, 0);
       rtx lopart = XEXP (reg, 0);
       rtx hipart = XEXP (reg, 1);
 #ifdef FRAME_GROWS_DOWNWARD
@@ -1423,7 +1409,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);
@@ -1433,14 +1419,6 @@ put_var_into_stack (decl)
     }
   else
     return;
-
-  if (current_function_check_memory_usage)
-    emit_library_call (chkr_set_right_libfunc, LCT_CONST_MAKE_BLOCK, VOIDmode,
-                      3, XEXP (reg, 0), Pmode,
-                      GEN_INT (GET_MODE_SIZE (GET_MODE (reg))),
-                      TYPE_MODE (sizetype),
-                      GEN_INT (MEMORY_USE_RW),
-                      TYPE_MODE (integer_type_node));
 }
 
 /* Subroutine of put_var_into_stack.  This puts a single pseudo reg REG
@@ -1451,16 +1429,9 @@ put_var_into_stack (decl)
    USED_P is nonzero if this reg might have already been used in an insn.  */
 
 static void
-put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
-                   original_regno, used_p, ht)
-     struct function *function;
-     rtx reg;
-     tree type;
-     enum machine_mode promoted_mode, decl_mode;
-     int volatile_p;
-     unsigned int original_regno;
-     int used_p;
-     struct hash_table *ht;
+put_reg_into_stack (struct function *function, rtx reg, tree type,
+                   enum machine_mode promoted_mode, enum machine_mode decl_mode,
+                   int volatile_p, unsigned int original_regno, int used_p, htab_t ht)
 {
   struct function *func = function ? function : cfun;
   rtx new = 0;
@@ -1503,12 +1474,8 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
    See function above for meaning of arguments.  */
 
 static void
-schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
-     struct function *function;
-     rtx reg;
-     tree type;
-     enum machine_mode promoted_mode;
-     struct hash_table *ht;
+schedule_fixup_var_refs (struct function *function, rtx reg, tree type,
+                        enum machine_mode promoted_mode, htab_t ht)
 {
   int unsigned_p = type ? TREE_UNSIGNED (type) : 0;
 
@@ -1516,8 +1483,7 @@ schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
     {
       struct var_refs_queue *temp;
 
-      temp
-       = (struct var_refs_queue *) ggc_alloc (sizeof (struct var_refs_queue));
+      temp = ggc_alloc (sizeof (struct var_refs_queue));
       temp->modified = reg;
       temp->promoted_mode = promoted_mode;
       temp->unsignedp = unsigned_p;
@@ -1526,39 +1492,41 @@ schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
     }
   else
     /* Variable is local; fix it up now.  */
-    fixup_var_refs (reg, promoted_mode, unsigned_p, ht);
+    fixup_var_refs (reg, promoted_mode, unsigned_p, reg, ht);
 }
 \f
 static void
-fixup_var_refs (var, promoted_mode, unsignedp, ht)
-     rtx var;
-     enum machine_mode promoted_mode;
-     int unsignedp;
-     struct hash_table *ht;
+fixup_var_refs (rtx var, enum machine_mode promoted_mode, int unsignedp,
+               rtx may_share, htab_t ht)
 {
   tree pending;
   rtx first_insn = get_insns ();
   struct sequence_stack *stack = seq_stack;
   tree rtl_exps = rtl_expr_chain;
+  int save_volatile_ok = volatile_ok;
 
   /* If there's a hash table, it must record all uses of VAR.  */
   if (ht)
     {
       if (stack != 0)
        abort ();
-      fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp);
+      fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp,
+                                     may_share);
       return;
     }
 
+  /* Volatile is valid in MEMs because all we're doing in changing the
+     address inside.  */
+  volatile_ok = 1;
   fixup_var_refs_insns (first_insn, var, promoted_mode, unsignedp,
-                       stack == 0);
+                       stack == 0, may_share);
 
   /* Scan all pending sequences too.  */
   for (; stack; stack = stack->next)
     {
       push_to_full_sequence (stack->first, stack->last);
       fixup_var_refs_insns (stack->first, var, promoted_mode, unsignedp,
-                           stack->next != 0);
+                           stack->next != 0, may_share);
       /* Update remembered end of sequence
         in case we added an insn at the end.  */
       stack->last = get_last_insn ();
@@ -1572,10 +1540,13 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
       if (seq != const0_rtx && seq != 0)
        {
          push_to_sequence (seq);
-         fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0);
+         fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0,
+                               may_share);
          end_sequence ();
        }
     }
+
+  volatile_ok = save_volatile_ok;
 }
 \f
 /* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
@@ -1583,9 +1554,7 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
    value is equal to X.  Allocate a new structure if no such entry exists.  */
 
 static struct fixup_replacement *
-find_fixup_replacement (replacements, x)
-     struct fixup_replacement **replacements;
-     rtx x;
+find_fixup_replacement (struct fixup_replacement **replacements, rtx x)
 {
   struct fixup_replacement *p;
 
@@ -1595,7 +1564,7 @@ find_fixup_replacement (replacements, x)
 
   if (p == 0)
     {
-      p = (struct fixup_replacement *) xmalloc (sizeof (struct fixup_replacement));
+      p = xmalloc (sizeof (struct fixup_replacement));
       p->old = x;
       p->new = 0;
       p->next = *replacements;
@@ -1605,17 +1574,14 @@ find_fixup_replacement (replacements, x)
   return p;
 }
 
-/* Scan the insn-chain starting with INSN for refs to VAR
-   and fix them up.  TOPLEVEL is nonzero if this chain is the
-   main chain of insns for the current function.  */
+/* Scan the insn-chain starting with INSN for refs to VAR and fix them
+   up.  TOPLEVEL is nonzero if this chain is the main chain of insns
+   for the current function.  MAY_SHARE is either a MEM that is not
+   to be unshared or a list of them.  */
 
 static void
-fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel)
-     rtx insn;
-     rtx var;
-     enum machine_mode promoted_mode;
-     int unsignedp;
-     int toplevel;
+fixup_var_refs_insns (rtx insn, rtx var, enum machine_mode promoted_mode,
+                     int unsignedp, int toplevel, rtx may_share)
 {
   while (insn)
     {
@@ -1640,7 +1606,8 @@ fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel)
              if (seq)
                {
                  push_to_sequence (seq);
-                 fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0);
+                 fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0,
+                                       may_share);
                  XEXP (PATTERN (insn), i) = get_insns ();
                  end_sequence ();
                }
@@ -1648,7 +1615,8 @@ fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel)
        }
 
       else if (INSN_P (insn))
-       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel);
+       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel,
+                            may_share);
 
       insn = next;
     }
@@ -1662,25 +1630,19 @@ fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel)
    (inside the CALL_PLACEHOLDER).  */
 
 static void
-fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp)
-     struct hash_table *ht;
-     rtx var;
-     enum machine_mode promoted_mode;
-     int unsignedp;
+fixup_var_refs_insns_with_hash (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);
-  rtx insn_list = ime->insns;
-
-  while (insn_list)
-    {
-      rtx insn = XEXP (insn_list, 0);
-       
-      if (INSN_P (insn))
-       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 1);
-
-      insn_list = XEXP (insn_list, 1);
-    }
+  struct insns_for_mem_entry tmp;
+  struct insns_for_mem_entry *ime;
+  rtx insn_list;
+
+  tmp.key = var;
+  ime = htab_find (ht, &tmp);
+  for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1))
+    if (INSN_P (XEXP (insn_list, 0)))
+      fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode,
+                          unsignedp, 1, may_share);
 }
 
 
@@ -1691,12 +1653,8 @@ fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp)
    function.  */
 
 static void
-fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
-     rtx insn;
-     rtx var;
-     enum machine_mode promoted_mode;
-     int unsignedp;
-     int toplevel;
+fixup_var_refs_insn (rtx insn, rtx var, enum machine_mode promoted_mode,
+                    int unsignedp, int toplevel, rtx no_share)
 {
   rtx call_dest = 0;
   rtx set, prev, prev_set;
@@ -1801,7 +1759,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
         it here.  */
 
       fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,
-                       &replacements);
+                       &replacements, no_share);
 
       /* If this is last_parm_insn, and any instructions were output
         after it to fix it up, then we must set last_parm_insn to
@@ -1821,7 +1779,8 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
              /* OLD might be a (subreg (mem)).  */
              if (GET_CODE (replacements->old) == SUBREG)
                replacements->old
-                 = fixup_memory_subreg (replacements->old, insn, 0);
+                 = fixup_memory_subreg (replacements->old, insn,
+                                        promoted_mode, 0);
              else
                replacements->old
                  = fixup_stack_1 (replacements->old, insn);
@@ -1838,7 +1797,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
                  start_sequence ();
                  convert_move (replacements->new,
                                replacements->old, unsignedp);
-                 seq = gen_sequence ();
+                 seq = get_insns ();
                  end_sequence ();
                }
              else
@@ -1861,7 +1820,8 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
     {
       if (GET_CODE (note) != INSN_LIST)
        XEXP (note, 0)
-         = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
+         = walk_fixup_memory_subreg (XEXP (note, 0), insn,
+                                     promoted_mode, 1);
       note = XEXP (note, 1);
     }
 }
@@ -1878,12 +1838,8 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
    or the SUBREG, as appropriate, to the pseudo.  */
 
 static void
-fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
-     rtx var;
-     enum machine_mode promoted_mode;
-     rtx *loc;
-     rtx insn;
-     struct fixup_replacement **replacements;
+fixup_var_refs_1 (rtx var, enum machine_mode promoted_mode, rtx *loc, rtx insn,
+                 struct fixup_replacement **replacements, rtx no_share)
 {
   int i;
   rtx x = *loc;
@@ -1918,7 +1874,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
              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)
@@ -1929,7 +1885,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  sub = force_operand (sub, y);
                  if (sub != y)
                    emit_insn (gen_move_insn (y, sub));
-                 seq = gen_sequence ();
+                 seq = get_insns ();
                  end_sequence ();
                }
 
@@ -1980,7 +1936,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
        {
          replacement = find_fixup_replacement (replacements, x);
          if (replacement->new == 0)
-           replacement->new = copy_most_rtx (x, var);
+           replacement->new = copy_most_rtx (x, no_share);
 
          *loc = x = replacement->new;
          code = GET_CODE (x);
@@ -1995,6 +1951,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
       return;
 
     case SIGN_EXTRACT:
@@ -2030,7 +1987,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  return;
                }
              else
-               tem = fixup_memory_subreg (tem, insn, 0);
+               tem = fixup_memory_subreg (tem, insn, promoted_mode, 0);
            }
          else
            tem = fixup_stack_1 (tem, insn);
@@ -2116,7 +2073,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          if (SUBREG_PROMOTED_VAR_P (x))
            {
              *loc = var;
-             fixup_var_refs_1 (var, GET_MODE (var), loc, insn, replacements);
+             fixup_var_refs_1 (var, GET_MODE (var), loc, insn, replacements,
+                               no_share);
              return;
            }
 
@@ -2140,11 +2098,28 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          replacement = find_fixup_replacement (replacements, x);
          if (replacement->new)
            {
+             enum machine_mode mode = GET_MODE (x);
              *loc = replacement->new;
+
+             /* Careful!  We may have just replaced a SUBREG by a MEM, which
+                means that the insn may have become invalid again.  We can't
+                in this case make a new replacement since we already have one
+                and we must deal with MATCH_DUPs.  */
+             if (GET_CODE (replacement->new) == MEM)
+               {
+                 INSN_CODE (insn) = -1;
+                 if (recog_memoized (insn) >= 0)
+                   return;
+
+                 fixup_var_refs_1 (replacement->new, mode, &PATTERN (insn),
+                                   insn, replacements, no_share);
+               }
+
              return;
            }
 
-         replacement->new = *loc = fixup_memory_subreg (x, insn, 0);
+         replacement->new = *loc = fixup_memory_subreg (x, insn,
+                                                        promoted_mode, 0);
 
          INSN_CODE (insn) = -1;
          if (! flag_force_mem && recog_memoized (insn) >= 0)
@@ -2222,11 +2197,11 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            /* Since this case will return, ensure we fixup all the
               operands here.  */
            fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 1),
-                             insn, replacements);
+                             insn, replacements, no_share);
            fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 2),
-                             insn, replacements);
+                             insn, replacements, no_share);
            fixup_var_refs_1 (var, promoted_mode, &SET_SRC (x),
-                             insn, replacements);
+                             insn, replacements, no_share);
 
            tem = XEXP (outerdest, 0);
 
@@ -2235,7 +2210,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
               This was legitimate when the MEM was a REG.  */
            if (GET_CODE (tem) == SUBREG
                && SUBREG_REG (tem) == var)
-             tem = fixup_memory_subreg (tem, insn, 0);
+             tem = fixup_memory_subreg (tem, insn, promoted_mode, 0);
            else
              tem = fixup_stack_1 (tem, insn);
 
@@ -2319,15 +2294,30 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          {
            rtx pat, last;
 
-           replacement = find_fixup_replacement (replacements, SET_SRC (x));
-           if (replacement->new)
-             SET_SRC (x) = replacement->new;
-           else if (GET_CODE (SET_SRC (x)) == SUBREG)
-             SET_SRC (x) = replacement->new
-               = fixup_memory_subreg (SET_SRC (x), insn, 0);
+           if (GET_CODE (SET_SRC (x)) == SUBREG
+               && (GET_MODE_SIZE (GET_MODE (SET_SRC (x)))
+                   > GET_MODE_SIZE (GET_MODE (var))))
+             {
+               /* This (subreg VAR) is now a paradoxical subreg.  We need
+                  to replace VAR instead of the subreg.  */
+               replacement = find_fixup_replacement (replacements, var);
+               if (replacement->new == NULL_RTX)
+                 replacement->new = gen_reg_rtx (GET_MODE (var));
+               SUBREG_REG (SET_SRC (x)) = replacement->new;
+             }
            else
-             SET_SRC (x) = replacement->new
-               = fixup_stack_1 (SET_SRC (x), insn);
+             {
+               replacement = find_fixup_replacement (replacements, SET_SRC (x));
+               if (replacement->new)
+                 SET_SRC (x) = replacement->new;
+               else if (GET_CODE (SET_SRC (x)) == SUBREG)
+                 SET_SRC (x) = replacement->new
+                   = fixup_memory_subreg (SET_SRC (x), insn, promoted_mode,
+                                          0);
+               else
+                 SET_SRC (x) = replacement->new
+                   = fixup_stack_1 (SET_SRC (x), insn);
+             }
 
            if (recog_memoized (insn) >= 0)
              return;
@@ -2336,12 +2326,12 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
               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);
 
@@ -2359,7 +2349,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                delete_insn (last);
              }
            else
-             PATTERN (insn) = pat;
+             PATTERN (insn) = PATTERN (pat);
 
            return;
          }
@@ -2376,7 +2366,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            rtx pat, last;
 
            if (GET_CODE (SET_DEST (x)) == SUBREG)
-             SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn, 0);
+             SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn,
+                                                 promoted_mode, 0);
            else
              SET_DEST (x) = fixup_stack_1 (SET_DEST (x), insn);
 
@@ -2384,7 +2375,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
              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);
 
@@ -2402,7 +2393,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                delete_insn (last);
              }
            else
-             PATTERN (insn) = pat;
+             PATTERN (insn) = PATTERN (pat);
 
            return;
          }
@@ -2421,6 +2412,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          {
            rtx temp;
            rtx fixeddest = SET_DEST (x);
+           enum machine_mode temp_mode;
 
            /* STRICT_LOW_PART can be discarded, around a MEM.  */
            if (GET_CODE (fixeddest) == STRICT_LOW_PART)
@@ -2428,13 +2420,17 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            /* Convert (SUBREG (MEM)) to a MEM in a changed mode.  */
            if (GET_CODE (fixeddest) == SUBREG)
              {
-               fixeddest = fixup_memory_subreg (fixeddest, insn, 0);
-               promoted_mode = GET_MODE (fixeddest);
+               fixeddest = fixup_memory_subreg (fixeddest, insn,
+                                                promoted_mode, 0);
+               temp_mode = GET_MODE (fixeddest);
              }
            else
-             fixeddest = fixup_stack_1 (fixeddest, insn);
+             {
+               fixeddest = fixup_stack_1 (fixeddest, insn);
+               temp_mode = promoted_mode;
+             }
 
-           temp = gen_reg_rtx (promoted_mode);
+           temp = gen_reg_rtx (temp_mode);
 
            emit_insn_after (gen_move_insn (fixeddest,
                                            gen_lowpart (GET_MODE (fixeddest),
@@ -2455,49 +2451,59 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       fixup_var_refs_1 (var, promoted_mode, &XEXP (x, i), insn, replacements);
+       fixup_var_refs_1 (var, promoted_mode, &XEXP (x, i), insn, replacements,
+                         no_share);
       else if (fmt[i] == 'E')
        {
          int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            fixup_var_refs_1 (var, promoted_mode, &XVECEXP (x, i, j),
-                             insn, replacements);
+                             insn, replacements, no_share);
        }
     }
 }
 \f
-/* Given X, an rtx of the form (SUBREG:m1 (MEM:m2 addr)),
-   return an rtx (MEM:m1 newaddr) which is equivalent.
-   If any insns must be emitted to compute NEWADDR, put them before INSN.
+/* Previously, X had the form (SUBREG:m1 (REG:PROMOTED_MODE ...)).
+   The REG  was placed on the stack, so X now has the form (SUBREG:m1
+   (MEM:m2 ...)).
+
+   Return an rtx (MEM:m1 newaddr) which is equivalent.  If any insns
+   must be emitted to compute NEWADDR, put them before INSN.
 
    UNCRITICAL nonzero means accept paradoxical subregs.
    This is used for subregs found inside REG_NOTES.  */
 
 static rtx
-fixup_memory_subreg (x, insn, uncritical)
-     rtx x;
-     rtx insn;
-     int uncritical;
+fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode, int uncritical)
 {
-  int offset = SUBREG_BYTE (x);
-  rtx addr = XEXP (SUBREG_REG (x), 0);
+  int offset;
+  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 (SUBREG_REG (x)))
-      && ! uncritical)
+  if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (mem)) && ! uncritical)
     abort ();
 
+  offset = SUBREG_BYTE (x);
+  if (BYTES_BIG_ENDIAN)
+    /* If the PROMOTED_MODE is wider than the mode of the MEM, adjust
+       the offset so that it points to the right location within the
+       MEM.  */
+    offset -= (GET_MODE_SIZE (promoted_mode) - GET_MODE_SIZE (GET_MODE (mem)));
+
   if (!flag_force_addr
       && memory_address_p (mode, plus_constant (addr, offset)))
     /* Shortcut if no insns need be emitted.  */
-    return adjust_address (SUBREG_REG (x), mode, offset);
+    return adjust_address (mem, mode, offset);
 
   start_sequence ();
-  result = adjust_address (SUBREG_REG (x), mode, offset);
-  emit_insn_before (gen_sequence (), insn);
+  result = adjust_address (mem, mode, offset);
+  seq = get_insns ();
   end_sequence ();
+
+  emit_insn_before (seq, insn);
   return result;
 }
 
@@ -2506,15 +2512,12 @@ fixup_memory_subreg (x, insn, uncritical)
    If X itself is a (SUBREG (MEM ...) ...), return the replacement expression.
    Otherwise return X, with its contents possibly altered.
 
-   If any insns must be emitted to compute NEWADDR, put them before INSN.
-
-   UNCRITICAL is as in fixup_memory_subreg.  */
+   INSN, PROMOTED_MODE and UNCRITICAL are as for
+   fixup_memory_subreg.  */
 
 static rtx
-walk_fixup_memory_subreg (x, insn, uncritical)
-     rtx x;
-     rtx insn;
-     int uncritical;
+walk_fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode,
+                         int uncritical)
 {
   enum rtx_code code;
   const char *fmt;
@@ -2526,7 +2529,7 @@ walk_fixup_memory_subreg (x, insn, uncritical)
   code = GET_CODE (x);
 
   if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
-    return fixup_memory_subreg (x, insn, uncritical);
+    return fixup_memory_subreg (x, insn, promoted_mode, uncritical);
 
   /* Nothing special about this RTX; fix its operands.  */
 
@@ -2534,13 +2537,15 @@ walk_fixup_memory_subreg (x, insn, uncritical)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, uncritical);
+       XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn,
+                                               promoted_mode, uncritical);
       else if (fmt[i] == 'E')
        {
          int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            XVECEXP (x, i, j)
-             = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, uncritical);
+             = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn,
+                                         promoted_mode, uncritical);
        }
     }
   return x;
@@ -2553,9 +2558,7 @@ walk_fixup_memory_subreg (x, insn, uncritical)
    Replace each such MEM rtx with a copy, to avoid clobberage.  */
 
 static rtx
-fixup_stack_1 (x, insn)
-     rtx x;
-     rtx insn;
+fixup_stack_1 (rtx x, rtx insn)
 {
   int i;
   RTX_CODE code = GET_CODE (x);
@@ -2585,7 +2588,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);
@@ -2620,10 +2623,7 @@ fixup_stack_1 (x, insn)
    is always 0.)  */
 
 static void
-optimize_bit_field (body, insn, equiv_mem)
-     rtx body;
-     rtx insn;
-     rtx *equiv_mem;
+optimize_bit_field (rtx body, rtx insn, rtx *equiv_mem)
 {
   rtx bitfield;
   int destflag;
@@ -2696,7 +2696,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.  */
@@ -2764,7 +2764,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);
        }
     }
 }
@@ -2822,15 +2822,16 @@ 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 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)
-     rtx reg;
-     tree decl;
+gen_mem_addressof (rtx reg, tree decl, int rescan)
 {
   rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)),
                             REGNO (reg), decl);
@@ -2851,28 +2852,39 @@ gen_mem_addressof (reg, decl)
     {
       tree type = TREE_TYPE (decl);
       enum machine_mode decl_mode
-       = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl))
-          : DECL_MODE (decl));
-      rtx decl_rtl = decl ? DECL_RTL_IF_SET (decl) : 0;
+       = (DECL_P (decl) ? DECL_MODE (decl) : TYPE_MODE (TREE_TYPE (decl)));
+      rtx decl_rtl = (TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl)
+                     : DECL_RTL_IF_SET (decl));
 
       PUT_MODE (reg, decl_mode);
 
       /* Clear DECL_RTL momentarily so functions below will work
         properly, then set it again.  */
-      if (decl_rtl == reg)
+      if (DECL_P (decl) && decl_rtl == reg)
        SET_DECL_RTL (decl, 0);
 
       set_mem_attributes (reg, decl, 1);
       set_mem_alias_set (reg, set);
 
-      if (decl_rtl == reg)
+      if (DECL_P (decl) && decl_rtl == reg)
        SET_DECL_RTL (decl, reg);
 
-      if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
-       fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), 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 if (rescan)
+    {
+      /* This can only happen during reload.  Clear the same flag bits as
+        reload.  */
+      MEM_VOLATILE_P (reg) = 0;
+      RTX_UNCHANGING_P (reg) = 0;
+      MEM_IN_STRUCT_P (reg) = 0;
+      MEM_SCALAR_P (reg) = 0;
+      MEM_ATTRS (reg) = 0;
+
+      fixup_var_refs (reg, GET_MODE (reg), 0, reg, 0);
     }
-  else
-    fixup_var_refs (reg, GET_MODE (reg), 0, 0);
 
   return reg;
 }
@@ -2880,8 +2892,7 @@ gen_mem_addressof (reg, decl)
 /* If DECL has an RTL that is an ADDRESSOF rtx, put it into the stack.  */
 
 void
-flush_addressof (decl)
-     tree decl;
+flush_addressof (tree decl)
 {
   if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
       && DECL_RTL (decl) != 0
@@ -2894,9 +2905,7 @@ flush_addressof (decl)
 /* Force the register pointed to by R, an ADDRESSOF rtx, into the stack.  */
 
 static void
-put_addressof_into_stack (r, ht)
-     rtx r;
-     struct hash_table *ht;
+put_addressof_into_stack (rtx r, htab_t ht)
 {
   tree decl, type;
   int volatile_p, used_p;
@@ -2913,8 +2922,7 @@ put_addressof_into_stack (r, ht)
       volatile_p = (TREE_CODE (decl) != SAVE_EXPR
                    && TREE_THIS_VOLATILE (decl));
       used_p = (TREE_USED (decl)
-               || (TREE_CODE (decl) != SAVE_EXPR
-                   && DECL_INITIAL (decl) != 0));
+               || (DECL_P (decl) && DECL_INITIAL (decl) != 0));
     }
   else
     {
@@ -2942,20 +2950,19 @@ 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)
-     rtx *loc;
-     rtx insn;
-     int force, store;
-     struct hash_table *ht;
+purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
+                  htab_t ht)
 {
   rtx x;
   RTX_CODE code;
   int i, j;
   const char *fmt;
   bool result = true;
+  bool libcall = false;
 
   /* Re-start here to avoid recursion in common cases.  */
  restart:
@@ -2964,6 +2971,10 @@ purge_addressof_1 (loc, insn, force, store, ht)
   if (x == 0)
     return true;
 
+  /* Is this a libcall?  */
+  if (!insn)
+    libcall = REG_NOTE_KIND (*loc) == REG_RETVAL;
+
   code = GET_CODE (x);
 
   /* If we don't return in any of the cases below, we will recurse inside
@@ -2971,8 +2982,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)
@@ -2980,11 +2993,8 @@ 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.  */
       sub = copy_rtx (XEXP (XEXP (x, 0), 0));
@@ -2993,12 +3003,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;
@@ -3017,6 +3035,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
@@ -3073,11 +3100,40 @@ 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.  */
+
+             /* 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)))
+                     && libcall))
+               {
+                 *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
                 version of that MEM.  Gcc testcase compile/990829-1.c can
-                generate an example of this siutation.  Rather than complain
+                generate an example of this situation.  Rather than complain
                 we return false, which will prompt our caller to remove the
                 offending note.  */
              return false;
@@ -3086,10 +3142,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.  */
@@ -3109,7 +3171,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 (),
@@ -3117,14 +3179,13 @@ purge_addressof_1 (loc, insn, force, store, ht)
 
                  start_sequence ();
                  store_bit_field (sub, size_x, 0, GET_MODE (x),
-                                  val, GET_MODE_SIZE (GET_MODE (sub)),
-                                  GET_MODE_ALIGNMENT (GET_MODE (sub)));
+                                  val, GET_MODE_SIZE (GET_MODE (sub)));
 
                  /* Make sure to unshare any shared rtl that store_bit_field
                     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))
@@ -3139,7 +3200,6 @@ purge_addressof_1 (loc, insn, force, store, ht)
                  start_sequence ();
                  val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX,
                                           GET_MODE (x), GET_MODE (x),
-                                          GET_MODE_SIZE (GET_MODE (sub)),
                                           GET_MODE_SIZE (GET_MODE (sub)));
 
                  if (! validate_change (insn, loc, val, 0))
@@ -3150,7 +3210,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 (),
@@ -3187,9 +3247,9 @@ purge_addressof_1 (loc, insn, force, store, ht)
                    return true;
                  }
              purge_addressof_replacements
-               = gen_rtx (EXPR_LIST, VOIDmode, XEXP (x, 0),
-                          gen_rtx_EXPR_LIST (VOIDmode, sub,
-                                             purge_addressof_replacements));
+               = gen_rtx_EXPR_LIST (VOIDmode, XEXP (x, 0),
+                                    gen_rtx_EXPR_LIST (VOIDmode, sub,
+                                                       purge_addressof_replacements));
              return true;
            }
          goto restart;
@@ -3202,61 +3262,44 @@ 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
-insns_for_mem_hash (k)
-     hash_table_key k;
+static hashval_t
+insns_for_mem_hash (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
-insns_for_mem_comp (k1, k2)
-     hash_table_key k1;
-     hash_table_key k2;
+static int
+insns_for_mem_comp (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 proessing.  */
+  /* The INSN we are currently processing.  */
   rtx insn;
 
   /* Zero if we are walking to find ADDRESSOFs, one if we are walking
@@ -3270,24 +3313,30 @@ struct insns_for_mem_walk_info
    insns_for_mem_walk_info structure).  */
 
 static int
-insns_for_mem_walk (r, data)
-     rtx *r;
-     void *data;
+insns_for_mem_walk (rtx *r, void *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);
+    {
+      void **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 = 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
@@ -3304,10 +3353,7 @@ insns_for_mem_walk (r, data)
    which REGs in HT.  */
 
 static void
-compute_insns_for_mem (insns, last_insn, ht)
-     rtx insns;
-     rtx last_insn;
-     struct hash_table *ht;
+compute_insns_for_mem (rtx insns, rtx last_insn, htab_t ht)
 {
   rtx insn;
   struct insns_for_mem_walk_info ifmwi;
@@ -3326,9 +3372,7 @@ compute_insns_for_mem (insns, last_insn, ht)
    Returns true iff the rtl is an ADDRESSOF.  */
 
 static int
-is_addressof (rtl, data)
-     rtx *rtl;
-     void *data ATTRIBUTE_UNUSED;
+is_addressof (rtx *rtl, void *data ATTRIBUTE_UNUSED)
 {
   return GET_CODE (*rtl) == ADDRESSOF;
 }
@@ -3338,11 +3382,10 @@ is_addressof (rtl, data)
    stack.  */
 
 void
-purge_addressof (insns)
-     rtx insns;
+purge_addressof (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
@@ -3351,23 +3394,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.  */
@@ -3387,8 +3428,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;
 
@@ -3407,12 +3460,11 @@ purge_addressof (insns)
   unshare_all_rtl_again (get_insns ());
 }
 \f
-/* Convert a SET of a hard subreg to a set of the appropriet hard
+/* Convert a SET of a hard subreg to a set of the appropriate hard
    register.  A subroutine of purge_hard_subreg_sets.  */
 
 static void
-purge_single_hard_subreg_set (pattern)
-     rtx pattern;
+purge_single_hard_subreg_set (rtx pattern)
 {
   rtx reg = SET_DEST (pattern);
   enum machine_mode mode = GET_MODE (SET_DEST (pattern));
@@ -3428,7 +3480,7 @@ purge_single_hard_subreg_set (pattern)
       reg = SUBREG_REG (reg);
     }
 
-                 
+
   if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER)
     {
       reg = gen_rtx_REG (mode, REGNO (reg) + offset);
@@ -3444,8 +3496,7 @@ purge_single_hard_subreg_set (pattern)
    of hard registers.  */
 
 void
-purge_hard_subreg_sets (insn)
-     rtx insn;
+purge_hard_subreg_sets (rtx insn)
 {
   for (; insn; insn = NEXT_INSN (insn))
     {
@@ -3457,7 +3508,7 @@ purge_hard_subreg_sets (insn)
            case SET:
              if (GET_CODE (SET_DEST (pattern)) == SUBREG)
                purge_single_hard_subreg_set (pattern);
-             break;          
+             break;
            case PARALLEL:
              {
                int j;
@@ -3481,9 +3532,7 @@ purge_hard_subreg_sets (insn)
    references to hard register references.  */
 
 void
-instantiate_virtual_regs (fndecl, insns)
-     tree fndecl;
-     rtx insns;
+instantiate_virtual_regs (tree fndecl, rtx insns)
 {
   rtx insn;
   unsigned int i;
@@ -3511,11 +3560,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
@@ -3540,9 +3597,7 @@ instantiate_virtual_regs (fndecl, insns)
    Otherwise, always do it.  */
 
 static void
-instantiate_decls (fndecl, valid_only)
-     tree fndecl;
-     int valid_only;
+instantiate_decls (tree fndecl, int valid_only)
 {
   tree decl;
 
@@ -3570,15 +3625,13 @@ instantiate_decls (fndecl, valid_only)
    BLOCK node and all its subblocks.  */
 
 static void
-instantiate_decls_1 (let, valid_only)
-     tree let;
-     int valid_only;
+instantiate_decls_1 (tree let, int valid_only)
 {
   tree t;
 
   for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
     if (DECL_RTL_SET_P (t))
-      instantiate_decl (DECL_RTL (t), 
+      instantiate_decl (DECL_RTL (t),
                        int_size_in_bytes (TREE_TYPE (t)),
                        valid_only);
 
@@ -3590,14 +3643,11 @@ 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
-instantiate_decl (x, size, valid_only)
-     rtx x;
-     HOST_WIDE_INT size;
-     int valid_only;
+instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only)
 {
   enum machine_mode mode;
   rtx addr;
@@ -3655,13 +3705,11 @@ instantiate_decl (x, size, valid_only)
 }
 \f
 /* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
-   is a virtual register, return the requivalent hard register and set the
+   is a virtual register, return the equivalent hard register and set the
    offset indirectly through the pointer.  Otherwise, return 0.  */
 
 static rtx
-instantiate_new_reg (x, poffset)
-     rtx x;
-     HOST_WIDE_INT *poffset;
+instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
 {
   rtx new;
   HOST_WIDE_INT offset;
@@ -3683,6 +3731,21 @@ 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 (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.
 
@@ -3698,10 +3761,7 @@ instantiate_new_reg (x, poffset)
    pseudos.  */
 
 static int
-instantiate_virtual_regs_1 (loc, object, extra_insns)
-     rtx *loc;
-     rtx object;
-     int extra_insns;
+instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
 {
   rtx x;
   RTX_CODE code;
@@ -3719,6 +3779,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.  */
@@ -3726,6 +3790,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case CODE_LABEL:
@@ -3755,7 +3820,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)
@@ -3766,12 +3834,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;
        }
@@ -3878,10 +3946,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;
+                   }
                }
            }
 
@@ -3982,6 +4053,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        }
 
       /* Fall through to generic unary operation case.  */
+    case PREFETCH:
     case SUBREG:
     case STRICT_LOW_PART:
     case NEG:          case NOT:
@@ -3993,6 +4065,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);
@@ -4031,10 +4105,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);
            }
        }
 
@@ -4080,7 +4154,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
    and disestablish them.  */
 
 static void
-delete_handlers ()
+delete_handlers (void)
 {
   rtx insn;
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
@@ -4128,57 +4202,53 @@ delete_handlers ()
     }
 }
 \f
-int
-max_parm_reg_num ()
-{
-  return max_parm_reg;
-}
-
 /* Return the first insn following those generated by `assign_parms'.  */
 
 rtx
-get_first_nonparm_insn ()
+get_first_nonparm_insn (void)
 {
   if (last_parm_insn)
     return NEXT_INSN (last_parm_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.
    EXP may be a type node or an expression (whose type is tested).  */
 
 int
-aggregate_value_p (exp)
-     tree exp;
+aggregate_value_p (tree exp, tree fntype)
 {
   int i, regno, nregs;
   rtx reg;
 
   tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
 
+  if (fntype)
+    switch (TREE_CODE (fntype))
+      {
+      case CALL_EXPR:
+       fntype = get_callee_fndecl (fntype);
+       fntype = fntype ? TREE_TYPE (fntype) : 0;
+       break;
+      case FUNCTION_DECL:
+       fntype = TREE_TYPE (fntype);
+       break;
+      case FUNCTION_TYPE:
+      case METHOD_TYPE:
+        break;
+      case IDENTIFIER_NODE:
+       fntype = 0;
+       break;
+      default:
+       /* We don't expect other rtl types here.  */
+       abort();
+      }
+
   if (TREE_CODE (type) == VOID_TYPE)
     return 0;
-  if (RETURN_IN_MEMORY (type))
+  if (targetm.calls.return_in_memory (type, fntype))
     return 1;
   /* Types that are TREE_ADDRESSABLE must be constructed in memory,
      and thus can't be returned in registers.  */
@@ -4196,7 +4266,7 @@ aggregate_value_p (exp)
     return 0;
 
   regno = REGNO (reg);
-  nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
+  nregs = hard_regno_nregs[regno][TYPE_MODE (type)];
   for (i = 0; i < nregs; i++)
     if (! call_used_regs[regno + i])
       return 1;
@@ -4208,42 +4278,24 @@ aggregate_value_p (exp)
    those registers as the RTL for them.  */
 
 void
-assign_parms (fndecl)
-     tree fndecl;
+assign_parms (tree fndecl)
 {
   tree parm;
-  rtx entry_parm = 0;
-  rtx stack_parm = 0;
   CUMULATIVE_ARGS args_so_far;
-  enum machine_mode promoted_mode, passed_mode;
-  enum machine_mode nominal_mode, promoted_nominal_mode;
-  int unsignedp;
   /* Total space needed so far for args on the stack,
      given as a constant and a tree-expression.  */
   struct args_size stack_args_size;
+  HOST_WIDE_INT extra_pretend_bytes = 0;
   tree fntype = TREE_TYPE (fndecl);
-  tree fnargs = DECL_ARGUMENTS (fndecl);
+  tree fnargs = DECL_ARGUMENTS (fndecl), orig_fnargs;
   /* This is used for the arg pointer when referring to stack args.  */
   rtx internal_arg_pointer;
   /* This is a dummy PARM_DECL that we used for the function result if
      the function returns a structure.  */
   tree function_result_decl = 0;
-#ifdef SETUP_INCOMING_VARARGS
   int varargs_setup = 0;
-#endif
+  int reg_parm_stack_space ATTRIBUTE_UNUSED = 0;
   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
@@ -4274,9 +4326,9 @@ assign_parms (fndecl)
   stack_args_size.var = 0;
 
   /* If struct value address is treated as the first argument, make it so.  */
-  if (aggregate_value_p (DECL_RESULT (fndecl))
+  if (aggregate_value_p (DECL_RESULT (fndecl), fndecl)
       && ! current_function_returns_pcc_struct
-      && struct_value_incoming_rtx == 0)
+      && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0)
     {
       tree type = build_pointer_type (TREE_TYPE (fntype));
 
@@ -4287,13 +4339,22 @@ assign_parms (fndecl)
       fnargs = function_result_decl;
     }
 
+  orig_fnargs = fnargs;
+
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
-  parm_reg_stack_loc = (rtx *) xcalloc (max_parm_reg, sizeof (rtx));
+  parm_reg_stack_loc = ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
+
+  if (SPLIT_COMPLEX_ARGS)
+    fnargs = split_complex_args (fnargs);
+
+#ifdef REG_PARM_STACK_SPACE
+  reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+#endif
 
 #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, -1);
 #endif
 
   /* We haven't yet found an argument that we must push and pretend the
@@ -4302,23 +4363,40 @@ assign_parms (fndecl)
 
   for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
     {
-      struct args_size stack_offset;
-      struct args_size arg_size;
+      rtx entry_parm;
+      rtx stack_parm;
+      enum machine_mode promoted_mode, passed_mode;
+      enum machine_mode nominal_mode, promoted_nominal_mode;
+      int unsignedp;
+      struct locate_and_pad_arg_data locate;
       int passed_pointer = 0;
       int did_conversion = 0;
       tree passed_type = DECL_ARG_TYPE (parm);
       tree nominal_type = TREE_TYPE (parm);
-      int pretend_named;
+      int last_named = 0, named_arg;
+      int in_regs;
+      int partial = 0;
+      int pretend_bytes = 0;
+      int loaded_in_reg = 0;
 
-      /* Set LAST_NAMED if this is last named arg before some
+      /* Set LAST_NAMED if this is last named arg before last
         anonymous args.  */
-      int last_named = ((TREE_CHAIN (parm) == 0
-                        || DECL_NAME (TREE_CHAIN (parm)) == 0)
-                       && (stdarg || current_function_varargs));
+      if (stdarg)
+       {
+         tree tem;
+
+         for (tem = TREE_CHAIN (parm); tem; tem = TREE_CHAIN (tem))
+           if (DECL_NAME (tem))
+             break;
+
+         if (tem == 0)
+           last_named = 1;
+       }
       /* 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.  */
-      int named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named;
+      named_arg = (targetm.calls.strict_argument_naming (&args_so_far)
+                  ? 1 : !last_named);
 
       if (TREE_TYPE (parm) == error_mark_node
          /* This can happen after weird syntax errors
@@ -4332,11 +4410,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);
@@ -4364,12 +4437,11 @@ assign_parms (fndecl)
         object itself or if the machine requires these objects be passed
         that way.  */
 
-      if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
-          && contains_placeholder_p (TYPE_SIZE (passed_type)))
+      if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (passed_type))
          || TREE_ADDRESSABLE (passed_type)
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
          || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
-                                             passed_type, named_arg)
+                                            passed_type, named_arg)
 #endif
          )
        {
@@ -4377,14 +4449,24 @@ 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;
 
-#ifdef PROMOTE_FUNCTION_ARGS
-      /* Compute the mode in which the arg is actually extended to.  */
-      unsignedp = TREE_UNSIGNED (passed_type);
-      promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
-#endif
+      if (targetm.calls.promote_function_args (TREE_TYPE (fndecl)))
+       {
+         /* Compute the mode in which the arg is actually extended to.  */
+         unsignedp = TREE_UNSIGNED (passed_type);
+         promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
+       }
 
       /* Let machine desc say which reg (if any) the parm arrives in.
         0 means it arrives on the stack.  */
@@ -4399,7 +4481,6 @@ assign_parms (fndecl)
       if (entry_parm == 0)
        promoted_mode = passed_mode;
 
-#ifdef SETUP_INCOMING_VARARGS
       /* If this is the last named parameter, do any required setup for
         varargs or stdargs.  We need to know about the case of this being an
         addressable type, in which case we skip the registers it
@@ -4412,11 +4493,18 @@ assign_parms (fndecl)
         Also, indicate when RTL generation is to be suppressed.  */
       if (last_named && !varargs_setup)
        {
-         SETUP_INCOMING_VARARGS (args_so_far, promoted_mode, passed_type,
-                                 current_function_pretend_args_size, 0);
+         int varargs_pretend_bytes = 0;
+         targetm.calls.setup_incoming_varargs (&args_so_far, promoted_mode,
+                                               passed_type,
+                                               &varargs_pretend_bytes, 0);
          varargs_setup = 1;
+
+         /* If the back-end has requested extra stack space, record how
+            much is needed.  Do not change pretend_args_size otherwise
+            since it may be nonzero from an earlier partial argument.  */
+         if (varargs_pretend_bytes > 0)
+           current_function_pretend_args_size = varargs_pretend_bytes;
        }
-#endif
 
       /* Determine parm's home in the stack,
         in case it arrives in the stack or we should pretend it did.
@@ -4430,27 +4518,96 @@ assign_parms (fndecl)
         it came in a register so that REG_PARM_STACK_SPACE isn't skipped.
         In this case, we call FUNCTION_ARG with NAMED set to 1 instead of
         0 as it was the previous time.  */
-
-      pretend_named = named_arg || PRETEND_OUTGOING_VARARGS_NAMED;
-      locate_and_pad_parm (promoted_mode, passed_type,
+      in_regs = entry_parm != 0;
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
-                          1,
-#else
+      in_regs = 1;
+#endif
+      if (!in_regs && !named_arg)
+       {
+         int pretend_named =
+           targetm.calls.pretend_outgoing_varargs_named (&args_so_far);
+         if (pretend_named)
+           {
 #ifdef FUNCTION_INCOMING_ARG
-                          FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
-                                                 passed_type,
-                                                 pretend_named) != 0,
+             in_regs = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
+                                              passed_type,
+                                              pretend_named) != 0;
 #else
-                          FUNCTION_ARG (args_so_far, promoted_mode,
-                                        passed_type,
-                                        pretend_named) != 0,
+             in_regs = FUNCTION_ARG (args_so_far, promoted_mode,
+                                     passed_type,
+                                     pretend_named) != 0;
 #endif
+           }
+       }
+
+      /* If this parameter was passed both in registers and in the stack,
+        use the copy on the stack.  */
+      if (MUST_PASS_IN_STACK (promoted_mode, passed_type))
+       entry_parm = 0;
+
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+      if (entry_parm)
+       {
+         partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
+                                               passed_type, named_arg);
+         if (partial
+             /* The caller might already have allocated stack space
+                for the register parameters.  */
+             && reg_parm_stack_space == 0)
+           {
+             /* Part of this argument is passed in registers and part
+                is passed on the stack.  Ask the prologue code to extend
+                the stack part so that we can recreate the full value.
+
+                PRETEND_BYTES is the size of the registers we need to store.
+                CURRENT_FUNCTION_PRETEND_ARGS_SIZE is the amount of extra
+                stack space that the prologue should allocate.
+
+                Internally, gcc assumes that the argument pointer is
+                aligned to STACK_BOUNDARY bits.  This is used both for
+                alignment optimizations (see init_emit) and to locate
+                arguments that are aligned to more than PARM_BOUNDARY
+                bits.  We must preserve this invariant by rounding
+                CURRENT_FUNCTION_PRETEND_ARGS_SIZE up to a stack
+                boundary.  */
+
+             /* We assume at most one partial arg, and it must be the first
+                argument on the stack.  */
+             if (extra_pretend_bytes || current_function_pretend_args_size)
+               abort ();
+
+             pretend_bytes = partial * UNITS_PER_WORD;
+             current_function_pretend_args_size
+               = CEIL_ROUND (pretend_bytes, STACK_BYTES);
+
+             /* We want to align relative to the actual stack pointer, so
+                don't include this in the stack size until later.  */
+             extra_pretend_bytes = current_function_pretend_args_size;
+           }
+       }
 #endif
-                          fndecl, &stack_args_size, &stack_offset, &arg_size,
-                          &alignment_pad);
+
+      memset (&locate, 0, sizeof (locate));
+      locate_and_pad_parm (promoted_mode, passed_type, in_regs,
+                          entry_parm ? partial : 0, fndecl,
+                          &stack_args_size, &locate);
+      /* Adjust offsets to include pretend args, unless this is the
+         split arg.  */
+      if (pretend_bytes == 0)
+       {
+         locate.slot_offset.constant += extra_pretend_bytes;
+         locate.offset.constant += extra_pretend_bytes;
+       }
 
       {
-       rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
+       rtx offset_rtx;
+
+       /* If we're passing this arg using a reg, make its stack home
+          the aligned stack slot.  */
+       if (entry_parm)
+         offset_rtx = ARGS_SIZE_RTX (locate.slot_offset);
+       else
+         offset_rtx = ARGS_SIZE_RTX (locate.offset);
 
        if (offset_rtx == const0_rtx)
          stack_parm = gen_rtx_MEM (promoted_mode, internal_arg_pointer);
@@ -4461,14 +4618,14 @@ assign_parms (fndecl)
                                                  offset_rtx));
 
        set_mem_attributes (stack_parm, parm, 1);
-      }
+       if (entry_parm && MEM_ATTRS (stack_parm)->align < PARM_BOUNDARY)
+         set_mem_align (stack_parm, PARM_BOUNDARY);
 
-      /* If this parameter was passed both in registers and in the stack,
-        use the copy on the stack.  */
-      if (MUST_PASS_IN_STACK (promoted_mode, passed_type))
-       entry_parm = 0;
+       /* Set also REG_ATTRS if parameter was passed in a register.  */
+       if (entry_parm)
+         set_reg_attrs_for_parm (entry_parm, stack_parm);
+      }
 
-#ifdef FUNCTION_ARG_PARTIAL_NREGS
       /* If this parm was passed part in regs and part in memory,
         pretend it arrived entirely in memory
         by pushing the register-part onto the stack.
@@ -4477,34 +4634,21 @@ assign_parms (fndecl)
         we could put it together in a pseudoreg directly,
         but for now that's not worth bothering with.  */
 
-      if (entry_parm)
+      if (partial)
        {
-         int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
-                                                 passed_type, named_arg);
-
-         if (nregs > 0)
-           {
-             current_function_pretend_args_size
-               = (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
-                  / (PARM_BOUNDARY / BITS_PER_UNIT)
-                  * (PARM_BOUNDARY / BITS_PER_UNIT));
-
-             /* Handle calls that pass values in multiple non-contiguous
-                locations.  The Irix 6 ABI has examples of this.  */
-             if (GET_CODE (entry_parm) == PARALLEL)
-               emit_group_store (validize_mem (stack_parm), entry_parm,
-                                 int_size_in_bytes (TREE_TYPE (parm)),
-                                 TYPE_ALIGN (TREE_TYPE (parm)));
+         /* Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+         if (GET_CODE (entry_parm) == PARALLEL)
+           emit_group_store (validize_mem (stack_parm), entry_parm,
+                             TREE_TYPE (parm),
+                             int_size_in_bytes (TREE_TYPE (parm)));
 
-             else
-               move_block_from_reg (REGNO (entry_parm),
-                                    validize_mem (stack_parm), nregs,
-                                    int_size_in_bytes (TREE_TYPE (parm)));
+         else
+           move_block_from_reg (REGNO (entry_parm), validize_mem (stack_parm),
+                                partial);
 
-             entry_parm = stack_parm;
-           }
+         entry_parm = stack_parm;
        }
-#endif
 
       /* If we didn't decide this parm came in a register,
         by default it came on the stack.  */
@@ -4512,32 +4656,26 @@ assign_parms (fndecl)
        entry_parm = stack_parm;
 
       /* Record permanently how this parm was passed.  */
-      DECL_INCOMING_RTL (parm) = entry_parm;
+      set_decl_incoming_rtl (parm, entry_parm);
 
       /* If there is actually space on the stack for this parm,
         count it in stack_args_size; otherwise set stack_parm to 0
         to indicate there is no preallocated stack slot for the parm.  */
 
       if (entry_parm == stack_parm
-          || (GET_CODE (entry_parm) == PARALLEL
-              && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX)
-#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+         || (GET_CODE (entry_parm) == PARALLEL
+             && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX)
+#if defined (REG_PARM_STACK_SPACE)
          /* On some machines, even if a parm value arrives in a register
-            there is still an (uninitialized) stack slot allocated for it.
-
-            ??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
-            whether this parameter already has a stack slot allocated,
-            because an arg block exists only if current_function_args_size
-            is larger than some threshold, and we haven't calculated that
-            yet.  So, for now, we just assume that stack slots never exist
-            in this case.  */
+            there is still an (uninitialized) stack slot allocated
+            for it.  */
          || REG_PARM_STACK_SPACE (fndecl) > 0
 #endif
          )
        {
-         stack_args_size.constant += arg_size.constant;
-         if (arg_size.var)
-           ADD_PARM_SIZE (stack_args_size, arg_size.var);
+         stack_args_size.constant += locate.size.constant;
+         if (locate.size.var)
+           ADD_PARM_SIZE (stack_args_size, locate.size.var);
        }
       else
        /* No stack slot was pushed for this parm.  */
@@ -4561,7 +4699,7 @@ assign_parms (fndecl)
 
       /* If parm was passed in memory, and we need to convert it on entry,
         don't store it back in that same slot.  */
-      if (entry_parm != 0
+      if (entry_parm == stack_parm
          && nominal_mode != BLKmode && nominal_mode != passed_mode)
        stack_parm = 0;
 
@@ -4581,7 +4719,7 @@ assign_parms (fndecl)
                && INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0)
              {
                entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0);
-               DECL_INCOMING_RTL (parm) = entry_parm;
+               set_decl_incoming_rtl (parm, entry_parm);
                break;
              }
        }
@@ -4600,17 +4738,58 @@ assign_parms (fndecl)
 
         Set DECL_RTL to that place.  */
 
-      if (nominal_mode == BLKmode || GET_CODE (entry_parm) == PARALLEL)
+      if (GET_CODE (entry_parm) == PARALLEL && nominal_mode != BLKmode
+         && XVECLEN (entry_parm, 0) > 1)
+       {
+         /* Reconstitute objects the size of a register or larger using
+            register operations instead of the stack.  */
+         rtx parmreg = gen_reg_rtx (nominal_mode);
+
+         if (REG_P (parmreg))
+           {
+             unsigned int regno = REGNO (parmreg);
+
+             emit_group_store (parmreg, entry_parm, TREE_TYPE (parm),
+                               int_size_in_bytes (TREE_TYPE (parm)));
+             SET_DECL_RTL (parm, parmreg);
+             loaded_in_reg = 1;
+
+             if (regno >= max_parm_reg)
+               {
+                 rtx *new;
+                 int old_max_parm_reg = max_parm_reg;
+
+                 /* It's slow to expand this one register at a time,
+                    but it's also rare and we need max_parm_reg to be
+                    precisely correct.  */
+                 max_parm_reg = regno + 1;
+                 new = ggc_realloc (parm_reg_stack_loc,
+                                    max_parm_reg * sizeof (rtx));
+                 memset (new + old_max_parm_reg, 0,
+                         (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
+                 parm_reg_stack_loc = new;
+                 parm_reg_stack_loc[regno] = stack_parm;
+               }
+           }
+       }
+
+      if (nominal_mode == BLKmode
+#ifdef BLOCK_REG_PADDING
+         || (locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward)
+             && GET_MODE_SIZE (promoted_mode) < UNITS_PER_WORD)
+#endif
+         || GET_CODE (entry_parm) == PARALLEL)
        {
          /* If a BLKmode arrives in registers, copy it to a stack slot.
             Handle calls that pass values in multiple non-contiguous
             locations.  The Irix 6 ABI has examples of this.  */
          if (GET_CODE (entry_parm) == REG
-             || GET_CODE (entry_parm) == PARALLEL)
+             || (GET_CODE (entry_parm) == PARALLEL
+                && (!loaded_in_reg || !optimize)))
            {
-             int size_stored
-               = CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
-                             UNITS_PER_WORD);
+             int size = int_size_in_bytes (TREE_TYPE (parm));
+             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
@@ -4618,36 +4797,87 @@ assign_parms (fndecl)
                 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.  */
+                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 (GET_MODE (entry_parm),
-                                         size_stored, 0);
+                 stack_parm = assign_stack_local (BLKmode, size_stored, 0);
+                 PUT_MODE (stack_parm, GET_MODE (entry_parm));
                  set_mem_attributes (stack_parm, parm, 1);
                }
-
+             else if (GET_CODE (entry_parm) == PARALLEL 
+                      && GET_MODE(entry_parm) == BLKmode)
+               ;
              else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
                abort ();
 
+             mem = validize_mem (stack_parm);
+
              /* Handle calls that pass values in multiple non-contiguous
                 locations.  The Irix 6 ABI has examples of this.  */
              if (GET_CODE (entry_parm) == PARALLEL)
-               emit_group_store (validize_mem (stack_parm), entry_parm,
-                                 int_size_in_bytes (TREE_TYPE (parm)),
-                                 TYPE_ALIGN (TREE_TYPE (parm)));
+               emit_group_store (mem, entry_parm, TREE_TYPE (parm), size);
+
+             else if (size == 0)
+               ;
+
+             /* If SIZE is that of a mode no bigger than a word, just use
+                that mode's store operation.  */
+             else if (size <= UNITS_PER_WORD)
+               {
+                 enum machine_mode mode
+                   = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+
+                 if (mode != BLKmode
+#ifdef BLOCK_REG_PADDING
+                     && (size == UNITS_PER_WORD
+                         || (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
+                             != (BYTES_BIG_ENDIAN ? upward : downward)))
+#endif
+                     )
+                   {
+                     rtx reg = gen_rtx_REG (mode, REGNO (entry_parm));
+                     emit_move_insn (change_address (mem, mode, 0), reg);
+                   }
+
+                 /* Blocks smaller than a word on a BYTES_BIG_ENDIAN
+                    machine must be aligned to the left before storing
+                    to memory.  Note that the previous test doesn't
+                    handle all cases (e.g. SIZE == 3).  */
+                 else if (size != UNITS_PER_WORD
+#ifdef BLOCK_REG_PADDING
+                          && (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
+                              == downward)
+#else
+                          && BYTES_BIG_ENDIAN
+#endif
+                          )
+                   {
+                     rtx tem, x;
+                     int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
+                     rtx reg = gen_rtx_REG (word_mode, REGNO (entry_parm));
+
+                     x = expand_binop (word_mode, ashl_optab, reg,
+                                       GEN_INT (by), 0, 1, OPTAB_WIDEN);
+                     tem = change_address (mem, word_mode, 0);
+                     emit_move_insn (tem, x);
+                   }
+                 else
+                   move_block_from_reg (REGNO (entry_parm), mem,
+                                        size_stored / UNITS_PER_WORD);
+               }
              else
-               move_block_from_reg (REGNO (entry_parm),
-                                    validize_mem (stack_parm),
-                                    size_stored / UNITS_PER_WORD,
-                                    int_size_in_bytes (TREE_TYPE (parm)));
+               move_block_from_reg (REGNO (entry_parm), mem,
+                                    size_stored / UNITS_PER_WORD);
            }
-         SET_DECL_RTL (parm, stack_parm);
+         /* If parm is already bound to register pair, don't change 
+            this binding.  */
+         if (! DECL_RTL_SET_P (parm))
+           SET_DECL_RTL (parm, stack_parm);
        }
       else if (! ((! optimize
-                  && ! DECL_REGISTER (parm)
-                  && ! DECL_INLINE (fndecl))
+                  && ! DECL_REGISTER (parm))
                  || TREE_SIDE_EFFECTS (parm)
                  /* If -ffloat-store specified, don't put explicit
                     float variables into registers.  */
@@ -4676,7 +4906,7 @@ assign_parms (fndecl)
          if (passed_pointer)
            {
              rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)),
-                                  parmreg);
+                                  parmreg);
              set_mem_attributes (x, parm, 1);
              SET_DECL_RTL (parm, x);
            }
@@ -4685,7 +4915,7 @@ assign_parms (fndecl)
              SET_DECL_RTL (parm, parmreg);
              maybe_set_unchanging (DECL_RTL (parm), parm);
            }
-             
+
          /* Copy the value into the register.  */
          if (nominal_mode != passed_mode
              || promoted_nominal_mode != promoted_mode)
@@ -4728,13 +4958,13 @@ assign_parms (fndecl)
                  /* The argument is already sign/zero extended, so note it
                     into the subreg.  */
                  SUBREG_PROMOTED_VAR_P (tempreg) = 1;
-                 SUBREG_PROMOTED_UNSIGNED_P (tempreg) = unsignedp;
+                 SUBREG_PROMOTED_UNSIGNED_SET (tempreg, unsignedp);
                }
 
              /* TREE_USED gets set erroneously during expand_assignment.  */
              save_tree_used = TREE_USED (parm);
              expand_assignment (parm,
-                                make_tree (nominal_type, tempreg), 0, 0);
+                                make_tree (nominal_type, tempreg), 0);
              TREE_USED (parm) = save_tree_used;
              conversion_insns = get_insns ();
              did_conversion = 1;
@@ -4746,14 +4976,15 @@ assign_parms (fndecl)
          /* If we were passed a pointer but the actual value
             can safely live in a register, put it in one.  */
          if (passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode
-             && ! ((! optimize
-                    && ! DECL_REGISTER (parm)
-                    && ! DECL_INLINE (fndecl))
-                   || TREE_SIDE_EFFECTS (parm)
-                   /* If -ffloat-store specified, don't put explicit
-                      float variables into registers.  */
-                   || (flag_float_store
-                       && TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE)))
+             /* If by-reference argument was promoted, demote it.  */
+             && (TYPE_MODE (TREE_TYPE (parm)) != GET_MODE (DECL_RTL (parm))
+                 || ! ((! optimize
+                        && ! DECL_REGISTER (parm))
+                       || TREE_SIDE_EFFECTS (parm)
+                       /* If -ffloat-store specified, don't put explicit
+                          float variables into registers.  */
+                       || (flag_float_store
+                           && TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE))))
            {
              /* We can't use nominal_mode, because it will have been set to
                 Pmode above.  We must use the actual mode of the parm.  */
@@ -4766,7 +4997,7 @@ assign_parms (fndecl)
                  push_to_sequence (conversion_insns);
                  emit_move_insn (tempreg, DECL_RTL (parm));
                  SET_DECL_RTL (parm,
-                               convert_to_mode (GET_MODE (parmreg), 
+                               convert_to_mode (GET_MODE (parmreg),
                                                 tempreg,
                                                 unsigned_p));
                  emit_move_insn (parmreg, DECL_RTL (parm));
@@ -4792,13 +5023,13 @@ assign_parms (fndecl)
 
          else if (passed_pointer
                   && FUNCTION_ARG_CALLEE_COPIES (args_so_far,
-                                                 TYPE_MODE (DECL_ARG_TYPE (parm)),
-                                                 DECL_ARG_TYPE (parm),
+                                                 TYPE_MODE (TREE_TYPE (passed_type)),
+                                                 TREE_TYPE (passed_type),
                                                  named_arg)
-                  && ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
+                  && ! TREE_ADDRESSABLE (TREE_TYPE (passed_type)))
            {
              rtx copy;
-             tree type = DECL_ARG_TYPE (parm);
+             tree type = TREE_TYPE (passed_type);
 
              /* This sequence may involve a library call perhaps clobbering
                 registers that haven't been copied to pseudos yet.  */
@@ -4819,14 +5050,6 @@ assign_parms (fndecl)
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
-             if (current_function_check_memory_usage)
-               emit_library_call (chkr_set_right_libfunc,
-                                  LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
-                                  XEXP (copy, 0), Pmode,
-                                  GEN_INT (int_size_in_bytes (type)),
-                                  TYPE_MODE (sizetype),
-                                  GEN_INT (MEMORY_USE_RW),
-                                  TYPE_MODE (integer_type_node));
              conversion_insns = get_insns ();
              did_conversion = 1;
              end_sequence ();
@@ -4853,10 +5076,10 @@ 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,
-                                     max_parm_reg * sizeof (rtx));
-             memset ((char *) (new + old_max_parm_reg), 0,
-                    (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
+             new = ggc_realloc (parm_reg_stack_loc,
+                                max_parm_reg * sizeof (rtx));
+             memset (new + old_max_parm_reg, 0,
+                     (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
              parm_reg_stack_loc = new;
            }
 
@@ -4893,7 +5116,7 @@ assign_parms (fndecl)
              && ! did_conversion
              && stack_parm != 0
              && GET_CODE (stack_parm) == MEM
-             && stack_offset.var == 0
+             && locate.offset.var == 0
              && reg_mentioned_p (virtual_incoming_args_rtx,
                                  XEXP (stack_parm, 0)))
            {
@@ -4938,13 +5161,13 @@ assign_parms (fndecl)
            {
              /* If we end up putting something into the stack,
                 fixup_var_refs_insns will need to make a pass over
-                all the instructions.  It looks throughs the pending
+                all the instructions.  It looks through the pending
                 sequences -- but it can't see the ones in the
                 CONVERSION_INSNS, if they're not on the sequence
                 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 ();
            }
@@ -4979,7 +5202,8 @@ assign_parms (fndecl)
                {
                  stack_parm
                    = assign_stack_local (GET_MODE (entry_parm),
-                                         GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
+                                         GET_MODE_SIZE (GET_MODE (entry_parm)),
+                                         0);
                  set_mem_attributes (stack_parm, parm, 1);
                }
 
@@ -4995,63 +5219,83 @@ assign_parms (fndecl)
                emit_move_insn (validize_mem (stack_parm),
                                validize_mem (entry_parm));
            }
-         if (current_function_check_memory_usage)
-           {
-             push_to_sequence (conversion_insns);
-             emit_library_call (chkr_set_right_libfunc, LCT_CONST_MAKE_BLOCK,
-                                VOIDmode, 3, XEXP (stack_parm, 0), Pmode,
-                                GEN_INT (GET_MODE_SIZE (GET_MODE
-                                                        (entry_parm))),
-                                TYPE_MODE (sizetype),
-                                GEN_INT (MEMORY_USE_RW),
-                                TYPE_MODE (integer_type_node));
 
-             conversion_insns = get_insns ();
-             end_sequence ();
-           }
          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)
+  if (SPLIT_COMPLEX_ARGS && fnargs != orig_fnargs)
+    {
+      for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm))
        {
-         tree result = DECL_RESULT (fndecl);
-         rtx x = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
+         if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE)
+           {
+             rtx tmp, real, imag;
+             enum machine_mode inner = GET_MODE_INNER (DECL_MODE (parm));
 
-         set_mem_attributes (x, result, 1);
-         SET_DECL_RTL (result, x);
-       }
+             real = DECL_RTL (fnargs);
+             imag = DECL_RTL (TREE_CHAIN (fnargs));
+             if (inner != GET_MODE (real))
+               {
+                 real = gen_lowpart_SUBREG (inner, real);
+                 imag = gen_lowpart_SUBREG (inner, imag);
+               }
+             tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
+             SET_DECL_RTL (parm, tmp);
 
-      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;
+             real = DECL_INCOMING_RTL (fnargs);
+             imag = DECL_INCOMING_RTL (TREE_CHAIN (fnargs));
+             if (inner != GET_MODE (real))
+               {
+                 real = gen_lowpart_SUBREG (inner, real);
+                 imag = gen_lowpart_SUBREG (inner, imag);
+               }
+             tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
+             set_decl_incoming_rtl (parm, tmp);
+             fnargs = TREE_CHAIN (fnargs);
+           }
+         else
+           {
+             SET_DECL_RTL (parm, DECL_RTL (fnargs));
+             set_decl_incoming_rtl (parm, DECL_INCOMING_RTL (fnargs));
+           }
+         fnargs = TREE_CHAIN (fnargs);
        }
-
     }
 
   /* Output all parameter conversion instructions (possibly including calls)
      now that all parameters have been copied out of hard registers.  */
-  emit_insns (conversion_insns);
+  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;
+
+      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);
+    }
 
   last_parm_insn = get_last_insn ();
 
+  /* We have aligned all the args, so add space for the pretend args.  */
+  stack_args_size.constant += extra_pretend_bytes;
   current_function_args_size = stack_args_size.constant;
 
   /* Adjust function incoming argument size for alignment and
      minimum length.  */
 
 #ifdef REG_PARM_STACK_SPACE
-#ifndef MAYBE_REG_PARM_STACK_SPACE
   current_function_args_size = MAX (current_function_args_size,
                                    REG_PARM_STACK_SPACE (fndecl));
 #endif
-#endif
-
-#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
 
   current_function_args_size
     = ((current_function_args_size + STACK_BYTES - 1)
@@ -5062,7 +5306,7 @@ assign_parms (fndecl)
     = (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
        : expand_expr (size_diffop (stack_args_size.var,
                                   size_int (-stack_args_size.constant)),
-                     NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD));
+                     NULL_RTX, VOIDmode, 0));
 #else
   current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
 #endif
@@ -5076,8 +5320,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
@@ -5087,6 +5330,84 @@ assign_parms (fndecl)
   current_function_return_rtx
     = (DECL_RTL_SET_P (DECL_RESULT (fndecl))
        ? DECL_RTL (DECL_RESULT (fndecl)) : 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.  */
+  if (DECL_RTL_SET_P (DECL_RESULT (fndecl)))
+    {
+      tree decl_result = DECL_RESULT (fndecl);
+      rtx decl_rtl = DECL_RTL (decl_result);
+
+      if (REG_P (decl_rtl)
+         ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER
+         : DECL_REGISTER (decl_result))
+       {
+         rtx real_decl_rtl;
+
+#ifdef FUNCTION_OUTGOING_VALUE
+         real_decl_rtl = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl_result),
+                                                  fndecl);
+#else
+         real_decl_rtl = FUNCTION_VALUE (TREE_TYPE (decl_result),
+                                         fndecl);
+#endif
+         REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
+         /* The delay slot scheduler assumes that current_function_return_rtx
+            holds the hard register containing the return value, not a
+            temporary pseudo.  */
+         current_function_return_rtx = real_decl_rtl;
+       }
+    }
+}
+
+/* If ARGS contains entries with complex types, split the entry into two
+   entries of the component type.  Return a new list of substitutions are
+   needed, else the old list.  */
+
+static tree
+split_complex_args (tree args)
+{
+  tree p;
+
+  /* Before allocating memory, check for the common case of no complex.  */
+  for (p = args; p; p = TREE_CHAIN (p))
+    if (TREE_CODE (TREE_TYPE (p)) == COMPLEX_TYPE)
+      goto found;
+  return args;
+
+ found:
+  args = copy_list (args);
+
+  for (p = args; p; p = TREE_CHAIN (p))
+    {
+      tree type = TREE_TYPE (p);
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+       {
+         tree decl;
+         tree subtype = TREE_TYPE (type);
+
+         /* Rewrite the PARM_DECL's type with its component.  */
+         TREE_TYPE (p) = subtype;
+         DECL_ARG_TYPE (p) = TREE_TYPE (DECL_ARG_TYPE (p));
+         DECL_MODE (p) = VOIDmode;
+         DECL_SIZE (p) = NULL;
+         DECL_SIZE_UNIT (p) = NULL;
+         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);
+         layout_decl (decl, 0);
+
+         /* Splice it in; skip the new decl.  */
+         TREE_CHAIN (decl) = TREE_CHAIN (p);
+         TREE_CHAIN (p) = decl;
+         p = decl;
+       }
+    }
+
+  return args;
 }
 \f
 /* Indicate whether REGNO is an incoming argument to the current function
@@ -5095,13 +5416,8 @@ assign_parms (fndecl)
    that REGNO is promoted from and whether the promotion was signed or
    unsigned.  */
 
-#ifdef PROMOTE_FUNCTION_ARGS
-
 rtx
-promoted_input_arg (regno, pmode, punsignedp)
-     unsigned int regno;
-     enum machine_mode *pmode;
-     int *punsignedp;
+promoted_input_arg (unsigned int regno, enum machine_mode *pmode, int *punsignedp)
 {
   tree arg;
 
@@ -5127,7 +5443,6 @@ promoted_input_arg (regno, pmode, punsignedp)
   return 0;
 }
 
-#endif
 \f
 /* Compute the size and offset from the start of the stacked arguments for a
    parm passed in mode PASSED_MODE and with type TYPE.
@@ -5135,10 +5450,13 @@ promoted_input_arg (regno, pmode, punsignedp)
    INITIAL_OFFSET_PTR points to the current offset into the stacked
    arguments.
 
-   The starting offset and size for this parm are returned in *OFFSET_PTR
-   and *ARG_SIZE_PTR, respectively.
+   The starting offset and size for this parm are returned in
+   LOCATE->OFFSET and LOCATE->SIZE, respectively.  When IN_REGS is
+   nonzero, the offset is that of stack slot, which is returned in
+   LOCATE->SLOT_OFFSET.  LOCATE->ALIGNMENT_PAD is the amount of
+   padding required from the initial offset ptr to the stack slot.
 
-   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.
@@ -5153,42 +5471,30 @@ promoted_input_arg (regno, pmode, punsignedp)
    initial offset is not affected by this rounding, while the size always
    is and the starting offset may be.  */
 
-/*  offset_ptr will be negative for ARGS_GROW_DOWNWARD case;
-    initial_offset_ptr is positive because locate_and_pad_parm's
+/*  LOCATE->OFFSET will be negative for ARGS_GROW_DOWNWARD case;
+    INITIAL_OFFSET_PTR is positive because locate_and_pad_parm's
     callers pass in the total size of args so far as
-    initial_offset_ptr. arg_size_ptr is always positive.*/
+    INITIAL_OFFSET_PTR.  LOCATE->SIZE is always positive.  */
 
 void
-locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
-                    initial_offset_ptr, offset_ptr, arg_size_ptr,
-                    alignment_pad)
-     enum machine_mode passed_mode;
-     tree type;
-     int in_regs ATTRIBUTE_UNUSED;
-     tree fndecl ATTRIBUTE_UNUSED;
-     struct args_size *initial_offset_ptr;
-     struct args_size *offset_ptr;
-     struct args_size *arg_size_ptr;
-     struct args_size *alignment_pad;
-
+locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs,
+                    int partial, tree fndecl ATTRIBUTE_UNUSED,
+                    struct args_size *initial_offset_ptr,
+                    struct locate_and_pad_arg_data *locate)
 {
-  tree sizetree
-    = 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);
+  tree sizetree;
+  enum direction where_pad;
+  int boundary;
+  int reg_parm_stack_space = 0;
+  int part_size_in_regs;
 
 #ifdef REG_PARM_STACK_SPACE
+  reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+
   /* If we have found a stack parm before we reach the end of the
      area reserved for registers, skip that area.  */
   if (! in_regs)
     {
-      int reg_parm_stack_space = 0;
-
-#ifdef MAYBE_REG_PARM_STACK_SPACE
-      reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
-#else
-      reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
-#endif
       if (reg_parm_stack_space > 0)
        {
          if (initial_offset_ptr->var)
@@ -5204,40 +5510,57 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     }
 #endif /* REG_PARM_STACK_SPACE */
 
-  arg_size_ptr->var = 0;
-  arg_size_ptr->constant = 0;
-  alignment_pad->var = 0;
-  alignment_pad->constant = 0;
+  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));
+
+  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;
 
 #ifdef ARGS_GROW_DOWNWARD
+  locate->slot_offset.constant = -initial_offset_ptr->constant;
   if (initial_offset_ptr->var)
-    {
-      offset_ptr->constant = 0;
-      offset_ptr->var = size_binop (MINUS_EXPR, ssize_int (0),
-                                   initial_offset_ptr->var);
-    }
-  else
-    {
-      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)
-    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,
-                                               ssize_int (0),
-                                               initial_offset_ptr->var),
-                                   offset_ptr->var);
+    locate->slot_offset.var = size_binop (MINUS_EXPR, ssize_int (0),
+                                         initial_offset_ptr->var);
 
-  else
-    arg_size_ptr->constant = (-initial_offset_ptr->constant
-                             - offset_ptr->constant);
+  {
+    tree s2 = sizetree;
+    if (where_pad != none
+       && (!host_integerp (sizetree, 1)
+           || (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
+      s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
+    SUB_PARM_SIZE (locate->slot_offset, s2);
+  }
+
+  locate->slot_offset.constant += part_size_in_regs;
+
+  if (!in_regs
+#ifdef REG_PARM_STACK_SPACE
+      || REG_PARM_STACK_SPACE (fndecl) > 0
+#endif
+     )
+    pad_to_arg_alignment (&locate->slot_offset, boundary,
+                         &locate->alignment_pad);
+
+  locate->size.constant = (-initial_offset_ptr->constant
+                          - locate->slot_offset.constant);
+  if (initial_offset_ptr->var)
+    locate->size.var = size_binop (MINUS_EXPR,
+                                  size_binop (MINUS_EXPR,
+                                              ssize_int (0),
+                                              initial_offset_ptr->var),
+                                  locate->slot_offset.var);
+
+  /* Pad_below needs the pre-rounded size to know how much to pad
+     below.  */
+  locate->offset = locate->slot_offset;
+  if (where_pad == downward)
+    pad_below (&locate->offset, passed_mode, sizetree);
 
 #else /* !ARGS_GROW_DOWNWARD */
   if (!in_regs
@@ -5245,8 +5568,9 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
       || REG_PARM_STACK_SPACE (fndecl) > 0
 #endif
       )
-    pad_to_arg_alignment (initial_offset_ptr, boundary, alignment_pad);
-  *offset_ptr = *initial_offset_ptr;
+    pad_to_arg_alignment (initial_offset_ptr, boundary,
+                         &locate->alignment_pad);
+  locate->slot_offset = *initial_offset_ptr;
 
 #ifdef PUSH_ROUNDING
   if (passed_mode != BLKmode)
@@ -5255,18 +5579,18 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
 
   /* Pad_below needs the pre-rounded size to know how much to pad below
      so this must be done before rounding up.  */
-  if (where_pad == downward
-    /* However, BLKmode args passed in regs have their padding done elsewhere.
-       The stack slot must be able to hold the entire register.  */
-      && !(in_regs && passed_mode == BLKmode))
-    pad_below (offset_ptr, passed_mode, sizetree);
+  locate->offset = locate->slot_offset;
+  if (where_pad == downward)
+    pad_below (&locate->offset, passed_mode, sizetree);
 
   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);
 
-  ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+  ADD_PARM_SIZE (locate->size, sizetree);
+
+  locate->size.constant -= part_size_in_regs;
 #endif /* ARGS_GROW_DOWNWARD */
 }
 
@@ -5274,15 +5598,22 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
    BOUNDARY is measured in bits, but must be a multiple of a storage unit.  */
 
 static void
-pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
-     struct args_size *offset_ptr;
-     int boundary;
-     struct args_size *alignment_pad;
+pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
+                     struct args_size *alignment_pad)
 {
   tree save_var = NULL_TREE;
   HOST_WIDE_INT save_constant = 0;
-
   int boundary_in_bytes = boundary / BITS_PER_UNIT;
+  HOST_WIDE_INT sp_offset = STACK_POINTER_OFFSET;
+
+#ifdef SPARC_STACK_BOUNDARY_HACK
+  /* The sparc port has a bug.  It sometimes claims a STACK_BOUNDARY
+     higher than the real alignment of %sp.  However, when it does this,
+     the alignment of %sp+STACK_POINTER_OFFSET will be STACK_BOUNDARY.
+     This is a temporary hack while the sparc port is fixed.  */
+  if (SPARC_STACK_BOUNDARY_HACK)
+    sp_offset = 0;
+#endif
 
   if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
     {
@@ -5297,26 +5628,30 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
     {
       if (offset_ptr->var)
        {
-         offset_ptr->var =
+         tree sp_offset_tree = ssize_int (sp_offset);
+         tree offset = size_binop (PLUS_EXPR,
+                                   ARGS_SIZE_TREE (*offset_ptr),
+                                   sp_offset_tree);
 #ifdef ARGS_GROW_DOWNWARD
-           round_down
+         tree rounded = round_down (offset, boundary / BITS_PER_UNIT);
 #else
-           round_up
+         tree rounded = round_up   (offset, boundary / BITS_PER_UNIT);
 #endif
-             (ARGS_SIZE_TREE (*offset_ptr),
-              boundary / BITS_PER_UNIT);
-         offset_ptr->constant = 0; /*?*/
-          if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
-            alignment_pad->var = size_binop (MINUS_EXPR, offset_ptr->var,
+
+         offset_ptr->var = size_binop (MINUS_EXPR, rounded, sp_offset_tree);
+         /* ARGS_SIZE_TREE includes constant term.  */
+         offset_ptr->constant = 0;
+         if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
+           alignment_pad->var = size_binop (MINUS_EXPR, offset_ptr->var,
                                             save_var);
        }
       else
        {
-         offset_ptr->constant =
+         offset_ptr->constant = -sp_offset +
 #ifdef ARGS_GROW_DOWNWARD
-           FLOOR_ROUND (offset_ptr->constant, boundary_in_bytes);
+           FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
 #else
-           CEIL_ROUND (offset_ptr->constant, boundary_in_bytes);
+           CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
 #endif
            if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
              alignment_pad->constant = offset_ptr->constant - save_constant;
@@ -5324,12 +5659,8 @@ 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;
-     enum machine_mode passed_mode;
-     tree sizetree;
+pad_below (struct args_size *offset_ptr, enum machine_mode passed_mode, tree sizetree)
 {
   if (passed_mode != BLKmode)
     {
@@ -5352,7 +5683,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.
@@ -5360,39 +5690,38 @@ pad_below (offset_ptr, passed_mode, sizetree)
    clobbers the pseudo-regs to hard regs.  */
 
 void
-uninitialized_vars_warning (block)
-     tree block;
+uninitialized_vars_warning (tree block)
 {
   tree decl, sub;
   for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
     {
       if (warn_uninitialized
-          && TREE_CODE (decl) == VAR_DECL
+         && TREE_CODE (decl) == VAR_DECL
          /* These warnings are unreliable for and aggregates
             because assigning the fields one by one can fail to convince
             flow.c that the entire aggregate was initialized.
             Unions are troublesome because members may be shorter.  */
          && ! AGGREGATE_TYPE_P (TREE_TYPE (decl))
-         && DECL_RTL (decl) != 0
+         && DECL_RTL_SET_P (decl)
          && GET_CODE (DECL_RTL (decl)) == REG
          /* Global optimizations can make it difficult to determine if a
             particular variable has been initialized.  However, a VAR_DECL
             with a nonzero DECL_INITIAL had an initializer, so do not
             claim it is potentially uninitialized.
 
-            We do not care about the actual value in DECL_INITIAL, so we do
-            not worry that it may be a dangling pointer.  */
-         && DECL_INITIAL (decl) == NULL_TREE
+            When the DECL_INITIAL is NULL call the language hook to tell us
+            if we want to warn.  */
+         && (DECL_INITIAL (decl) == NULL_TREE || lang_hooks.decl_uninit (decl))
          && regno_uninitialized (REGNO (DECL_RTL (decl))))
-       warning_with_decl (decl,
-                          "`%s' might be used uninitialized in this function");
+       warning ("%J'%D' might be used uninitialized in this function",
+                decl, decl);
       if (extra_warnings
-          && TREE_CODE (decl) == VAR_DECL
-         && DECL_RTL (decl) != 0
+         && TREE_CODE (decl) == VAR_DECL
+         && DECL_RTL_SET_P (decl)
          && GET_CODE (DECL_RTL (decl)) == REG
          && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
-       warning_with_decl (decl,
-                          "variable `%s' might be clobbered by `longjmp' or `vfork'");
+       warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'",
+                decl, decl);
     }
   for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
     uninitialized_vars_warning (sub);
@@ -5402,7 +5731,7 @@ uninitialized_vars_warning (block)
    but for arguments instead of local variables.  */
 
 void
-setjmp_args_warning ()
+setjmp_args_warning (void)
 {
   tree decl;
   for (decl = DECL_ARGUMENTS (current_function_decl);
@@ -5410,16 +5739,15 @@ setjmp_args_warning ()
     if (DECL_RTL (decl) != 0
        && GET_CODE (DECL_RTL (decl)) == REG
        && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
-      warning_with_decl (decl,
-                        "argument `%s' might be clobbered by `longjmp' or `vfork'");
+      warning ("%Jargument '%D' might be clobbered by `longjmp' or `vfork'",
+              decl, decl);
 }
 
 /* If this function call setjmp, put all vars into the stack
    unless they were declared `register'.  */
 
 void
-setjmp_protect (block)
-     tree block;
+setjmp_protect (tree block)
 {
   tree decl, sub;
   for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
@@ -5443,7 +5771,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);
 }
@@ -5451,7 +5779,7 @@ setjmp_protect (block)
 /* Like the previous function, but for args instead of local variables.  */
 
 void
-setjmp_protect_args ()
+setjmp_protect_args (void)
 {
   tree decl;
   for (decl = DECL_ARGUMENTS (current_function_decl);
@@ -5470,15 +5798,14 @@ 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,
    or 0 if it does not need one.  */
 
 rtx
-lookup_static_chain (decl)
-     tree decl;
+lookup_static_chain (tree decl)
 {
   tree context = decl_function_context (decl);
   tree link;
@@ -5506,9 +5833,7 @@ lookup_static_chain (decl)
    into an address valid in this function (using a static chain).  */
 
 rtx
-fix_lexical_addr (addr, var)
-     rtx addr;
-     tree var;
+fix_lexical_addr (rtx addr, tree var)
 {
   rtx basereg;
   HOST_WIDE_INT displacement;
@@ -5589,8 +5914,7 @@ fix_lexical_addr (addr, var)
    and emit rtl to initialize its contents (at entry to this function).  */
 
 rtx
-trampoline_address (function)
-     tree function;
+trampoline_address (tree function)
 {
   tree link;
   tree rtlexp;
@@ -5622,23 +5946,13 @@ trampoline_address (function)
       && fn_context != inline_function_decl)
     fp = find_function_data (fn_context);
 
-  /* Allocate run-time space for this trampoline
-     (usually in the defining function's stack frame).  */
-#ifdef ALLOCATE_TRAMPOLINE
-  tramp = ALLOCATE_TRAMPOLINE (fp);
-#else
+  /* Allocate run-time space for this trampoline.  */
   /* 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
-
   /* Record the trampoline for reuse and note it for later initialization
      by expand_function_end.  */
   if (fp != 0)
@@ -5666,10 +5980,8 @@ trampoline_address (function)
    round it to multiple of TRAMPOLINE_ALIGNMENT.  */
 
 static rtx
-round_trampoline_addr (tramp)
-     rtx tramp;
+round_trampoline_addr (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);
@@ -5679,7 +5991,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;
 }
 
@@ -5688,8 +6000,7 @@ round_trampoline_addr (tramp)
    function call .  */
 
 static rtx
-adjust_trampoline_addr (tramp)
-     rtx tramp;
+adjust_trampoline_addr (rtx tramp)
 {
   tramp = round_trampoline_addr (tramp);
 #ifdef TRAMPOLINE_ADJUST_ADDRESS
@@ -5706,7 +6017,7 @@ adjust_trampoline_addr (tramp)
    and INSNS, the insn chain of the function.  */
 
 void
-identify_blocks ()
+identify_blocks (void)
 {
   int n_blocks;
   tree *block_vector, *last_block_vector;
@@ -5719,7 +6030,7 @@ identify_blocks ()
   /* Fill the BLOCK_VECTOR with all of the BLOCKs in this function, in
      depth-first order.  */
   block_vector = get_block_vector (block, &n_blocks);
-  block_stack = (tree *) xmalloc (n_blocks * sizeof (tree));
+  block_stack = xmalloc (n_blocks * sizeof (tree));
 
   last_block_vector = identify_blocks_1 (get_insns (),
                                         block_vector + 1,
@@ -5742,11 +6053,8 @@ identify_blocks ()
    BLOCK_VECTOR is incremented for each block seen.  */
 
 static tree *
-identify_blocks_1 (insns, block_vector, end_block_vector, orig_block_stack)
-     rtx insns;
-     tree *block_vector;
-     tree *end_block_vector;
-     tree *orig_block_stack;
+identify_blocks_1 (rtx insns, tree *block_vector, tree *end_block_vector,
+                  tree *orig_block_stack)
 {
   rtx insn;
   tree *block_stack = orig_block_stack;
@@ -5809,7 +6117,7 @@ identify_blocks_1 (insns, block_vector, end_block_vector, orig_block_stack)
    on what optimization has been performed.  */
 
 void
-reorder_blocks ()
+reorder_blocks (void)
 {
   tree block = DECL_INITIAL (current_function_decl);
   varray_type block_stack;
@@ -5832,15 +6140,12 @@ 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.  */
 
 static void
-reorder_blocks_0 (block)
-     tree block;
+reorder_blocks_0 (tree block)
 {
   while (block)
     {
@@ -5851,10 +6156,7 @@ reorder_blocks_0 (block)
 }
 
 static void
-reorder_blocks_1 (insns, current_block, p_block_stack)
-     rtx insns;
-     tree current_block;
-     varray_type *p_block_stack;
+reorder_blocks_1 (rtx insns, tree current_block, varray_type *p_block_stack)
 {
   rtx insn;
 
@@ -5887,10 +6189,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)
@@ -5920,8 +6228,7 @@ reorder_blocks_1 (insns, current_block, p_block_stack)
    the new origin block.  */
 
 static void
-reorder_fix_fragments (block)
-    tree block;
+reorder_fix_fragments (tree block)
 {
   while (block)
     {
@@ -5933,7 +6240,7 @@ reorder_fix_fragments (block)
          if (! TREE_ASM_WRITTEN (dup_origin))
            {
              new_origin = BLOCK_FRAGMENT_CHAIN (dup_origin);
-             
+
              /* Find the first of the remaining fragments.  There must
                 be at least one -- the current block.  */
              while (! TREE_ASM_WRITTEN (new_origin))
@@ -5975,8 +6282,7 @@ reorder_fix_fragments (block)
    and return the new head of the chain (old last element).  */
 
 static tree
-blocks_nreverse (t)
-     tree t;
+blocks_nreverse (tree t)
 {
   tree prev = 0, decl, next;
   for (decl = t; decl; decl = next)
@@ -5994,9 +6300,7 @@ blocks_nreverse (t)
    blocks.  */
 
 static int
-all_blocks (block, vector)
-     tree block;
-     tree *vector;
+all_blocks (tree block, tree *vector)
 {
   int n_blocks = 0;
 
@@ -6025,26 +6329,23 @@ all_blocks (block, vector)
    to call `free' on the pointer returned.  */
 
 static tree *
-get_block_vector (block, n_blocks_p)
-     tree block;
-     int *n_blocks_p;
+get_block_vector (tree block, int *n_blocks_p)
 {
   tree *block_vector;
 
   *n_blocks_p = all_blocks (block, NULL);
-  block_vector = (tree *) xmalloc (*n_blocks_p * sizeof (tree));
+  block_vector = xmalloc (*n_blocks_p * sizeof (tree));
   all_blocks (block, block_vector);
 
   return block_vector;
 }
 
-static int next_block_index = 2;
+static GTY(()) int next_block_index = 2;
 
 /* Set BLOCK_NUMBER for all the blocks in FN.  */
 
 void
-number_blocks (fn)
-     tree fn;
+number_blocks (tree fn)
 {
   int i;
   int n_blocks;
@@ -6069,102 +6370,97 @@ number_blocks (fn)
 
   return;
 }
-\f
-/* Allocate a function structure and reset its contents to the defaults.  */
 
-static void
-prepare_function_start ()
-{
-  cfun = (struct function *) ggc_alloc_cleared (sizeof (struct function));
+/* If VAR is present in a subblock of BLOCK, return the subblock.  */
 
-  init_stmt_for_function ();
-  init_eh_for_function ();
-
-  cse_not_expected = ! optimize;
-
-  /* Caller save not needed yet.  */
-  caller_save_needed = 0;
+tree
+debug_find_var_in_block_tree (tree var, tree block)
+{
+  tree t;
 
-  /* No stack slots have been made yet.  */
-  stack_slot_list = 0;
+  for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t))
+    if (t == var)
+      return block;
 
-  current_function_has_nonlocal_label = 0;
-  current_function_has_nonlocal_goto = 0;
+  for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t))
+    {
+      tree ret = debug_find_var_in_block_tree (var, t);
+      if (ret)
+       return ret;
+    }
 
-  /* There is no stack slot for handling nonlocal gotos.  */
-  nonlocal_goto_handler_slots = 0;
-  nonlocal_goto_stack_level = 0;
+  return NULL_TREE;
+}
+\f
+/* Allocate a function structure for FNDECL and set its contents
+   to the defaults.  */
 
-  /* No labels have been declared for nonlocal use.  */
-  nonlocal_labels = 0;
-  nonlocal_goto_handler_labels = 0;
+void
+allocate_struct_function (tree fndecl)
+{
+  tree result;
 
-  /* No function calls so far in this function.  */
-  function_call_count = 0;
+  cfun = ggc_alloc_cleared (sizeof (struct function));
 
-  /* No parm regs have been allocated.
-     (This is important for output_inline_function.)  */
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
 
-  /* Initialize the RTL mechanism.  */
-  init_emit ();
+  cfun->stack_alignment_needed = STACK_BOUNDARY;
+  cfun->preferred_stack_boundary = STACK_BOUNDARY;
 
-  /* Initialize the queue of pending postincrement and postdecrements,
-     and some other info in expr.c.  */
-  init_expr ();
+  current_function_funcdef_no = funcdef_no++;
 
-  /* We haven't done register allocation yet.  */
-  reg_renumber = 0;
-
-  init_varasm_status (cfun);
+  cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
 
-  /* Clear out data used for inlining.  */
-  cfun->inlinable = 0;
-  cfun->original_decl_initial = 0;
-  cfun->original_arg_vector = 0;
+  init_stmt_for_function ();
+  init_eh_for_function ();
 
-  cfun->stack_alignment_needed = STACK_BOUNDARY;
-  cfun->preferred_stack_boundary = STACK_BOUNDARY;
+  (*lang_hooks.function.init) (cfun);
+  if (init_machine_status)
+    cfun->machine = (*init_machine_status) ();
 
-  /* Set if a call to setjmp is seen.  */
-  current_function_calls_setjmp = 0;
+  if (fndecl == NULL)
+    return;
 
-  /* Set if a call to longjmp is seen.  */
-  current_function_calls_longjmp = 0;
+  DECL_STRUCT_FUNCTION (fndecl) = cfun;
+  cfun->decl = fndecl;
 
-  current_function_calls_alloca = 0;
-  current_function_contains_functions = 0;
-  current_function_is_leaf = 0;
-  current_function_nothrow = 0;
-  current_function_sp_is_unchanging = 0;
-  current_function_uses_only_leaf_regs = 0;
-  current_function_has_computed_jump = 0;
-  current_function_is_thunk = 0;
+  result = DECL_RESULT (fndecl);
+  if (aggregate_value_p (result, fndecl))
+    {
+#ifdef PCC_STATIC_STRUCT_RETURN
+      current_function_returns_pcc_struct = 1;
+#endif
+      current_function_returns_struct = 1;
+    }
 
-  current_function_returns_pcc_struct = 0;
-  current_function_returns_struct = 0;
-  current_function_epilogue_delay_list = 0;
-  current_function_uses_const_pool = 0;
-  current_function_uses_pic_offset_table = 0;
-  current_function_cannot_inline = 0;
+  current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result));
 
-  /* We have not yet needed to make a label to jump to for tail-recursion.  */
-  tail_recursion_label = 0;
+  current_function_needs_context
+    = (decl_function_context (current_function_decl) != 0
+       && ! DECL_NO_STATIC_CHAIN (current_function_decl));
+}
 
-  /* We haven't had a need to make a save area for ap yet.  */
-  arg_pointer_save_area = 0;
+/* Reset cfun, and other non-struct-function variables to defaults as
+   appropriate for emitting rtl at the start of a function.  */
 
-  /* No stack slots allocated yet.  */
-  frame_offset = 0;
+static void
+prepare_function_start (tree fndecl)
+{
+  if (fndecl && DECL_STRUCT_FUNCTION (fndecl))
+    cfun = DECL_STRUCT_FUNCTION (fndecl);
+  else
+    allocate_struct_function (fndecl);
+  init_emit ();
+  init_varasm_status (cfun);
+  init_expr ();
 
-  /* No SAVE_EXPRs in this function yet.  */
-  save_expr_regs = 0;
+  cse_not_expected = ! optimize;
 
-  /* No RTL_EXPRs in this function yet.  */
-  rtl_expr_chain = 0;
+  /* Caller save not needed yet.  */
+  caller_save_needed = 0;
 
-  /* Set up to allocate temporaries.  */
-  init_temp_slots ();
+  /* We haven't done register allocation yet.  */
+  reg_renumber = 0;
 
   /* Indicate that we need to distinguish between the return value of the
      present function and the return value of a function being called.  */
@@ -6178,32 +6474,15 @@ 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;
-  current_function_stdarg = 0;
-
-  /* We haven't made any trampolines for this function yet.  */
-  trampoline_list = 0;
-
-  init_pending_stack_adjust ();
-  inhibit_defer_pop = 0;
-
-  current_function_outgoing_args_size = 0;
-
-  if (init_lang_status)
-    (*init_lang_status) (cfun);
-  if (init_machine_status)
-    (*init_machine_status) (cfun);
 }
 
 /* Initialize the rtl expansion mechanism so that we can do simple things
    like generate sequences.  This is used to provide a context during global
    initialization of some passes.  */
 void
-init_dummy_function_start ()
+init_dummy_function_start (void)
 {
-  prepare_function_start ();
+  prepare_function_start (NULL);
 }
 
 /* Generate RTL for the start of the function SUBR (a FUNCTION_DECL tree node)
@@ -6211,59 +6490,36 @@ init_dummy_function_start ()
    of the function.  */
 
 void
-init_function_start (subr, filename, line)
-     tree subr;
-     const char *filename;
-     int line;
+init_function_start (tree subr)
 {
-  prepare_function_start ();
-
-  current_function_name = (*decl_printable_name) (subr, 2);
-  cfun->decl = subr;
-
-  /* Nonzero if this is a nested function that uses a static chain.  */
-
-  current_function_needs_context
-    = (decl_function_context (current_function_decl) != 0
-       && ! DECL_NO_STATIC_CHAIN (current_function_decl));
+  prepare_function_start (subr);
 
   /* Within function body, compute a type's size as soon it is laid out.  */
   immediate_size_expand++;
 
-  /* Prevent ever trying to delete the first instruction of a function.
-     Also tell final how to output a linenum before the function prologue.
-     Note linenums could be missing, e.g. when compiling a Java .class file.  */
-  if (line > 0)
-    emit_line_note (filename, line);
+  /* Prevent ever trying to delete the first instruction of a
+     function.  Also tell final how to output a linenum before the
+     function prologue.  Note linenums could be missing, e.g. when
+     compiling a Java .class file.  */
+  if (DECL_SOURCE_LINE (subr))
+    emit_line_note (DECL_SOURCE_LOCATION (subr));
 
   /* Make sure first insn is a note even if we don't want linenums.
      This makes sure the first insn will never be deleted.
      Also, final expects a note to appear there.  */
-  emit_note (NULL, NOTE_INSN_DELETED);
-
-  /* Set flags used by final.c.  */
-  if (aggregate_value_p (DECL_RESULT (subr)))
-    {
-#ifdef PCC_STATIC_STRUCT_RETURN
-      current_function_returns_pcc_struct = 1;
-#endif
-      current_function_returns_struct = 1;
-    }
+  emit_note (NOTE_INSN_DELETED);
 
   /* Warn if this value is an aggregate type,
      regardless of which calling convention we are using for it.  */
   if (warn_aggregate_return
       && AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr))))
     warning ("function returns an aggregate");
-
-  current_function_returns_pointer
-    = POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (subr)));
 }
 
 /* Make sure all values used by the optimization passes have sane
    defaults.  */
 void
-init_function_for_compilation ()
+init_function_for_compilation (void)
 {
   reg_renumber = 0;
 
@@ -6273,15 +6529,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)
@@ -6290,14 +6537,15 @@ mark_varargs ()
 #endif
 
 void
-expand_main_function ()
+expand_main_function (void)
 {
 #ifdef FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
   if (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN)
     {
       int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
-      rtx tmp;
+      rtx tmp, seq;
 
+      start_sequence ();
       /* Forcibly align the stack.  */
 #ifdef STACK_GROWS_DOWNWARD
       tmp = expand_simple_binop (Pmode, AND, stack_pointer_rtx, GEN_INT(-align),
@@ -6310,21 +6558,28 @@ expand_main_function ()
 #endif
       if (tmp != stack_pointer_rtx)
        emit_move_insn (stack_pointer_rtx, tmp);
-      
+
       /* 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 = get_insns ();
+      end_sequence ();
+
+      for (tmp = get_last_insn (); tmp; tmp = PREV_INSN (tmp))
+       if (NOTE_P (tmp) && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_FUNCTION_BEG)
+         break;
+      if (tmp)
+       emit_insn_before (seq, tmp);
+      else
+       emit_insn (seq);
     }
 #endif
 
 #ifndef HAS_INIT_SECTION
-  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), 0,
-                    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
@@ -6332,16 +6587,14 @@ extern struct obstack permanent_obstack;
    TREE_VALUE of each node is a SAVE_EXPR.  */
 
 void
-expand_pending_sizes (pending_sizes)
-     tree pending_sizes;
+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,
-                  EXPAND_MEMORY_USE_BAD);
+      expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
       /* Flush the queue in case this parameter declaration has
         side-effects.  */
       emit_queue ();
@@ -6355,9 +6608,7 @@ expand_pending_sizes (pending_sizes)
    the function's parameters, which must be run at any return statement.  */
 
 void
-expand_function_start (subr, parms_have_cleanups)
-     tree subr;
-     int parms_have_cleanups;
+expand_function_start (tree subr, int parms_have_cleanups)
 {
   tree tem;
   rtx last_ptr = NULL_RTX;
@@ -6366,15 +6617,14 @@ expand_function_start (subr, parms_have_cleanups)
      valid operands of arithmetic insns.  */
   init_recog_no_volatile ();
 
-  /* Set this before generating any memory accesses.  */
-  current_function_check_memory_usage
-    = (flag_check_memory_usage
-       && ! DECL_NO_CHECK_MEMORY_USAGE (current_function_decl));
-
   current_function_instrument_entry_exit
     = (flag_instrument_function_entry_exit
        && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
 
+  current_function_profile
+    = (profile_flag
+       && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
+
   current_function_limit_stack
     = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
 
@@ -6409,7 +6659,7 @@ expand_function_start (subr, parms_have_cleanups)
      before any library calls that assign parms might generate.  */
 
   /* Decide whether to return the value in memory or in a register.  */
-  if (aggregate_value_p (DECL_RESULT (subr)))
+  if (aggregate_value_p (DECL_RESULT (subr), subr))
     {
       /* Returning something that won't go in a register.  */
       rtx value_address = 0;
@@ -6423,13 +6673,14 @@ expand_function_start (subr, parms_have_cleanups)
       else
 #endif
        {
+         rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 1);
          /* Expect to be passed the address of a place to store the value.
             If it is passed as an argument, assign_parms will take care of
             it.  */
-         if (struct_value_incoming_rtx)
+         if (sv)
            {
              value_address = gen_reg_rtx (Pmode);
-             emit_move_insn (value_address, struct_value_incoming_rtx);
+             emit_move_insn (value_address, sv);
            }
        }
       if (value_address)
@@ -6455,18 +6706,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.
@@ -6478,17 +6728,17 @@ expand_function_start (subr, parms_have_cleanups)
      avoid conflicts with the parameter passing registers.  */
 
   if (SMALL_REGISTER_CLASSES && current_function_needs_context)
-      if (GET_CODE (static_chain_incoming_rtx) != REG)
-        emit_move_insn (last_ptr, static_chain_incoming_rtx);
+    if (GET_CODE (static_chain_incoming_rtx) != REG)
+      emit_move_insn (last_ptr, static_chain_incoming_rtx);
 
   /* The following was moved from init_function_start.
      The move is supposed to make sdb output more accurate.  */
   /* Indicate the beginning of the function body,
      as opposed to parm setup.  */
-  emit_note (NULL, NOTE_INSN_FUNCTION_BEG);
+  emit_note (NOTE_INSN_FUNCTION_BEG);
 
   if (GET_CODE (get_last_insn ()) != NOTE)
-    emit_note (NULL, NOTE_INSN_DELETED);
+    emit_note (NOTE_INSN_DELETED);
   parm_birth_insn = get_last_insn ();
 
   context_display = 0;
@@ -6519,7 +6769,7 @@ expand_function_start (subr, parms_have_cleanups)
          tem = decl_function_context (tem);
          if (tem == 0)
            break;
-         /* Chain thru stack frames, assuming pointer to next lexical frame
+         /* Chain through stack frames, assuming pointer to next lexical frame
             is found at the place we always store it.  */
 #ifdef FRAME_GROWS_DOWNWARD
          last_ptr = plus_constant (last_ptr,
@@ -6544,23 +6794,25 @@ expand_function_start (subr, parms_have_cleanups)
        fun = XEXP (fun, 0);
       else
        abort ();
-      emit_library_call (profile_function_entry_libfunc, 0, VOIDmode, 2,
-                        fun, Pmode,
+      emit_library_call (profile_function_entry_libfunc, LCT_NORMAL, VOIDmode,
+                        2, fun, Pmode,
                         expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
                                                     0,
                                                     hard_frame_pointer_rtx),
                         Pmode);
     }
 
+  if (current_function_profile)
+    {
 #ifdef PROFILE_HOOK
-  if (profile_flag)
-    PROFILE_HOOK (profile_label_no);
+      PROFILE_HOOK (current_function_funcdef_no);
 #endif
+    }
 
   /* After the display initializations is where the tail-recursion label
      should go, if we end up needing one.   Ensure we have a NOTE here
      since some things (like trampolines) get placed before this.  */
-  tail_recursion_reentry = emit_note (NULL, NOTE_INSN_DELETED);
+  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 ()));
@@ -6571,7 +6823,7 @@ expand_function_start (subr, parms_have_cleanups)
 \f
 /* Undo the effects of init_dummy_function_start.  */
 void
-expand_dummy_function_end ()
+expand_dummy_function_end (void)
 {
   /* End any sequences that failed to be closed due to syntax errors.  */
   while (in_sequence_p ())
@@ -6589,9 +6841,7 @@ expand_dummy_function_end ()
    the current function.  */
 
 void
-diddle_return_value (doit, arg)
-     void (*doit) PARAMS ((rtx, void *));
-     void *arg;
+diddle_return_value (void (*doit) (rtx, void *), void *arg)
 {
   rtx outgoing = current_function_return_rtx;
 
@@ -6615,15 +6865,13 @@ diddle_return_value (doit, arg)
 }
 
 static void
-do_clobber_return_reg (reg, arg)
-     rtx reg;
-     void *arg ATTRIBUTE_UNUSED;
+do_clobber_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED)
 {
   emit_insn (gen_rtx_CLOBBER (VOIDmode, reg));
 }
 
 void
-clobber_return_register ()
+clobber_return_register (void)
 {
   diddle_return_value (do_clobber_return_reg, NULL);
 
@@ -6640,38 +6888,27 @@ clobber_return_register ()
 }
 
 static void
-do_use_return_reg (reg, arg)
-     rtx reg;
-     void *arg ATTRIBUTE_UNUSED;
+do_use_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED)
 {
   emit_insn (gen_rtx_USE (VOIDmode, reg));
 }
 
 void
-use_return_register ()
+use_return_register (void)
 {
   diddle_return_value (do_use_return_reg, NULL);
 }
 
-/* Generate RTL for the end of the current function.
-   FILENAME and LINE are the current position in the source file.
+static GTY(()) rtx initial_trampoline;
 
-   It is up to language-specific callers to do cleanups for parameters--
-   or else, supply 1 for END_BINDINGS and we will call expand_end_bindings.  */
+/* Generate RTL for the end of the current function.  */
 
 void
-expand_function_end (filename, line, end_bindings)
-     const char *filename;
-     int line;
-     int end_bindings;
+expand_function_end (void)
 {
   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
@@ -6709,8 +6946,7 @@ expand_function_end (filename, line, end_bindings)
        {
          initial_trampoline
            = gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
-
-         ggc_add_rtx_root (&initial_trampoline, 1);
+         set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
        }
 #endif
 
@@ -6718,17 +6954,17 @@ expand_function_end (filename, line, end_bindings)
       start_sequence ();
       tramp = round_trampoline_addr (XEXP (tramp, 0));
 #ifdef TRAMPOLINE_TEMPLATE
-      blktramp = change_address (initial_trampoline, BLKmode, tramp);
+      blktramp = replace_equiv_address (initial_trampoline, tramp);
       emit_block_move (blktramp, initial_trampoline,
-                      GEN_INT (TRAMPOLINE_SIZE),
-                      TRAMPOLINE_ALIGNMENT);
+                      GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
 #endif
+      trampolines_created = 1;
       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,
@@ -6746,17 +6982,13 @@ 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
-     warning.  WARN_UNUSED_PARAMETER is negative when set by
-     -Wunused.  */
-  if (warn_unused_parameter > 0
-      || (warn_unused_parameter < 0 && extra_warnings))
+  /* Possibly warn about unused parameters.  */
+  if (warn_unused_parameter)
     {
       tree decl;
 
@@ -6764,7 +6996,7 @@ expand_function_end (filename, line, end_bindings)
           decl; decl = TREE_CHAIN (decl))
        if (! TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
            && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
-         warning_with_decl (decl, "unused parameter `%s'");
+          warning ("%Junused parameter '%D'", decl, decl);
     }
 
   /* Delete handlers for nonlocal gotos if nothing uses them.  */
@@ -6786,7 +7018,7 @@ expand_function_end (filename, line, end_bindings)
   /* Mark the end of the function body.
      If control reaches this insn, the function can drop through
      without returning a value.  */
-  emit_note (NULL, NOTE_INSN_FUNCTION_END);
+  emit_note (NOTE_INSN_FUNCTION_END);
 
   /* Must mark the last line number note in the function, so that the test
      coverage code can avoid counting the last line twice.  This just tells
@@ -6794,14 +7026,15 @@ expand_function_end (filename, line, end_bindings)
      already exists a copy of this note somewhere above.  This line number
      note is still needed for debugging though, so we can't delete it.  */
   if (flag_test_coverage)
-    emit_note (NULL, NOTE_INSN_REPEATED_LINE_NUMBER);
+    emit_note (NOTE_INSN_REPEATED_LINE_NUMBER);
 
   /* Output a linenumber for the end of the function.
      SDB depends on this.  */
-  emit_line_note_force (filename, line);
+  force_next_line_note ();
+  emit_line_note (input_location);
 
   /* Before the return label (if any), clobber the return
-     registers so that they are not propogated live to the rest of
+     registers so that they are not propagated live to the rest of
      the function.  This can only happen with functions that drop
      through; if there had been a return statement, there would
      have either been a return rtx, or a jump to the return label.
@@ -6818,10 +7051,6 @@ expand_function_end (filename, line, end_bindings)
   if (return_label)
     emit_label (return_label);
 
-  /* C++ uses this.  */
-  if (end_bindings)
-    expand_end_bindings (0, 0, 0);
-
   if (current_function_instrument_entry_exit)
     {
       rtx fun = DECL_RTL (current_function_decl);
@@ -6829,8 +7058,8 @@ expand_function_end (filename, line, end_bindings)
        fun = XEXP (fun, 0);
       else
        abort ();
-      emit_library_call (profile_function_exit_libfunc, 0, VOIDmode, 2,
-                        fun, Pmode,
+      emit_library_call (profile_function_exit_libfunc, LCT_NORMAL, VOIDmode,
+                        2, fun, Pmode,
                         expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
                                                     0,
                                                     hard_frame_pointer_rtx),
@@ -6845,16 +7074,14 @@ expand_function_end (filename, line, end_bindings)
   /* 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.  */
-#ifdef EXIT_IGNORE_STACK
-  if (! EXIT_IGNORE_STACK)
-#endif
-    if (current_function_calls_alloca)
-      {
-       rtx tem = 0;
+  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);
-      }
+      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
@@ -6868,49 +7095,46 @@ expand_function_end (filename, line, end_bindings)
          ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER
          : DECL_REGISTER (decl_result))
        {
-         rtx real_decl_rtl;
+         rtx real_decl_rtl = current_function_return_rtx;
 
-#ifdef FUNCTION_OUTGOING_VALUE
-         real_decl_rtl = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl_result),
-                                                  current_function_decl);
-#else
-         real_decl_rtl = FUNCTION_VALUE (TREE_TYPE (decl_result),
-                                         current_function_decl);
-#endif
-         REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
+         /* This should be set in assign_parms.  */
+         if (! REG_FUNCTION_VALUE_P (real_decl_rtl))
+           abort ();
 
          /* If this is a BLKmode structure being returned in registers,
             then use the mode computed in expand_return.  Note that if
-            decl_rtl is memory, then its mode may have been changed, 
+            decl_rtl is memory, then its mode may have been changed,
             but that current_function_return_rtx has not.  */
          if (GET_MODE (real_decl_rtl) == BLKmode)
-           PUT_MODE (real_decl_rtl, GET_MODE (current_function_return_rtx));
+           PUT_MODE (real_decl_rtl, GET_MODE (decl_rtl));
 
          /* If a named return value dumped decl_return to memory, then
-            we may need to re-do the PROMOTE_MODE signed/unsigned 
+            we may need to re-do the PROMOTE_MODE signed/unsigned
             extension.  */
          if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
            {
              int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result));
 
-#ifdef PROMOTE_FUNCTION_RETURN
-             promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
-                           &unsignedp, 1);
-#endif
+             if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
+               promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
+                             &unsignedp, 1);
 
              convert_move (real_decl_rtl, decl_rtl, unsignedp);
            }
          else if (GET_CODE (real_decl_rtl) == PARALLEL)
-           emit_group_load (real_decl_rtl, decl_rtl,
-                            int_size_in_bytes (TREE_TYPE (decl_result)),
-                            TYPE_ALIGN (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,
+                                TREE_TYPE (decl_result),
+                                int_size_in_bytes (TREE_TYPE (decl_result)));
+           }
          else
            emit_move_insn (real_decl_rtl, decl_rtl);
-
-         /* The delay slot scheduler assumes that current_function_return_rtx
-            holds the hard register containing the return value, not a
-            temporary pseudo.  */
-         current_function_return_rtx = real_decl_rtl;
        }
     }
 
@@ -6939,12 +7163,9 @@ expand_function_end (filename, line, end_bindings)
         assignment and USE below when inlining this function.  */
       REG_FUNCTION_VALUE_P (outgoing) = 1;
 
-#ifdef POINTERS_EXTEND_UNSIGNED
       /* The address may be ptr_mode and OUTGOING may be Pmode.  */
-      if (GET_MODE (outgoing) != GET_MODE (value_address))
-       value_address = convert_memory_address (GET_MODE (outgoing),
-                                               value_address);
-#endif
+      value_address = convert_memory_address (GET_MODE (outgoing),
+                                             value_address);
 
       emit_move_insn (outgoing, value_address);
 
@@ -6960,18 +7181,23 @@ expand_function_end (filename, line, end_bindings)
   /* Emit the actual code to clobber return register.  */
   {
     rtx seq, after;
-    
+
     start_sequence ();
     clobber_return_register ();
-    seq = gen_sequence ();
+    seq = get_insns ();
     end_sequence ();
 
     after = emit_insn_after (seq, clobber_after);
-    
+
     if (clobber_after != after)
       cfun->x_clobber_return_insn = 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);
+
   /* ??? This should no longer be necessary since stupid is no longer with
      us, but there are some parts of the compiler (eg reload_combine, and
      sh mach_dep_reorg) that still try and compute their own lifetime info
@@ -6989,8 +7215,7 @@ expand_function_end (filename, line, end_bindings)
 }
 
 rtx
-get_arg_pointer_save_area (f)
-     struct function *f;
+get_arg_pointer_save_area (struct function *f)
 {
   rtx ret = f->x_arg_pointer_save_area;
 
@@ -7004,12 +7229,12 @@ get_arg_pointer_save_area (f)
     {
       rtx seq;
 
-      /* Save the arg pointer at the beginning of the function.  The 
+      /* Save the arg pointer at the beginning of the function.  The
         generated stack slot may not be a valid memory address, so we
         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 ();
@@ -7020,40 +7245,51 @@ 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;
+record_insns (rtx insns, varray_type *vecp)
 {
-  if (GET_CODE (insns) == SEQUENCE)
+  int i, len;
+  rtx tmp;
+
+  tmp = insns;
+  len = 0;
+  while (tmp != NULL_RTX)
     {
-      int len = XVECLEN (insns, 0);
-      int i = VARRAY_SIZE (*vecp);
+      len++;
+      tmp = NEXT_INSN (tmp);
+    }
 
-      VARRAY_GROW (*vecp, i + len);
-      while (--len >= 0)
-       {
-         VARRAY_INT (*vecp, i) = INSN_UID (XVECEXP (insns, 0, len));
-         ++i;
-       }
+  i = VARRAY_SIZE (*vecp);
+  VARRAY_GROW (*vecp, i + len);
+  tmp = insns;
+  while (tmp != NULL_RTX)
+    {
+      VARRAY_INT (*vecp, i) = INSN_UID (tmp);
+      i++;
+      tmp = NEXT_INSN (tmp);
     }
-  else
+}
+
+/* Set the locator of the insn chain starting at INSN to LOC.  */
+static void
+set_insn_locators (rtx insn, int loc)
+{
+  while (insn != NULL_RTX)
     {
-      int i = VARRAY_SIZE (*vecp);
-      VARRAY_GROW (*vecp, i + 1);
-      VARRAY_INT (*vecp, i) = INSN_UID (insns);
+      if (INSN_P (insn))
+       INSN_LOCATOR (insn) = loc;
+      insn = NEXT_INSN (insn);
     }
 }
 
-/* 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)
-     rtx insn;
-     varray_type vec;
+contains (rtx insn, varray_type vec)
 {
   int i, j;
 
@@ -7077,8 +7313,7 @@ contains (insn, vec)
 }
 
 int
-prologue_epilogue_contains (insn)
-     rtx insn;
+prologue_epilogue_contains (rtx insn)
 {
   if (contains (insn, prologue))
     return 1;
@@ -7088,8 +7323,7 @@ prologue_epilogue_contains (insn)
 }
 
 int
-sibcall_epilogue_contains (insn)
-     rtx insn;
+sibcall_epilogue_contains (rtx insn)
 {
   if (sibcall_epilogue)
     return contains (insn, sibcall_epilogue);
@@ -7101,80 +7335,381 @@ sibcall_epilogue_contains (insn)
    block_for_insn appropriately.  */
 
 static void
-emit_return_into_block (bb, line_note)
-     basic_block bb;
-     rtx line_note;
+emit_return_into_block (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 (bb));
   if (line_note)
-    emit_line_note_after (NOTE_SOURCE_FILE (line_note),
-                         NOTE_LINE_NUMBER (line_note), PREV_INSN (bb->end));
+    emit_note_copy_after (line_note, PREV_INSN (BB_END (bb)));
 }
 #endif /* HAVE_return */
 
-#ifdef HAVE_epilogue
+#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.  */
+
+struct epi_info
+{
+  rtx sp_equiv_reg;            /* REG that SP is set from, perhaps SP.  */
+  HOST_WIDE_INT sp_offset;     /* Offset from SP_EQUIV_REG of present SP.  */
+  rtx new_sp_equiv_reg;                /* REG to be used at end of insn.  */
+  HOST_WIDE_INT new_sp_offset; /* Offset to be used at end of insn.  */
+  rtx equiv_reg_src;           /* If nonzero, the value that SP_EQUIV_REG
+                                  should be set to once we no longer need
+                                  its value.  */
+  rtx const_equiv[FIRST_PSEUDO_REGISTER]; /* Any known constant equivalences
+                                            for registers.  */
+};
 
-/* Modify SEQ, a SEQUENCE that is part of the epilogue, to no modifications
-   to the stack pointer.  */
+static void handle_epilogue_set (rtx, struct epi_info *);
+static void update_epilogue_consts (rtx, rtx, void *);
+static void emit_equiv_load (struct epi_info *);
 
-static void
-keep_stack_depressed (seq)
-     rtx seq;
+/* 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 (rtx insns)
 {
-  int i;
-  rtx sp_from_reg = 0;
-  int sp_modified_unknown = 0;
+  int j;
+  struct epi_info info;
+  rtx insn, next;
 
-  /* If the epilogue is just a single instruction, it's OK as is */
+  /* If the epilogue is just a single instruction, it must be OK as is.  */
+  if (NEXT_INSN (insns) == NULL_RTX)
+    return insns;
 
-  if (GET_CODE (seq) != SEQUENCE)
-    return;
+  /* Otherwise, start a sequence, initialize the information we have, and
+     process all the insns we were given.  */
+  start_sequence ();
+
+  info.sp_equiv_reg = stack_pointer_rtx;
+  info.sp_offset = 0;
+  info.equiv_reg_src = 0;
 
-  /* Scan all insns in SEQ looking for ones that modified the stack
-     pointer.  Record if it modified the stack pointer by copying it
-     from the frame pointer or if it modified it in some other way.
-     Then modify any subsequent stack pointer references to take that
-     into account.  We start by only allowing SP to be copied from a
-     register (presumably FP) and then be subsequently referenced.  */
+  for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+    info.const_equiv[j] = 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 (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
-       continue;
+      if (!INSN_P (insn))
+       {
+         add_insn (insn);
+         insn = next;
+         continue;
+       }
 
-      if (reg_set_p (stack_pointer_rtx, insn))
+      /* If this insn references the register that SP is equivalent to and
+        we have a pending load to that register, we must force out the load
+        first and then indicate we no longer know what SP's equivalent is.  */
+      if (info.equiv_reg_src != 0
+         && reg_referenced_p (info.sp_equiv_reg, PATTERN (insn)))
        {
-         rtx set = single_set (insn);
+         emit_equiv_load (&info);
+         info.sp_equiv_reg = 0;
+       }
 
-         /* If SP is set as a side-effect, we can't support this.  */
-         if (set == 0)
+      info.new_sp_equiv_reg = info.sp_equiv_reg;
+      info.new_sp_offset = info.sp_offset;
+
+      /* If this is a (RETURN) and the return address is on the stack,
+        update the address and change to an indirect jump.  */
+      if (GET_CODE (PATTERN (insn)) == RETURN
+         || (GET_CODE (PATTERN (insn)) == PARALLEL
+             && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))
+       {
+         rtx retaddr = INCOMING_RETURN_ADDR_RTX;
+         rtx base = 0;
+         HOST_WIDE_INT offset = 0;
+         rtx jump_insn, jump_set;
+
+         /* If the return address is in a register, we can emit the insn
+            unchanged.  Otherwise, it must be a MEM and we see what the
+            base register and offset are.  In any case, we have to emit any
+            pending load to the equivalent reg of SP, if any.  */
+         if (GET_CODE (retaddr) == REG)
+           {
+             emit_equiv_load (&info);
+             add_insn (insn);
+             insn = next;
+             continue;
+           }
+         else if (GET_CODE (retaddr) == MEM
+                  && GET_CODE (XEXP (retaddr, 0)) == REG)
+           base = gen_rtx_REG (Pmode, REGNO (XEXP (retaddr, 0))), offset = 0;
+         else if (GET_CODE (retaddr) == MEM
+                  && GET_CODE (XEXP (retaddr, 0)) == PLUS
+                  && GET_CODE (XEXP (XEXP (retaddr, 0), 0)) == REG
+                  && GET_CODE (XEXP (XEXP (retaddr, 0), 1)) == CONST_INT)
+           {
+             base = gen_rtx_REG (Pmode, REGNO (XEXP (XEXP (retaddr, 0), 0)));
+             offset = INTVAL (XEXP (XEXP (retaddr, 0), 1));
+           }
+         else
            abort ();
 
-         if (GET_CODE (SET_SRC (set)) == REG)
-           sp_from_reg = SET_SRC (set);
+         /* If the base of the location containing the return pointer
+            is SP, we must update it with the replacement address.  Otherwise,
+            just build the necessary MEM.  */
+         retaddr = plus_constant (base, offset);
+         if (base == stack_pointer_rtx)
+           retaddr = simplify_replace_rtx (retaddr, stack_pointer_rtx,
+                                           plus_constant (info.sp_equiv_reg,
+                                                          info.sp_offset));
+
+         retaddr = gen_rtx_MEM (Pmode, retaddr);
+
+         /* If there is a pending load to the equivalent register for SP
+            and we reference that register, we must load our address into
+            a scratch register and then do that load.  */
+         if (info.equiv_reg_src
+             && reg_overlap_mentioned_p (info.equiv_reg_src, retaddr))
+           {
+             unsigned int regno;
+             rtx reg;
+
+             for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+               if (HARD_REGNO_MODE_OK (regno, Pmode)
+                   && !fixed_regs[regno]
+                   && TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)
+                   && !REGNO_REG_SET_P (EXIT_BLOCK_PTR->global_live_at_start,
+                                        regno)
+                   && !refers_to_regno_p (regno,
+                                          regno + hard_regno_nregs[regno]
+                                                                  [Pmode],
+                                          info.equiv_reg_src, NULL)
+                   && info.const_equiv[regno] == 0)
+                 break;
+
+             if (regno == FIRST_PSEUDO_REGISTER)
+               abort ();
+
+             reg = gen_rtx_REG (Pmode, regno);
+             emit_move_insn (reg, retaddr);
+             retaddr = reg;
+           }
+
+         emit_equiv_load (&info);
+         jump_insn = emit_jump_insn (gen_indirect_jump (retaddr));
+
+         /* Show the SET in the above insn is a RETURN.  */
+         jump_set = single_set (jump_insn);
+         if (jump_set == 0)
+           abort ();
          else
-           sp_modified_unknown = 1;
+           SET_IS_RETURN_P (jump_set) = 1;
+       }
+
+      /* If SP is not mentioned in the pattern and its equivalent register, if
+        any, is not modified, just emit it.  Otherwise, if neither is set,
+        replace the reference to SP and emit the insn.  If none of those are
+        true, handle each SET individually.  */
+      else if (!reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))
+              && (info.sp_equiv_reg == stack_pointer_rtx
+                  || !reg_set_p (info.sp_equiv_reg, insn)))
+       add_insn (insn);
+      else if (! reg_set_p (stack_pointer_rtx, insn)
+              && (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 ();
 
-         /* Don't allow the SP modification to happen.  We don't call
-            delete_insn here since INSN isn't in any chain.  */
-         PUT_CODE (insn, NOTE);
-         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-         NOTE_SOURCE_FILE (insn) = 0;
+         add_insn (insn);
        }
-      else if (reg_referenced_p (stack_pointer_rtx, PATTERN (insn)))
+      else if (GET_CODE (PATTERN (insn)) == SET)
+       handle_epilogue_set (PATTERN (insn), &info);
+      else if (GET_CODE (PATTERN (insn)) == PARALLEL)
        {
-         if (sp_modified_unknown)
+         for (j = 0; j < XVECLEN (PATTERN (insn), 0); j++)
+           if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET)
+             handle_epilogue_set (XVECEXP (PATTERN (insn), 0, j), &info);
+       }
+      else
+       add_insn (insn);
+
+      info.sp_equiv_reg = info.new_sp_equiv_reg;
+      info.sp_offset = info.new_sp_offset;
+
+      /* Now update any constants this insn sets.  */
+      note_stores (PATTERN (insn), update_epilogue_consts, &info);
+      insn = next;
+    }
+
+  insns = get_insns ();
+  end_sequence ();
+  return insns;
+}
+
+/* SET is a SET from an insn in the epilogue.  P is a pointer to the epi_info
+   structure that contains information about what we've seen so far.  We
+   process this SET by either updating that data or by emitting one or
+   more insns.  */
+
+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.  */
+  if (reg_set_p (stack_pointer_rtx, set))
+    {
+      if (SET_DEST (set) != stack_pointer_rtx)
+       abort ();
+
+      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 (GET_CODE (XEXP (SET_SRC (set), 1)) == REG
+                  && 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 ();
+       }
+      else
+       p->new_sp_equiv_reg = SET_SRC (set), p->new_sp_offset = 0;
 
-         else if (sp_from_reg != 0)
-           PATTERN (insn)
-             = replace_rtx (PATTERN (insn), stack_pointer_rtx, sp_from_reg);
+      /* If we are adjusting SP, we adjust from the old data.  */
+      if (p->new_sp_equiv_reg == stack_pointer_rtx)
+       {
+         p->new_sp_equiv_reg = p->sp_equiv_reg;
+         p->new_sp_offset += p->sp_offset;
        }
+
+      if (p->new_sp_equiv_reg == 0 || GET_CODE (p->new_sp_equiv_reg) != REG)
+       abort ();
+
+      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).  */
+  else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set))
+    {
+      if (p->equiv_reg_src != 0
+         || GET_CODE (p->new_sp_equiv_reg) != REG
+         || GET_CODE (SET_DEST (set)) != REG
+         || 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));
+    }
+
+  /* Otherwise, replace any references to SP in the insn to its new value
+     and emit the insn.  */
+  else
+    {
+      SET_SRC (set) = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
+                                           plus_constant (p->sp_equiv_reg,
+                                                          p->sp_offset));
+      SET_DEST (set) = simplify_replace_rtx (SET_DEST (set), stack_pointer_rtx,
+                                            plus_constant (p->sp_equiv_reg,
+                                                           p->sp_offset));
+      emit_insn (set);
+    }
+}
+
+/* Update the tracking information for registers set to constants.  */
+
+static void
+update_epilogue_consts (rtx dest, rtx x, void *data)
+{
+  struct epi_info *p = (struct epi_info *) data;
+  rtx new;
+
+  if (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
+    return;
+
+  /* If we are either clobbering a register or doing a partial set,
+     show we don't know the value.  */
+  else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x)))
+    p->const_equiv[REGNO (dest)] = 0;
+
+  /* If we are setting it to a constant, record that constant.  */
+  else if (GET_CODE (SET_SRC (x)) == CONST_INT)
+    p->const_equiv[REGNO (dest)] = SET_SRC (x);
+
+  /* If this is a binary operation between a register we have been tracking
+     and a constant, see if we can compute a new constant value.  */
+  else if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
+           || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2')
+          && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
+          && REGNO (XEXP (SET_SRC (x), 0)) < FIRST_PSEUDO_REGISTER
+          && p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))] != 0
+          && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
+          && 0 != (new = simplify_binary_operation
+                   (GET_CODE (SET_SRC (x)), GET_MODE (dest),
+                    p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))],
+                    XEXP (SET_SRC (x), 1)))
+          && GET_CODE (new) == CONST_INT)
+    p->const_equiv[REGNO (dest)] = new;
+
+  /* Otherwise, we can't do anything with this value.  */
+  else
+    p->const_equiv[REGNO (dest)] = 0;
+}
+
+/* Emit an insn to do the load shown in p->equiv_reg_src, if needed.  */
+
+static void
+emit_equiv_load (struct epi_info *p)
+{
+  if (p->equiv_reg_src != 0)
+    {
+      rtx dest = p->sp_equiv_reg;
+
+      if (GET_MODE (p->equiv_reg_src) != GET_MODE (dest))
+       dest = gen_rtx_REG (GET_MODE (p->equiv_reg_src),
+                           REGNO (p->sp_equiv_reg));
+
+      emit_move_insn (dest, p->equiv_reg_src);
+      p->equiv_reg_src = 0;
     }
 }
 #endif
@@ -7184,12 +7719,13 @@ keep_stack_depressed (seq)
    the epilogue begins.  Update the basic block information when possible.  */
 
 void
-thread_prologue_and_epilogue_insns (f)
-     rtx f ATTRIBUTE_UNUSED;
+thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
 {
   int inserted = 0;
   edge e;
+#if defined (HAVE_sibcall_epilogue) || defined (HAVE_epilogue) || defined (HAVE_return) || defined (HAVE_prologue)
   rtx seq;
+#endif
 #ifdef HAVE_prologue
   rtx prologue_end = NULL_RTX;
 #endif
@@ -7205,15 +7741,14 @@ 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);
+      prologue_end = emit_note (NOTE_INSN_PROLOGUE_END);
 
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
+      set_insn_locators (seq, prologue_locator);
 
-      /* Can't deal with multiple successsors of the entry block
+      /* 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)
@@ -7253,7 +7788,7 @@ thread_prologue_and_epilogue_insns (f)
       last = e->src;
 
       /* Verify that there are no active instructions in the last block.  */
-      label = last->end;
+      label = BB_END (last);
       while (label && GET_CODE (label) != CODE_LABEL)
        {
          if (active_insn_p (label))
@@ -7261,7 +7796,7 @@ thread_prologue_and_epilogue_insns (f)
          label = PREV_INSN (label);
        }
 
-      if (last->head == label && GET_CODE (label) == CODE_LABEL)
+      if (BB_HEAD (last) == label && GET_CODE (label) == CODE_LABEL)
        {
          rtx epilogue_line_note = NULL_RTX;
 
@@ -7285,7 +7820,7 @@ thread_prologue_and_epilogue_insns (f)
              if (bb == ENTRY_BLOCK_PTR)
                continue;
 
-             jump = bb->end;
+             jump = BB_END (bb);
              if ((GET_CODE (jump) != JUMP_INSN) || JUMP_LABEL (jump) != label)
                continue;
 
@@ -7301,19 +7836,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
@@ -7331,9 +7855,9 @@ thread_prologue_and_epilogue_insns (f)
          /* Emit a return insn for the exit fallthru block.  Whether
             this is still reachable will be determined later.  */
 
-         emit_barrier_after (last->end);
+         emit_barrier_after (BB_END (last));
          emit_return_into_block (last, epilogue_line_note);
-         epilogue_end = last->end;
+         epilogue_end = BB_END (last);
          last->succ->flags &= ~EDGE_FALLTHRU;
          goto epilogue_done;
        }
@@ -7354,24 +7878,25 @@ thread_prologue_and_epilogue_insns (f)
        goto epilogue_done;
 
       start_sequence ();
-      epilogue_end = emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
+      epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
 
       seq = gen_epilogue ();
 
-      /* If this function returns with the stack depressed, massage
-        the epilogue to actually do that.  */
+#ifdef INCOMING_RETURN_ADDR_RTX
+      /* If this function returns with the stack depressed and we can support
+        it, massage the epilogue to actually do that.  */
       if (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
          && TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (current_function_decl)))
-       keep_stack_depressed (seq);
+       seq = keep_stack_depressed (seq);
+#endif
 
       emit_jump_insn (seq);
 
       /* Retain a map of the epilogue insns.  */
-      if (GET_CODE (seq) != SEQUENCE)
-       seq = get_insns ();
       record_insns (seq, &epilogue);
+      set_insn_locators (seq, epilogue_locator);
 
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
 
       insert_insn_on_edge (seq, e);
@@ -7388,7 +7913,7 @@ epilogue_done:
   for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
     {
       basic_block bb = e->src;
-      rtx insn = bb->end;
+      rtx insn = BB_END (bb);
       rtx i;
       rtx newinsn;
 
@@ -7397,20 +7922,23 @@ 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);
+      set_insn_locators (seq, epilogue_locator);
+
       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
 
 #ifdef HAVE_prologue
+  /* This is probably all useless now that we use locators.  */
   if (prologue_end)
     {
       rtx insn, prev;
@@ -7422,7 +7950,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.
@@ -7443,7 +7971,7 @@ epilogue_done:
        }
 
       /* Find the last line number note in the first block.  */
-      for (insn = BASIC_BLOCK (0)->end;
+      for (insn = BB_END (ENTRY_BLOCK_PTR->next_bb);
           insn != prologue_end && insn;
           insn = PREV_INSN (insn))
        if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
@@ -7458,9 +7986,7 @@ epilogue_done:
               insn = PREV_INSN (insn))
            if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
              {
-               emit_line_note_after (NOTE_SOURCE_FILE (insn),
-                                     NOTE_LINE_NUMBER (insn),
-                                     prologue_end);
+               emit_note_copy_after (insn, prologue_end);
                break;
              }
        }
@@ -7472,7 +7998,7 @@ epilogue_done:
       rtx insn, next;
 
       /* Similarly, move any line notes that appear after the epilogue.
-         There is no need, however, to be quite so anal about the existance
+         There is no need, however, to be quite so anal about the existence
         of such a note.  */
       for (insn = epilogue_end; insn; insn = next)
        {
@@ -7488,211 +8014,109 @@ epilogue_done:
    scheduling and delayed branch scheduling.  */
 
 void
-reposition_prologue_and_epilogue_notes (f)
-     rtx f ATTRIBUTE_UNUSED;
+reposition_prologue_and_epilogue_notes (rtx f ATTRIBUTE_UNUSED)
 {
 #if defined (HAVE_prologue) || defined (HAVE_epilogue)
+  rtx insn, last, note;
   int len;
 
   if ((len = VARRAY_SIZE (prologue)) > 0)
     {
-      rtx insn, note = 0;
+      last = 0, note = 0;
 
       /* Scan from the beginning until we reach the last prologue insn.
         We apparently can't depend on basic_block_{head,end} after
         reorg has run.  */
-      for (insn = f; len && insn; insn = NEXT_INSN (insn))
+      for (insn = f; insn; insn = NEXT_INSN (insn))
        {
          if (GET_CODE (insn) == NOTE)
            {
              if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
                note = insn;
            }
-         else if ((len -= contains (insn, prologue)) == 0)
+         else if (contains (insn, prologue))
            {
-             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)
-               {
-                 for (note = insn; (note = NEXT_INSN (note));)
-                   if (GET_CODE (note) == NOTE
-                       && NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
-                     break;
-               }
-
-             next = NEXT_INSN (note);
-
-             /* Whether or not we can depend on BLOCK_HEAD,
-                attempt to keep it up-to-date.  */
-             if (BLOCK_HEAD (0) == note)
-               BLOCK_HEAD (0) = next;
+             last = insn;
+             if (--len == 0)
+               break;
+           }
+       }
 
-             remove_insn (note);
-             /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note.  */
-             if (GET_CODE (insn) == CODE_LABEL)
-               insn = NEXT_INSN (insn);
-             add_insn_after (note, insn);
+      if (last)
+       {
+         /* Find the prologue-end note if we haven't already, and
+            move it to just after the last prologue insn.  */
+         if (note == 0)
+           {
+             for (note = last; (note = NEXT_INSN (note));)
+               if (GET_CODE (note) == NOTE
+                   && NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
+                 break;
            }
+
+         /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note.  */
+         if (GET_CODE (last) == CODE_LABEL)
+           last = NEXT_INSN (last);
+         reorder_insns (note, note, last);
        }
     }
 
   if ((len = VARRAY_SIZE (epilogue)) > 0)
     {
-      rtx insn, note = 0;
+      last = 0, note = 0;
 
       /* Scan from the end until we reach the first epilogue insn.
         We apparently can't depend on basic_block_{head,end} after
         reorg has run.  */
-      for (insn = get_last_insn (); len && insn; insn = PREV_INSN (insn))
+      for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
        {
          if (GET_CODE (insn) == NOTE)
            {
              if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
                note = insn;
            }
-         else if ((len -= contains (insn, epilogue)) == 0)
+         else if (contains (insn, epilogue))
            {
-             /* Find the epilogue-begin note if we haven't already, and
-                move it to just before the first epilogue insn.  */
-             if (note == 0)
-               {
-                 for (note = insn; (note = PREV_INSN (note));)
-                   if (GET_CODE (note) == NOTE
-                       && NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
-                     break;
-               }
-
-             /* Whether or not we can depend on BLOCK_HEAD,
-                attempt to keep it up-to-date.  */
-             if (n_basic_blocks
-                 && BLOCK_HEAD (n_basic_blocks-1) == insn)
-               BLOCK_HEAD (n_basic_blocks-1) = note;
-
-             remove_insn (note);
-             add_insn_before (note, insn);
+             last = insn;
+             if (--len == 0)
+               break;
            }
        }
-    }
-#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;
+      if (last)
+       {
+         /* Find the epilogue-begin note if we haven't already, and
+            move it to just before the first epilogue insn.  */
+         if (note == 0)
+           {
+             for (note = insn; (note = PREV_INSN (note));)
+               if (GET_CODE (note) == NOTE
+                   && NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
+                 break;
+           }
 
-  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);
+         if (PREV_INSN (last) != note)
+           reorder_insns (note, note, PREV_INSN (last));
+       }
     }
-
-  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);
-  if (mark_lang_status)
-    (*mark_lang_status) (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);
+#endif /* HAVE_prologue or HAVE_epilogue */
 }
 
 /* Called once, at initialization, to initialize function.c.  */
 
 void
-init_function_once ()
+init_function_once (void)
 {
-  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");
 }
+
+/* Returns the name of the current function.  */
+const char *
+current_function_name (void)
+{
+  return (*lang_hooks.decl_printable_name) (cfun->decl, 2);
+}
+
+#include "gt-function.h"