OSDN Git Service

2004-07-01 Jerry Quinn <jlquinn@optonline.net>
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 7ae19d5..008669f 100644 (file)
@@ -1,6 +1,6 @@
 /* Expands front end tree to back end RTL for GCC.
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -63,10 +63,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "integrate.h"
 #include "langhooks.h"
 #include "target.h"
-
-#ifndef TRAMPOLINE_ALIGNMENT
-#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
-#endif
+#include "cfglayout.h"
 
 #ifndef LOCAL_ALIGNMENT
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
@@ -132,9 +129,6 @@ 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;
 
@@ -142,9 +136,6 @@ static GTY(()) int funcdef_no;
    target specific, per-function data structures.  */
 struct machine_function * (*init_machine_status) (void);
 
-/* The FUNCTION_DECL for an inline function currently being expanded.  */
-tree inline_function_decl;
-
 /* The currently compiled function.  */
 struct function *cfun = 0;
 
@@ -178,6 +169,9 @@ struct temp_slot GTY(())
 {
   /* Points to next temporary slot.  */
   struct temp_slot *next;
+  /* Points to previous temporary slot.  */
+  struct temp_slot *prev;
+
   /* The rtx to used to reference the slot.  */
   rtx slot;
   /* The rtx used to represent the address if not the address of the
@@ -236,7 +230,7 @@ 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);
+                               unsigned int, bool, bool, bool, 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);
@@ -248,7 +242,7 @@ 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 walk_fixup_memory_subreg (rtx, 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);
@@ -256,20 +250,14 @@ 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 its not used so that we
+/* We always define `record_insns' even if it's not used so that we
    can always export `prologue_epilogue_contains'.  */
 static void record_insns (rtx, varray_type *) ATTRIBUTE_UNUSED;
 static int contains (rtx, varray_type);
@@ -345,7 +333,7 @@ push_function_context_to (tree context)
   outer_function_chain = p;
   p->fixup_var_refs_queue = 0;
 
-  (*lang_hooks.function.enter_nested) (p);
+  lang_hooks.function.enter_nested (p);
 
   cfun = 0;
 }
@@ -373,7 +361,7 @@ pop_function_context_from (tree context ATTRIBUTE_UNUSED)
 
   restore_emit_status (p);
 
-  (*lang_hooks.function.leave_nested) (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
@@ -425,7 +413,7 @@ free_after_parsing (struct function *f)
   /* f->varasm is used by code generation.  */
   /* f->eh->eh_return_stub_label is used by code generation.  */
 
-  (*lang_hooks.function.final) (f);
+  lang_hooks.function.final (f);
   f->stmt = NULL;
 }
 
@@ -442,35 +430,24 @@ free_after_compilation (struct function *f)
   f->varasm = NULL;
   f->machine = NULL;
 
-  f->x_temp_slots = NULL;
+  f->x_avail_temp_slots = NULL;
+  f->x_used_temp_slots = NULL;
   f->arg_offset_rtx = NULL;
   f->return_rtx = NULL;
   f->internal_arg_pointer = NULL;
-  f->x_nonlocal_labels = NULL;
-  f->x_nonlocal_goto_handler_slots = NULL;
   f->x_nonlocal_goto_handler_labels = NULL;
-  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;
-  f->x_tail_recursion_label = NULL;
   f->x_tail_recursion_reentry = NULL;
   f->x_arg_pointer_save_area = NULL;
-  f->x_clobber_return_insn = NULL;
-  f->x_context_display = NULL;
-  f->x_trampoline_list = NULL;
   f->x_parm_birth_insn = NULL;
-  f->x_last_parm_insn = NULL;
   f->x_parm_reg_stack_loc = NULL;
   f->fixup_var_refs_queue = NULL;
   f->original_arg_vector = NULL;
   f->original_decl_initial = NULL;
-  f->inl_last_parm_insn = NULL;
   f->epilogue_delay_list = NULL;
 }
 \f
@@ -506,6 +483,7 @@ get_frame_size (void)
    ALIGN controls the amount of alignment for the address of the slot:
    0 means according to MODE,
    -1 means use BIGGEST_ALIGNMENT and round size to multiple of that,
+   -2 means use BITS_PER_UNIT,
    positive specifies alignment boundary in bits.
 
    We do not round to stack_boundary here.
@@ -532,7 +510,7 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align,
 
       /* Allow the target to (possibly) increase the alignment of this
         stack slot.  */
-      type = (*lang_hooks.types.type_for_mode) (mode, 0);
+      type = lang_hooks.types.type_for_mode (mode, 0);
       if (type)
        alignment = LOCAL_ALIGNMENT (type, alignment);
 
@@ -543,6 +521,8 @@ assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size, int align,
       alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
       size = CEIL_ROUND (size, alignment);
     }
+  else if (align == -2)
+    alignment = 1; /* BITS_PER_UNIT / BITS_PER_UNIT */
   else
     alignment = align / BITS_PER_UNIT;
 
@@ -623,6 +603,82 @@ assign_stack_local (enum machine_mode mode, HOST_WIDE_INT size, int align)
 {
   return assign_stack_local_1 (mode, size, align, cfun);
 }
+
+\f
+/* Removes temporary slot TEMP from LIST.  */
+
+static void
+cut_slot_from_list (struct temp_slot *temp, struct temp_slot **list)
+{
+  if (temp->next)
+    temp->next->prev = temp->prev;
+  if (temp->prev)
+    temp->prev->next = temp->next;
+  else
+    *list = temp->next;
+
+  temp->prev = temp->next = NULL;
+}
+
+/* Inserts temporary slot TEMP to LIST.  */
+
+static void
+insert_slot_to_list (struct temp_slot *temp, struct temp_slot **list)
+{
+  temp->next = *list;
+  if (*list)
+    (*list)->prev = temp;
+  temp->prev = NULL;
+  *list = temp;
+}
+
+/* Returns the list of used temp slots at LEVEL.  */
+
+static struct temp_slot **
+temp_slots_at_level (int level)
+{
+  level++;
+
+  if (!used_temp_slots)
+    VARRAY_GENERIC_PTR_INIT (used_temp_slots, 3, "used_temp_slots");
+
+  while (level >= (int) VARRAY_ACTIVE_SIZE (used_temp_slots))
+    VARRAY_PUSH_GENERIC_PTR (used_temp_slots, NULL);
+
+  return (struct temp_slot **) &VARRAY_GENERIC_PTR (used_temp_slots, level);
+}
+
+/* Returns the maximal temporary slot level.  */
+
+static int
+max_slot_level (void)
+{
+  if (!used_temp_slots)
+    return -1;
+
+  return VARRAY_ACTIVE_SIZE (used_temp_slots) - 1;
+}
+
+/* Moves temporary slot TEMP to LEVEL.  */
+
+static void
+move_slot_to_level (struct temp_slot *temp, int level)
+{
+  cut_slot_from_list (temp, temp_slots_at_level (temp->level));
+  insert_slot_to_list (temp, temp_slots_at_level (level));
+  temp->level = level;
+}
+
+/* Make temporary slot TEMP available.  */
+
+static void
+make_slot_available (struct temp_slot *temp)
+{
+  cut_slot_from_list (temp, temp_slots_at_level (temp->level));
+  insert_slot_to_list (temp, &avail_temp_slots);
+  temp->in_use = 0;
+  temp->level = -1;
+}
 \f
 /* Allocate a temporary stack slot and record it for possible later
    reuse.
@@ -646,7 +702,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
                            tree type)
 {
   unsigned int align;
-  struct temp_slot *p, *best_p = 0;
+  struct temp_slot *p, *best_p = 0, *selected = NULL, **pp;
   rtx slot;
 
   /* If SIZE is -1 it means that somebody tried to allocate a temporary
@@ -660,7 +716,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
     align = GET_MODE_ALIGNMENT (mode);
 
   if (! type)
-    type = (*lang_hooks.types.type_for_mode) (mode, 0);
+    type = lang_hooks.types.type_for_mode (mode, 0);
 
   if (type)
     align = LOCAL_ALIGNMENT (type, align);
@@ -668,24 +724,30 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
   /* Try to find an available, already-allocated temporary of the proper
      mode which meets the size and alignment requirements.  Choose the
      smallest one with the closest alignment.  */
-  for (p = temp_slots; p; p = p->next)
-    if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
-       && ! p->in_use
-       && objects_must_conflict_p (p->type, type)
-       && (best_p == 0 || best_p->size > p->size
-           || (best_p->size == p->size && best_p->align > p->align)))
-      {
-       if (p->align == align && p->size == size)
-         {
-           best_p = 0;
-           break;
-         }
-       best_p = p;
-      }
+  for (p = avail_temp_slots; p; p = p->next)
+    {
+      if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
+         && objects_must_conflict_p (p->type, type)
+         && (best_p == 0 || best_p->size > p->size
+             || (best_p->size == p->size && best_p->align > p->align)))
+       {
+         if (p->align == align && p->size == size)
+           {
+             selected = p;
+             cut_slot_from_list (selected, &avail_temp_slots);
+             best_p = 0;
+             break;
+           }
+         best_p = p;
+       }
+    }
 
   /* Make our best, if any, the one to use.  */
   if (best_p)
     {
+      selected = best_p;
+      cut_slot_from_list (selected, &avail_temp_slots);
+
       /* If there are enough aligned bytes left over, make them into a new
         temp_slot so that the extra bytes don't get wasted.  Do this only
         for BLKmode slots, so that we can be sure of the alignment.  */
@@ -708,8 +770,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
              p->address = 0;
              p->rtl_expr = 0;
              p->type = best_p->type;
-             p->next = temp_slots;
-             temp_slots = p;
+             insert_slot_to_list (p, &avail_temp_slots);
 
              stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, p->slot,
                                                   stack_slot_list);
@@ -718,12 +779,10 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
              best_p->full_size = rounded_size;
            }
        }
-
-      p = best_p;
     }
 
   /* If we still didn't find one, make a new temporary.  */
-  if (p == 0)
+  if (selected == 0)
     {
       HOST_WIDE_INT frame_offset_old = frame_offset;
 
@@ -768,10 +827,11 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
       p->full_size = frame_offset - frame_offset_old;
 #endif
       p->address = 0;
-      p->next = temp_slots;
-      temp_slots = p;
+
+      selected = p;
     }
 
+  p = selected;
   p->in_use = 1;
   p->addr_taken = 0;
   p->rtl_expr = seq_rtl_expr;
@@ -780,7 +840,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
   if (keep == 2)
     {
       p->level = target_temp_slot_level;
-      p->keep = 0;
+      p->keep = 1;
     }
   else if (keep == 3)
     {
@@ -793,6 +853,8 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size, int keep
       p->keep = keep;
     }
 
+  pp = temp_slots_at_level (p->level);
+  insert_slot_to_list (p, pp);
 
   /* Create a new MEM rtx to avoid clobbering MEM flags of old slots.  */
   slot = gen_rtx_MEM (mode, XEXP (p->slot, 0));
@@ -841,7 +903,7 @@ assign_temp (tree type_or_decl, int keep, int memory_required,
 {
   tree type, decl;
   enum machine_mode mode;
-#ifndef PROMOTE_FOR_CALL_ONLY
+#ifdef PROMOTE_MODE
   int unsignedp;
 #endif
 
@@ -851,8 +913,8 @@ assign_temp (tree type_or_decl, int keep, int memory_required,
     decl = NULL, type = type_or_decl;
 
   mode = TYPE_MODE (type);
-#ifndef PROMOTE_FOR_CALL_ONLY
-  unsignedp = TREE_UNSIGNED (type);
+#ifdef PROMOTE_MODE
+  unsignedp = TYPE_UNSIGNED (type);
 #endif
 
   if (mode == BLKmode || memory_required)
@@ -889,7 +951,7 @@ assign_temp (tree type_or_decl, int keep, int memory_required,
       return tmp;
     }
 
-#ifndef PROMOTE_FOR_CALL_ONLY
+#ifdef PROMOTE_MODE
   if (! dont_promote)
     mode = promote_mode (type, mode, &unsignedp, 0);
 #endif
@@ -906,8 +968,7 @@ assign_temp (tree type_or_decl, int keep, int memory_required,
 void
 combine_temp_slots (void)
 {
-  struct temp_slot *p, *q;
-  struct temp_slot *prev_p, *prev_q;
+  struct temp_slot *p, *q, *next, *next_q;
   int num_slots;
 
   /* We can't combine slots, because the information about which slot
@@ -918,52 +979,50 @@ combine_temp_slots (void)
   /* If there are a lot of temp slots, don't do anything unless
      high levels of optimization.  */
   if (! flag_expensive_optimizations)
-    for (p = temp_slots, num_slots = 0; p; p = p->next, num_slots++)
+    for (p = avail_temp_slots, num_slots = 0; p; p = p->next, num_slots++)
       if (num_slots > 100 || (num_slots > 10 && optimize == 0))
        return;
 
-  for (p = temp_slots, prev_p = 0; p; p = prev_p ? prev_p->next : temp_slots)
+  for (p = avail_temp_slots; p; p = next)
     {
       int delete_p = 0;
 
-      if (! p->in_use && GET_MODE (p->slot) == BLKmode)
-       for (q = p->next, prev_q = p; q; q = prev_q->next)
-         {
-           int delete_q = 0;
-           if (! q->in_use && GET_MODE (q->slot) == BLKmode)
-             {
-               if (p->base_offset + p->full_size == q->base_offset)
-                 {
-                   /* Q comes after P; combine Q into P.  */
-                   p->size += q->size;
-                   p->full_size += q->full_size;
-                   delete_q = 1;
-                 }
-               else if (q->base_offset + q->full_size == p->base_offset)
-                 {
-                   /* P comes after Q; combine P into Q.  */
-                   q->size += p->size;
-                   q->full_size += p->full_size;
-                   delete_p = 1;
-                   break;
-                 }
-             }
-           /* Either delete Q or advance past it.  */
-           if (delete_q)
-             prev_q->next = q->next;
-           else
-             prev_q = q;
-         }
-      /* Either delete P or advance past it.  */
-      if (delete_p)
+      next = p->next;
+
+      if (GET_MODE (p->slot) != BLKmode)
+       continue;
+
+      for (q = p->next; q; q = next_q)
        {
-         if (prev_p)
-           prev_p->next = p->next;
-         else
-           temp_slots = p->next;
+                 int delete_q = 0;
+
+         next_q = q->next;
+
+         if (GET_MODE (q->slot) != BLKmode)
+           continue;
+
+         if (p->base_offset + p->full_size == q->base_offset)
+           {
+             /* Q comes after P; combine Q into P.  */
+             p->size += q->size;
+             p->full_size += q->full_size;
+             delete_q = 1;
+           }
+         else if (q->base_offset + q->full_size == p->base_offset)
+           {
+             /* P comes after Q; combine P into Q.  */
+             q->size += p->size;
+             q->full_size += p->full_size;
+             delete_p = 1;
+             break;
+           }
+         if (delete_q)
+           cut_slot_from_list (q, &avail_temp_slots);
        }
-      else
-       prev_p = p;
+
+      /* Either delete P or advance past it.  */
+      if (delete_p)
+       cut_slot_from_list (p, &avail_temp_slots);
     }
 }
 \f
@@ -974,33 +1033,32 @@ find_temp_slot_from_address (rtx x)
 {
   struct temp_slot *p;
   rtx next;
+  int i;
 
-  for (p = temp_slots; p; p = p->next)
-    {
-      if (! p->in_use)
-       continue;
-
-      else if (XEXP (p->slot, 0) == x
-              || p->address == x
-              || (GET_CODE (x) == PLUS
-                  && XEXP (x, 0) == virtual_stack_vars_rtx
-                  && GET_CODE (XEXP (x, 1)) == CONST_INT
-                  && INTVAL (XEXP (x, 1)) >= p->base_offset
-                  && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size))
-       return p;
-
-      else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST)
-       for (next = p->address; next; next = XEXP (next, 1))
-         if (XEXP (next, 0) == x)
-           return p;
-    }
+  for (i = max_slot_level (); i >= 0; i--)
+    for (p = *temp_slots_at_level (i); p; p = p->next)
+      {
+       if (XEXP (p->slot, 0) == x
+           || p->address == x
+           || (GET_CODE (x) == PLUS
+               && XEXP (x, 0) == virtual_stack_vars_rtx
+               && GET_CODE (XEXP (x, 1)) == CONST_INT
+               && INTVAL (XEXP (x, 1)) >= p->base_offset
+               && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size))
+         return p;
+
+       else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST)
+         for (next = p->address; next; next = XEXP (next, 1))
+           if (XEXP (next, 0) == x)
+             return p;
+      }
 
   /* If we have a sum involving a register, see if it points to a temp
      slot.  */
-  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG
+  if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
       && (p = find_temp_slot_from_address (XEXP (x, 0))) != 0)
     return p;
-  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG
+  else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 1))
           && (p = find_temp_slot_from_address (XEXP (x, 1))) != 0)
     return p;
 
@@ -1030,7 +1088,7 @@ update_temp_slot_address (rtx old, rtx new)
       if (GET_CODE (old) != PLUS)
        return;
 
-      if (GET_CODE (new) == REG)
+      if (REG_P (new))
        {
          update_temp_slot_address (XEXP (old, 0), new);
          update_temp_slot_address (XEXP (old, 1), new);
@@ -1076,7 +1134,7 @@ mark_temp_addr_taken (rtx x)
 
   /* If X is not in memory or is at a constant address, it cannot be in
      a temporary slot.  */
-  if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
+  if (!MEM_P (x) || CONSTANT_P (XEXP (x, 0)))
     return;
 
   p = find_temp_slot_from_address (XEXP (x, 0));
@@ -1096,15 +1154,19 @@ mark_temp_addr_taken (rtx x)
 void
 preserve_temp_slots (rtx x)
 {
-  struct temp_slot *p = 0;
+  struct temp_slot *p = 0, *next;
 
   /* If there is no result, we still might have some objects whose address
      were taken, so we need to make sure they stay around.  */
   if (x == 0)
     {
-      for (p = temp_slots; p; p = p->next)
-       if (p->in_use && p->level == temp_slot_level && p->addr_taken)
-         p->level--;
+      for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+       {
+         next = p->next;
+
+         if (p->addr_taken)
+           move_slot_to_level (p, temp_slot_level - 1);
+       }
 
       return;
     }
@@ -1113,17 +1175,21 @@ preserve_temp_slots (rtx x)
      a temporary slot we know it points to.  To be consistent with
      the code below, we really should preserve all non-kept slots
      if we can't find a match, but that seems to be much too costly.  */
-  if (GET_CODE (x) == REG && REG_POINTER (x))
+  if (REG_P (x) && REG_POINTER (x))
     p = find_temp_slot_from_address (x);
 
   /* If X is not in memory or is at a constant address, it cannot be in
      a temporary slot, but it can contain something whose address was
      taken.  */
-  if (p == 0 && (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))))
+  if (p == 0 && (!MEM_P (x) || CONSTANT_P (XEXP (x, 0))))
     {
-      for (p = temp_slots; p; p = p->next)
-       if (p->in_use && p->level == temp_slot_level && p->addr_taken)
-         p->level--;
+      for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+       {
+         next = p->next;
+
+         if (p->addr_taken)
+           move_slot_to_level (p, temp_slot_level - 1);
+       }
 
       return;
     }
@@ -1140,20 +1206,28 @@ preserve_temp_slots (rtx x)
 
       if (p->level == temp_slot_level)
        {
-         for (q = temp_slots; q; q = q->next)
-           if (q != p && q->addr_taken && q->level == p->level)
-             q->level--;
+         for (q = *temp_slots_at_level (temp_slot_level); q; q = next)
+           {
+             next = q->next;
+
+             if (p != q && q->addr_taken)
+               move_slot_to_level (q, temp_slot_level - 1);
+           }
 
-         p->level--;
+         move_slot_to_level (p, temp_slot_level - 1);
          p->addr_taken = 0;
        }
       return;
     }
 
   /* Otherwise, preserve all non-kept slots at this level.  */
-  for (p = temp_slots; p; p = p->next)
-    if (p->in_use && p->level == temp_slot_level && ! p->keep)
-      p->level--;
+  for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+    {
+      next = p->next;
+
+      if (!p->keep)
+       move_slot_to_level (p, temp_slot_level - 1);
+    }
 }
 
 /* X is the result of an RTL_EXPR.  If it is a temporary slot associated
@@ -1168,7 +1242,7 @@ preserve_rtl_expr_result (rtx x)
 
   /* If X is not in memory or is at a constant address, it cannot be in
      a temporary slot.  */
-  if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))
+  if (x == 0 || !MEM_P (x) || CONSTANT_P (XEXP (x, 0)))
     return;
 
   /* If we can find a match, move it to our level unless it is already at
@@ -1176,7 +1250,7 @@ preserve_rtl_expr_result (rtx x)
   p = find_temp_slot_from_address (XEXP (x, 0));
   if (p != 0)
     {
-      p->level = MIN (p->level, temp_slot_level);
+      move_slot_to_level (p, MIN (p->level, temp_slot_level));
       p->rtl_expr = 0;
     }
 
@@ -1193,12 +1267,15 @@ preserve_rtl_expr_result (rtx x)
 void
 free_temp_slots (void)
 {
-  struct temp_slot *p;
+  struct temp_slot *p, *next;
+
+  for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+    {
+      next = p->next;
 
-  for (p = temp_slots; p; p = p->next)
-    if (p->in_use && p->level == temp_slot_level && ! p->keep
-       && p->rtl_expr == 0)
-      p->in_use = 0;
+      if (!p->keep && p->rtl_expr == 0)
+       make_slot_available (p);
+    }
 
   combine_temp_slots ();
 }
@@ -1208,37 +1285,26 @@ free_temp_slots (void)
 void
 free_temps_for_rtl_expr (tree t)
 {
-  struct temp_slot *p;
-
-  for (p = temp_slots; p; p = p->next)
-    if (p->rtl_expr == t)
-      {
-       /* If this slot is below the current TEMP_SLOT_LEVEL, then it
-          needs to be preserved.  This can happen if a temporary in
-          the RTL_EXPR was addressed; preserve_temp_slots will move
-          the temporary into a higher level.  */
-       if (temp_slot_level <= p->level)
-         p->in_use = 0;
-       else
-         p->rtl_expr = NULL_TREE;
-      }
-
-  combine_temp_slots ();
-}
-
-/* Mark all temporaries ever allocated in this function as not suitable
-   for reuse until the current level is exited.  */
-
-void
-mark_all_temps_used (void)
-{
-  struct temp_slot *p;
+  struct temp_slot *p, *next;
 
-  for (p = temp_slots; p; p = p->next)
+  for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
     {
-      p->in_use = p->keep = 1;
-      p->level = MIN (p->level, temp_slot_level);
+      next = p->next;
+
+      if (p->rtl_expr == t)
+       {
+         /* If this slot is below the current TEMP_SLOT_LEVEL, then it
+            needs to be preserved.  This can happen if a temporary in
+            the RTL_EXPR was addressed; preserve_temp_slots will move
+            the temporary into a higher level.  */
+         if (temp_slot_level <= p->level)
+           make_slot_available (p);
+         else
+           p->rtl_expr = NULL_TREE;
+       }
     }
+
+  combine_temp_slots ();
 }
 
 /* Push deeper into the nesting level for stack temporaries.  */
@@ -1255,11 +1321,15 @@ push_temp_slots (void)
 void
 pop_temp_slots (void)
 {
-  struct temp_slot *p;
+  struct temp_slot *p, *next;
 
-  for (p = temp_slots; p; p = p->next)
-    if (p->in_use && p->level == temp_slot_level && p->rtl_expr == 0)
-      p->in_use = 0;
+  for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
+    {
+      next = p->next;
+
+      if (p->rtl_expr == 0)
+       make_slot_available (p);
+    }
 
   combine_temp_slots ();
 
@@ -1272,7 +1342,8 @@ void
 init_temp_slots (void)
 {
   /* We have not allocated any temporaries yet.  */
-  temp_slots = 0;
+  avail_temp_slots = 0;
+  used_temp_slots = 0;
   temp_slot_level = 0;
   var_temp_slot_level = 0;
   target_temp_slot_level = 0;
@@ -1287,21 +1358,21 @@ init_temp_slots (void)
 void
 put_var_into_stack (tree decl, int rescan)
 {
-  rtx reg;
+  rtx orig_reg, reg;
   enum machine_mode promoted_mode, decl_mode;
   struct function *function = 0;
   tree context;
-  int can_use_addressof;
-  int volatilep = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl);
-  int usedp = (TREE_USED (decl)
+  bool can_use_addressof_p;
+  bool volatile_p = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl);
+  bool used_p = (TREE_USED (decl)
               || (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0));
 
   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)
-        : DECL_RTL_IF_SET (decl));
orig_reg = 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
      since in that case caller is setting TREE_ADDRESSABLE
@@ -1320,7 +1391,7 @@ put_var_into_stack (tree decl, int rescan)
      because it might not be in any active function.
      FIXME: Is that really supposed to happen?
      It does in ObjC at least.  */
-  if (context != current_function_decl && context != inline_function_decl)
+  if (context != current_function_decl)
     for (function = outer_function_chain; function; function = function->outer)
       if (function->decl == context)
        break;
@@ -1329,18 +1400,18 @@ put_var_into_stack (tree decl, int rescan)
      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
+      && MEM_P (reg)
+      && REG_P (XEXP (reg, 0))
       && REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)
     {
-      reg = XEXP (reg, 0);
+      orig_reg = reg = XEXP (reg, 0);
       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
+  can_use_addressof_p
     = (function == 0
        && ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl))
        && optimize > 0
@@ -1353,19 +1424,26 @@ put_var_into_stack (tree decl, int rescan)
 
   /* If we can't use ADDRESSOF, make sure we see through one we already
      generated.  */
-  if (! can_use_addressof && GET_CODE (reg) == MEM
+  if (! can_use_addressof_p
+      && MEM_P (reg)
       && GET_CODE (XEXP (reg, 0)) == ADDRESSOF)
     reg = XEXP (XEXP (reg, 0), 0);
 
   /* Now we should have a value that resides in one or more pseudo regs.  */
 
-  if (GET_CODE (reg) == REG)
+  if (REG_P (reg))
     {
-      if (can_use_addressof)
+      if (can_use_addressof_p)
        gen_mem_addressof (reg, decl, rescan);
       else
-       put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
-                           decl_mode, volatilep, 0, usedp, 0);
+       put_reg_into_stack (function, reg, TREE_TYPE (decl), decl_mode,
+                           0, volatile_p, used_p, false, 0);
+
+         /* If this was previously a MEM but we've removed the ADDRESSOF,
+            set this address into that MEM so we always use the same
+            rtx for this variable.  */
+         if (orig_reg != reg && MEM_P (orig_reg))
+           XEXP (orig_reg, 0) = XEXP (reg, 0);
     }
   else if (GET_CODE (reg) == CONCAT)
     {
@@ -1375,20 +1453,20 @@ put_var_into_stack (tree decl, int rescan)
         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 = (*lang_hooks.types.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
       /* Since part 0 should have a lower address, do it second.  */
       put_reg_into_stack (function, hipart, part_type, part_mode,
-                         part_mode, volatilep, 0, 0, 0);
+                         0, volatile_p, false, false, 0);
       put_reg_into_stack (function, lopart, part_type, part_mode,
-                         part_mode, volatilep, 0, 0, 0);
+                         0, volatile_p, false, true, 0);
 #else
       put_reg_into_stack (function, lopart, part_type, part_mode,
-                         part_mode, volatilep, 0, 0, 0);
+                         0, volatile_p, false, false, 0);
       put_reg_into_stack (function, hipart, part_type, part_mode,
-                         part_mode, volatilep, 0, 0, 0);
+                         0, volatile_p, false, true, 0);
 #endif
 
       /* Change the CONCAT into a combined MEM for both parts.  */
@@ -1409,7 +1487,7 @@ put_var_into_stack (tree decl, int rescan)
       /* Prevent sharing of rtl that might lose.  */
       if (GET_CODE (XEXP (reg, 0)) == PLUS)
        XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
-      if (usedp && rescan)
+      if (used_p && rescan)
        {
          schedule_fixup_var_refs (function, reg, TREE_TYPE (decl),
                                   promoted_mode, 0);
@@ -1423,28 +1501,38 @@ put_var_into_stack (tree decl, int rescan)
 
 /* Subroutine of put_var_into_stack.  This puts a single pseudo reg REG
    into the stack frame of FUNCTION (0 means the current function).
+   TYPE is the user-level data type of the value hold in the register.
    DECL_MODE is the machine mode of the user-level data type.
-   PROMOTED_MODE is the machine mode of the register.
-   VOLATILE_P is nonzero if this is for a "volatile" decl.
-   USED_P is nonzero if this reg might have already been used in an insn.  */
+   ORIGINAL_REGNO must be set if the real regno is not visible in REG.
+   VOLATILE_P is true if this is for a "volatile" decl.
+   USED_P is true if this reg might have already been used in an insn.
+   CONSECUTIVE_P is true if the stack slot assigned to reg must be
+   consecutive with the previous stack slot.  */
 
 static void
 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)
+                   enum machine_mode decl_mode, unsigned int original_regno,
+                   bool volatile_p, bool used_p, bool consecutive_p,
+                   htab_t ht)
 {
   struct function *func = function ? function : cfun;
-  rtx new = 0;
+  enum machine_mode mode = GET_MODE (reg);
   unsigned int regno = original_regno;
+  rtx new = 0;
 
   if (regno == 0)
     regno = REGNO (reg);
 
   if (regno < func->x_max_parm_reg)
-    new = func->x_parm_reg_stack_loc[regno];
+    {
+      if (!func->x_parm_reg_stack_loc)
+       abort ();
+      new = func->x_parm_reg_stack_loc[regno];
+    }
 
   if (new == 0)
-    new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func);
+    new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode),
+                               consecutive_p ? -2 : 0, func);
 
   PUT_CODE (reg, MEM);
   PUT_MODE (reg, decl_mode);
@@ -1466,7 +1554,7 @@ put_reg_into_stack (struct function *function, rtx reg, tree type,
     }
 
   if (used_p)
-    schedule_fixup_var_refs (function, reg, type, promoted_mode, ht);
+    schedule_fixup_var_refs (function, reg, type, mode, ht);
 }
 
 /* Make sure that all refs to the variable, previously made
@@ -1477,7 +1565,7 @@ static void
 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;
+  int unsigned_p = type ? TYPE_UNSIGNED (type) : 0;
 
   if (function != 0)
     {
@@ -1503,6 +1591,7 @@ fixup_var_refs (rtx var, enum machine_mode promoted_mode, int unsignedp,
   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)
@@ -1514,6 +1603,9 @@ fixup_var_refs (rtx var, enum machine_mode promoted_mode, int unsignedp,
       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, may_share);
 
@@ -1523,8 +1615,8 @@ fixup_var_refs (rtx var, enum machine_mode promoted_mode, int unsignedp,
       push_to_full_sequence (stack->first, stack->last);
       fixup_var_refs_insns (stack->first, var, promoted_mode, unsignedp,
                            stack->next != 0, may_share);
-      /* Update remembered end of sequence
-        in case we added an insn at the end.  */
+      /* Update bounds of sequence in case we added insns.  */
+      stack->first = get_insns ();
       stack->last = get_last_insn ();
       end_sequence ();
     }
@@ -1541,6 +1633,8 @@ fixup_var_refs (rtx var, enum machine_mode promoted_mode, int unsignedp,
          end_sequence ();
        }
     }
+
+  volatile_ok = save_volatile_ok;
 }
 \f
 /* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
@@ -1583,32 +1677,7 @@ fixup_var_refs_insns (rtx insn, rtx var, enum machine_mode promoted_mode,
          pointer now.  */
       rtx next = NEXT_INSN (insn);
 
-      /* CALL_PLACEHOLDERs are special; we have to switch into each of
-        the three sequences they (potentially) contain, and process
-        them recursively.  The CALL_INSN itself is not interesting.  */
-
-      if (GET_CODE (insn) == CALL_INSN
-         && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
-       {
-         int i;
-
-         /* Look at the Normal call, sibling call and tail recursion
-            sequences attached to the CALL_PLACEHOLDER.  */
-         for (i = 0; i < 3; i++)
-           {
-             rtx seq = XEXP (PATTERN (insn), i);
-             if (seq)
-               {
-                 push_to_sequence (seq);
-                 fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0,
-                                       may_share);
-                 XEXP (PATTERN (insn), i) = get_insns ();
-                 end_sequence ();
-               }
-           }
-       }
-
-      else if (INSN_P (insn))
+      if (INSN_P (insn))
        fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel,
                             may_share);
 
@@ -1617,11 +1686,7 @@ fixup_var_refs_insns (rtx insn, rtx var, enum machine_mode promoted_mode,
 }
 
 /* Look up the insns which reference VAR in HT and fix them up.  Other
-   arguments are the same as fixup_var_refs_insns.
-
-   N.B. No need for special processing of CALL_PLACEHOLDERs here,
-   because the hash table will point straight to the interesting insn
-   (inside the CALL_PLACEHOLDER).  */
+   arguments are the same as fixup_var_refs_insns.  */
 
 static void
 fixup_var_refs_insns_with_hash (htab_t ht, rtx var, enum machine_mode promoted_mode,
@@ -1690,7 +1755,7 @@ fixup_var_refs_insn (rtx insn, rtx var, enum machine_mode promoted_mode,
              don't delete the insn.  */
           && find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0
           && (rtx_equal_p (SET_SRC (set), var)
-              || (GET_CODE (SET_SRC (set)) == REG
+              || (REG_P (SET_SRC (set))
                   && (prev = prev_nonnote_insn (insn)) != 0
                   && (prev_set = single_set (prev)) != 0
                   && SET_DEST (prev_set) == SET_SRC (set)
@@ -1701,7 +1766,6 @@ fixup_var_refs_insn (rtx insn, rtx var, enum machine_mode promoted_mode,
   else
     {
       struct fixup_replacement *replacements = 0;
-      rtx next_insn = NEXT_INSN (insn);
 
       if (SMALL_REGISTER_CLASSES)
        {
@@ -1755,17 +1819,11 @@ fixup_var_refs_insn (rtx insn, rtx var, enum machine_mode promoted_mode,
       fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,
                        &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
-        the last such instruction emitted.  */
-      if (insn == last_parm_insn)
-       last_parm_insn = PREV_INSN (next_insn);
-
       while (replacements)
        {
          struct fixup_replacement *next;
 
-         if (GET_CODE (replacements->new) == REG)
+         if (REG_P (replacements->new))
            {
              rtx insert_before;
              rtx seq;
@@ -1814,7 +1872,7 @@ fixup_var_refs_insn (rtx insn, rtx var, enum machine_mode promoted_mode,
     {
       if (GET_CODE (note) != INSN_LIST)
        XEXP (note, 0)
-         = walk_fixup_memory_subreg (XEXP (note, 0), insn,
+         = walk_fixup_memory_subreg (XEXP (note, 0), insn, var,
                                      promoted_mode, 1);
       note = XEXP (note, 1);
     }
@@ -2099,7 +2157,7 @@ fixup_var_refs_1 (rtx var, enum machine_mode promoted_mode, rtx *loc, rtx insn,
                 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)
+             if (MEM_P (replacement->new))
                {
                  INSN_CODE (insn) = -1;
                  if (recog_memoized (insn) >= 0)
@@ -2280,9 +2338,9 @@ fixup_var_refs_1 (rtx var, enum machine_mode promoted_mode, rtx *loc, rtx insn,
        if ((SET_SRC (x) == var
             || (GET_CODE (SET_SRC (x)) == SUBREG
                 && SUBREG_REG (SET_SRC (x)) == var))
-           && (GET_CODE (SET_DEST (x)) == REG
+           && (REG_P (SET_DEST (x))
                || (GET_CODE (SET_DEST (x)) == SUBREG
-                   && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG))
+                   && REG_P (SUBREG_REG (SET_DEST (x)))))
            && GET_MODE (var) == promoted_mode
            && x == single_set (insn))
          {
@@ -2351,9 +2409,9 @@ fixup_var_refs_1 (rtx var, enum machine_mode promoted_mode, rtx *loc, rtx insn,
        if ((SET_DEST (x) == var
             || (GET_CODE (SET_DEST (x)) == SUBREG
                 && SUBREG_REG (SET_DEST (x)) == var))
-           && (GET_CODE (SET_SRC (x)) == REG
+           && (REG_P (SET_SRC (x))
                || (GET_CODE (SET_SRC (x)) == SUBREG
-                   && GET_CODE (SUBREG_REG (SET_SRC (x))) == REG))
+                   && REG_P (SUBREG_REG (SET_SRC (x)))))
            && GET_MODE (var) == promoted_mode
            && x == single_set (insn))
          {
@@ -2501,17 +2559,17 @@ fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode, int uncri
   return result;
 }
 
-/* Do fixup_memory_subreg on all (SUBREG (MEM ...) ...) contained in X.
+/* Do fixup_memory_subreg on all (SUBREG (VAR) ...) contained in X.
+   VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE.
    Replace subexpressions of X in place.
-   If X itself is a (SUBREG (MEM ...) ...), return the replacement expression.
+   If X itself is a (SUBREG (VAR) ...), return the replacement expression.
    Otherwise return X, with its contents possibly altered.
 
-   INSN, PROMOTED_MODE and UNCRITICAL are as for
-   fixup_memory_subreg.  */
+   INSN and UNCRITICAL are as for fixup_memory_subreg.  */
 
 static rtx
-walk_fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode,
-                         int uncritical)
+walk_fixup_memory_subreg (rtx x, rtx insn, rtx var,
+                         enum machine_mode promoted_mode, int uncritical)
 {
   enum rtx_code code;
   const char *fmt;
@@ -2522,7 +2580,7 @@ walk_fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode,
 
   code = GET_CODE (x);
 
-  if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
+  if (code == SUBREG && SUBREG_REG (x) == var)
     return fixup_memory_subreg (x, insn, promoted_mode, uncritical);
 
   /* Nothing special about this RTX; fix its operands.  */
@@ -2531,14 +2589,14 @@ walk_fixup_memory_subreg (rtx x, rtx insn, enum machine_mode promoted_mode,
   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,
+       XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, var,
                                                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,
+             = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, var,
                                          promoted_mode, uncritical);
        }
     }
@@ -2564,7 +2622,7 @@ fixup_stack_1 (rtx x, rtx insn)
       /* If we have address of a stack slot but it's not valid
         (displacement is too large), compute the sum in a register.  */
       if (GET_CODE (ad) == PLUS
-         && GET_CODE (XEXP (ad, 0)) == REG
+         && REG_P (XEXP (ad, 0))
          && ((REGNO (XEXP (ad, 0)) >= FIRST_VIRTUAL_REGISTER
               && REGNO (XEXP (ad, 0)) <= LAST_VIRTUAL_REGISTER)
              || REGNO (XEXP (ad, 0)) == FRAME_POINTER_REGNUM
@@ -2644,17 +2702,17 @@ optimize_bit_field (rtx body, rtx insn, rtx *equiv_mem)
       /* Now check that the containing word is memory, not a register,
         and that it is safe to change the machine mode.  */
 
-      if (GET_CODE (XEXP (bitfield, 0)) == MEM)
+      if (MEM_P (XEXP (bitfield, 0)))
        memref = XEXP (bitfield, 0);
-      else if (GET_CODE (XEXP (bitfield, 0)) == REG
+      else if (REG_P (XEXP (bitfield, 0))
               && equiv_mem != 0)
        memref = equiv_mem[REGNO (XEXP (bitfield, 0))];
       else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG
-              && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == MEM)
+              && MEM_P (SUBREG_REG (XEXP (bitfield, 0))))
        memref = SUBREG_REG (XEXP (bitfield, 0));
       else if (GET_CODE (XEXP (bitfield, 0)) == SUBREG
               && equiv_mem != 0
-              && GET_CODE (SUBREG_REG (XEXP (bitfield, 0))) == REG)
+              && REG_P (SUBREG_REG (XEXP (bitfield, 0))))
        memref = equiv_mem[REGNO (SUBREG_REG (XEXP (bitfield, 0)))];
 
       if (memref
@@ -2839,6 +2897,7 @@ gen_mem_addressof (rtx reg, tree decl, int rescan)
   RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
 
   PUT_CODE (reg, MEM);
+  MEM_VOLATILE_P (reg) = 0;
   MEM_ATTRS (reg) = 0;
   XEXP (reg, 0) = r;
 
@@ -2865,17 +2924,15 @@ gen_mem_addressof (rtx reg, tree decl, int rescan)
 
       if (rescan
          && (TREE_USED (decl) || (DECL_P (decl) && DECL_INITIAL (decl) != 0)))
-       fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), reg, 0);
+       fixup_var_refs (reg, GET_MODE (reg), TYPE_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);
     }
@@ -2890,9 +2947,9 @@ flush_addressof (tree decl)
 {
   if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
       && DECL_RTL (decl) != 0
-      && GET_CODE (DECL_RTL (decl)) == MEM
+      && MEM_P (DECL_RTL (decl))
       && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF
-      && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG)
+      && REG_P (XEXP (XEXP (DECL_RTL (decl), 0), 0)))
     put_addressof_into_stack (XEXP (DECL_RTL (decl), 0), 0);
 }
 
@@ -2902,11 +2959,11 @@ static void
 put_addressof_into_stack (rtx r, htab_t ht)
 {
   tree decl, type;
-  int volatile_p, used_p;
+  bool volatile_p, used_p;
 
   rtx reg = XEXP (r, 0);
 
-  if (GET_CODE (reg) != REG)
+  if (!REG_P (reg))
     abort ();
 
   decl = ADDRESSOF_DECL (r);
@@ -2921,12 +2978,12 @@ put_addressof_into_stack (rtx r, htab_t ht)
   else
     {
       type = NULL_TREE;
-      volatile_p = 0;
-      used_p = 1;
+      volatile_p = false;
+      used_p = true;
     }
 
-  put_reg_into_stack (0, reg, type, GET_MODE (reg), GET_MODE (reg),
-                     volatile_p, ADDRESSOF_REGNO (r), used_p, ht);
+  put_reg_into_stack (0, reg, type, GET_MODE (reg), ADDRESSOF_REGNO (r),
+                     volatile_p, used_p, false, ht);
 }
 
 /* List of replacements made below in purge_addressof_1 when creating
@@ -2986,7 +3043,7 @@ purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
     {
       rtx sub, insns;
 
-      if (GET_CODE (XEXP (x, 0)) != MEM)
+      if (!MEM_P (XEXP (x, 0)))
        put_addressof_into_stack (x, ht);
 
       /* We must create a copy of the rtx because it was created by
@@ -3001,7 +3058,7 @@ purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
       /* 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)
+      if (REG_P (sub) && REGNO (sub) <= LAST_VIRTUAL_REGISTER)
        sub = copy_to_reg (sub);
       else
        sub = force_operand (sub, NULL_RTX);
@@ -3020,12 +3077,12 @@ purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
     {
       rtx sub = XEXP (XEXP (x, 0), 0);
 
-      if (GET_CODE (sub) == MEM)
+      if (MEM_P (sub))
        sub = adjust_address_nv (sub, GET_MODE (x), 0);
-      else if (GET_CODE (sub) == REG
+      else if (REG_P (sub)
               && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
        ;
-      else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
+      else if (REG_P (sub) && GET_MODE (x) != GET_MODE (sub))
        {
          int size_x, size_sub;
 
@@ -3063,7 +3120,7 @@ purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
                    rtx z = XEXP (XEXP (tem, 1), 0);
 
                    if (GET_MODE (x) == GET_MODE (z)
-                       || (GET_CODE (XEXP (XEXP (tem, 1), 0)) != REG
+                       || (!REG_P (XEXP (XEXP (tem, 1), 0))
                            && GET_CODE (XEXP (XEXP (tem, 1), 0)) != SUBREG))
                      abort ();
 
@@ -3228,7 +3285,7 @@ purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
        {
          /* Remember the replacement so that the same one can be done
             on the REG_NOTES.  */
-         if (GET_CODE (sub) == REG || GET_CODE (sub) == SUBREG)
+         if (REG_P (sub) || GET_CODE (sub) == SUBREG)
            {
              rtx tem;
 
@@ -3241,9 +3298,9 @@ purge_addressof_1 (rtx *loc, rtx insn, int force, int store, int may_postpone,
                    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;
@@ -3315,7 +3372,7 @@ insns_for_mem_walk (rtx *r, void *data)
   tmp.insns = NULL_RTX;
 
   if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
-      && GET_CODE (XEXP (*r, 0)) == REG)
+      && REG_P (XEXP (*r, 0)))
     {
       void **e;
       tmp.key = XEXP (*r, 0);
@@ -3326,7 +3383,7 @@ insns_for_mem_walk (rtx *r, void *data)
          memcpy (*e, &tmp, sizeof (tmp));
        }
     }
-  else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
+  else if (ifmwi->pass == 1 && *r && REG_P (*r))
     {
       struct insns_for_mem_entry *ifme;
       tmp.key = *r;
@@ -3464,7 +3521,7 @@ purge_single_hard_subreg_set (rtx pattern)
   enum machine_mode mode = GET_MODE (SET_DEST (pattern));
   int offset = 0;
 
-  if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG
+  if (GET_CODE (reg) == SUBREG && REG_P (SUBREG_REG (reg))
       && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
     {
       offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
@@ -3475,7 +3532,7 @@ purge_single_hard_subreg_set (rtx pattern)
     }
 
 
-  if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER)
+  if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)
     {
       reg = gen_rtx_REG (mode, REGNO (reg) + offset);
       SET_DEST (pattern) = reg;
@@ -3526,30 +3583,30 @@ purge_hard_subreg_sets (rtx insn)
    references to hard register references.  */
 
 void
-instantiate_virtual_regs (tree fndecl, rtx insns)
+instantiate_virtual_regs (void)
 {
   rtx insn;
   unsigned int i;
 
   /* Compute the offsets to use for this function.  */
-  in_arg_offset = FIRST_PARM_OFFSET (fndecl);
+  in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
   var_offset = STARTING_FRAME_OFFSET;
-  dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
+  dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
   out_arg_offset = STACK_POINTER_OFFSET;
-  cfa_offset = ARG_POINTER_CFA_OFFSET (fndecl);
+  cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
 
   /* Scan all variables and parameters of this function.  For each that is
      in memory, instantiate all virtual registers if the result is a valid
      address.  If not, we do it later.  That will handle most uses of virtual
      regs on many machines.  */
-  instantiate_decls (fndecl, 1);
+  instantiate_decls (current_function_decl, 1);
 
   /* Initialize recognition, indicating that volatile is OK.  */
   init_recog ();
 
   /* Scan through all the insns, instantiating every virtual register still
      present.  */
-  for (insn = insns; insn; insn = NEXT_INSN (insn))
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
        || GET_CODE (insn) == CALL_INSN)
       {
@@ -3577,7 +3634,7 @@ instantiate_virtual_regs (tree fndecl, rtx insns)
 
   /* Now instantiate the remaining register equivalences for debugging info.
      These will not be valid addresses.  */
-  instantiate_decls (fndecl, 0);
+  instantiate_decls (current_function_decl, 0);
 
   /* Indicate that, from now on, assign_stack_local should use
      frame_pointer_rtx.  */
@@ -3649,13 +3706,13 @@ instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only)
   /* If this is not a MEM, no need to do anything.  Similarly if the
      address is a constant or a register that is not a virtual register.  */
 
-  if (x == 0 || GET_CODE (x) != MEM)
+  if (x == 0 || !MEM_P (x))
     return;
 
   addr = XEXP (x, 0);
   if (CONSTANT_P (addr)
-      || (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == REG)
-      || (GET_CODE (addr) == REG
+      || (GET_CODE (addr) == ADDRESSOF && REG_P (XEXP (addr, 0)))
+      || (REG_P (addr)
          && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
              || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
     return;
@@ -3813,14 +3870,14 @@ instantiate_virtual_regs_1 (rtx *loc, rtx object, int 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)
+         if (!REG_P (src) && GET_CODE (src) != PLUS)
            {
              instantiate_virtual_regs_lossage (object);
              return 1;
            }
 
          start_sequence ();
-         if (GET_CODE (src) != REG)
+         if (!REG_P (src))
            temp = force_operand (src, NULL_RTX);
          else
            temp = src;
@@ -3886,7 +3943,7 @@ instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
              /* We know the second operand is a constant.  Unless the
                 first operand is a REG (which has been already checked),
                 it needs to be checked.  */
-             if (GET_CODE (XEXP (x, 0)) != REG)
+             if (!REG_P (XEXP (x, 0)))
                {
                  loc = &XEXP (x, 0);
                  goto restart;
@@ -4072,10 +4129,10 @@ instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
         go ahead and make the invalid one, but do it to a copy.  For a REG,
         just make the recursive call, since there's no chance of a problem.  */
 
-      if ((GET_CODE (XEXP (x, 0)) == MEM
+      if ((MEM_P (XEXP (x, 0))
           && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
                                          0))
-         || (GET_CODE (XEXP (x, 0)) == REG
+         || (REG_P (XEXP (x, 0))
              && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
        return 1;
 
@@ -4109,10 +4166,10 @@ instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
       return 1;
 
     case ADDRESSOF:
-      if (GET_CODE (XEXP (x, 0)) == REG)
+      if (REG_P (XEXP (x, 0)))
        return 1;
 
-      else if (GET_CODE (XEXP (x, 0)) == MEM)
+      else if (MEM_P (XEXP (x, 0)))
        {
          /* If we have a (addressof (mem ..)), do any instantiation inside
             since we know we'll be making the inside valid when we finally
@@ -4143,69 +4200,6 @@ instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
   return 1;
 }
 \f
-/* Optimization: assuming this function does not receive nonlocal gotos,
-   delete the handlers for such, as well as the insns to establish
-   and disestablish them.  */
-
-static void
-delete_handlers (void)
-{
-  rtx insn;
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    {
-      /* Delete the handler by turning off the flag that would
-        prevent jump_optimize from deleting it.
-        Also permit deletion of the nonlocal labels themselves
-        if nothing local refers to them.  */
-      if (GET_CODE (insn) == CODE_LABEL)
-       {
-         tree t, last_t;
-
-         LABEL_PRESERVE_P (insn) = 0;
-
-         /* Remove it from the nonlocal_label list, to avoid confusing
-            flow.  */
-         for (t = nonlocal_labels, last_t = 0; t;
-              last_t = t, t = TREE_CHAIN (t))
-           if (DECL_RTL (TREE_VALUE (t)) == insn)
-             break;
-         if (t)
-           {
-             if (! last_t)
-               nonlocal_labels = TREE_CHAIN (nonlocal_labels);
-             else
-               TREE_CHAIN (last_t) = TREE_CHAIN (t);
-           }
-       }
-      if (GET_CODE (insn) == INSN)
-       {
-         int can_delete = 0;
-         rtx t;
-         for (t = nonlocal_goto_handler_slots; t != 0; t = XEXP (t, 1))
-           if (reg_mentioned_p (t, PATTERN (insn)))
-             {
-               can_delete = 1;
-               break;
-             }
-         if (can_delete
-             || (nonlocal_goto_stack_level != 0
-                 && reg_mentioned_p (nonlocal_goto_stack_level,
-                                     PATTERN (insn))))
-           delete_related_insns (insn);
-       }
-    }
-}
-\f
-/* Return the first insn following those generated by `assign_parms'.  */
-
-rtx
-get_first_nonparm_insn (void)
-{
-  if (last_parm_insn)
-    return NEXT_INSN (last_parm_insn);
-  return get_insns ();
-}
-
 /* 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.
@@ -4256,11 +4250,11 @@ aggregate_value_p (tree exp, tree fntype)
 
   /* If we have something other than a REG (e.g. a PARALLEL), then assume
      it is OK.  */
-  if (GET_CODE (reg) != REG)
+  if (!REG_P (reg))
     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;
@@ -4279,6 +4273,7 @@ assign_parms (tree fndecl)
   /* 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), orig_fnargs;
   /* This is used for the arg pointer when referring to stack args.  */
@@ -4293,12 +4288,7 @@ assign_parms (tree fndecl)
   /* Nonzero if function takes extra anonymous args.
      This means the last named arg must be on the stack
      right before the anonymous ones.  */
-  int stdarg
-    = (TYPE_ARG_TYPES (fntype) != 0
-       && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-          != void_type_node));
-
-  current_function_stdarg = stdarg;
+  int stdarg = current_function_stdarg;
 
   /* If the reg that the virtual arg pointer will be translated into is
      not a fixed reg or is the stack pointer, make a copy of the virtual
@@ -4337,21 +4327,18 @@ assign_parms (tree fndecl)
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
   parm_reg_stack_loc = ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
 
-  if (SPLIT_COMPLEX_ARGS)
+  /* If the target wants to split complex arguments into scalars, do so.  */
+  if (targetm.calls.split_complex_arg)
     fnargs = split_complex_args (fnargs);
 
 #ifdef REG_PARM_STACK_SPACE
-#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
-#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, fndecl);
+  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
@@ -4374,6 +4361,7 @@ assign_parms (tree fndecl)
       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 last
         anonymous args.  */
@@ -4391,7 +4379,8 @@ assign_parms (tree fndecl)
       /* Set NAMED_ARG if this arg should be treated as a named arg.  For
         most machines, if this is a varargs/stdarg function, then we treat
         the last named arg as if it were anonymous too.  */
-      named_arg = targetm.calls.strict_argument_naming (&args_so_far) ? 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
@@ -4459,8 +4448,9 @@ assign_parms (tree fndecl)
       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);
+         unsignedp = TYPE_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.
@@ -4546,12 +4536,9 @@ assign_parms (tree fndecl)
          partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
                                                passed_type, named_arg);
          if (partial
-#ifndef MAYBE_REG_PARM_STACK_SPACE
              /* The caller might already have allocated stack space
                 for the register parameters.  */
-             && reg_parm_stack_space == 0
-#endif
-             )
+             && 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
@@ -4568,15 +4555,19 @@ assign_parms (tree fndecl)
                 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);
 
-             /* If PRETEND_BYTES != CURRENT_FUNCTION_PRETEND_ARGS_SIZE,
-                insert the padding before the start of the first pretend
-                argument.  */
-             stack_args_size.constant
-               = (current_function_pretend_args_size - pretend_bytes);
+             /* 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
@@ -4585,9 +4576,13 @@ assign_parms (tree fndecl)
       locate_and_pad_parm (promoted_mode, passed_type, in_regs,
                           entry_parm ? partial : 0, fndecl,
                           &stack_args_size, &locate);
+      /* Adjust offsets to include the pretend args.  */
+      locate.slot_offset.constant += extra_pretend_bytes - pretend_bytes;
+      locate.offset.constant += extra_pretend_bytes - pretend_bytes;
 
       {
        rtx offset_rtx;
+       unsigned int align, boundary;
 
        /* If we're passing this arg using a reg, make its stack home
           the aligned stack slot.  */
@@ -4605,10 +4600,24 @@ assign_parms (tree fndecl)
                                                  offset_rtx));
 
        set_mem_attributes (stack_parm, parm, 1);
-       if (entry_parm && MEM_ATTRS (stack_parm)->align < PARM_BOUNDARY)
-         set_mem_align (stack_parm, PARM_BOUNDARY);
 
-       /* Set also REG_ATTRS if parameter was passed in a register.  */
+       boundary = FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type);
+       align = 0;
+
+       /* If we're padding upward, we know that the alignment of the slot
+          is FUNCTION_ARG_BOUNDARY.  If we're using slot_offset, we're
+          intentionally forcing upward padding.  Otherwise we have to come
+          up with a guess at the alignment based on OFFSET_RTX.  */
+       if (locate.where_pad == upward || entry_parm)
+         align = boundary;
+       else if (GET_CODE (offset_rtx) == CONST_INT)
+         {
+           align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary;
+           align = align & -align;
+         }
+       if (align > 0)
+         set_mem_align (stack_parm, align);
+
        if (entry_parm)
          set_reg_attrs_for_parm (entry_parm, stack_parm);
       }
@@ -4643,7 +4652,7 @@ assign_parms (tree 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
@@ -4652,21 +4661,15 @@ assign_parms (tree fndecl)
       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)
+#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 += pretend_bytes + locate.size.constant;
+         stack_args_size.constant += locate.size.constant;
          if (locate.size.var)
            ADD_PARM_SIZE (stack_args_size, locate.size.var);
        }
@@ -4682,13 +4685,9 @@ assign_parms (tree fndecl)
       /* If we can't trust the parm stack slot to be aligned enough
         for its ultimate type, don't use that slot after entry.
         We'll make another stack slot, if we need one.  */
-      {
-       unsigned int thisparm_boundary
-         = FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type);
-
-       if (GET_MODE_ALIGNMENT (nominal_mode) > thisparm_boundary)
-         stack_parm = 0;
-      }
+      if (STRICT_ALIGNMENT && stack_parm
+         && GET_MODE_ALIGNMENT (nominal_mode) > MEM_ALIGN (stack_parm))
+       stack_parm = 0;
 
       /* If parm was passed in memory, and we need to convert it on entry,
         don't store it back in that same slot.  */
@@ -4706,13 +4705,13 @@ assign_parms (tree fndecl)
 
          for (i = 0; i < len; i++)
            if (XEXP (XVECEXP (entry_parm, 0, i), 0) != NULL_RTX
-               && GET_CODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) == REG
+               && REG_P (XEXP (XVECEXP (entry_parm, 0, i), 0))
                && (GET_MODE (XEXP (XVECEXP (entry_parm, 0, i), 0))
                    == passed_mode)
                && 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;
              }
        }
@@ -4740,9 +4739,29 @@ assign_parms (tree fndecl)
 
          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;
+               }
            }
        }
 
@@ -4756,8 +4775,9 @@ assign_parms (tree fndecl)
          /* 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)
+         if (REG_P (entry_parm)
+             || (GET_CODE (entry_parm) == PARALLEL
+                && (!loaded_in_reg || !optimize)))
            {
              int size = int_size_in_bytes (TREE_TYPE (parm));
              int size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
@@ -4778,10 +4798,9 @@ assign_parms (tree fndecl)
                  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 (GET_CODE (entry_parm) == PARALLEL)
                ;
-             else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
+             else if (size != 0 && PARM_BOUNDARY % BITS_PER_WORD != 0)
                abort ();
 
              mem = validize_mem (stack_parm);
@@ -4844,7 +4863,7 @@ assign_parms (tree fndecl)
                                     size_stored / UNITS_PER_WORD);
            }
          /* If parm is already bound to register pair, don't change 
-            this binding. */
+            this binding.  */
          if (! DECL_RTL_SET_P (parm))
            SET_DECL_RTL (parm, stack_parm);
        }
@@ -4865,7 +4884,7 @@ assign_parms (tree fndecl)
          rtx parmreg;
          unsigned int regno, regnoi = 0, regnor = 0;
 
-         unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
+         unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm));
 
          promoted_nominal_mode
            = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
@@ -4921,7 +4940,7 @@ assign_parms (tree fndecl)
 
              if (GET_CODE (tempreg) == SUBREG
                  && GET_MODE (tempreg) == nominal_mode
-                 && GET_CODE (SUBREG_REG (tempreg)) == REG
+                 && REG_P (SUBREG_REG (tempreg))
                  && nominal_mode == passed_mode
                  && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm)
                  && GET_MODE_SIZE (GET_MODE (tempreg))
@@ -4965,7 +4984,7 @@ assign_parms (tree fndecl)
              if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm)))
                {
                  rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm)));
-                 int unsigned_p = TREE_UNSIGNED (TREE_TYPE (parm));
+                 int unsigned_p = TYPE_UNSIGNED (TREE_TYPE (parm));
                  push_to_sequence (conversion_insns);
                  emit_move_insn (tempreg, DECL_RTL (parm));
                  SET_DECL_RTL (parm,
@@ -5087,7 +5106,7 @@ assign_parms (tree fndecl)
          if (nominal_mode == passed_mode
              && ! did_conversion
              && stack_parm != 0
-             && GET_CODE (stack_parm) == MEM
+             && MEM_P (stack_parm)
              && locate.offset.var == 0
              && reg_mentioned_p (virtual_incoming_args_rtx,
                                  XEXP (stack_parm, 0)))
@@ -5158,7 +5177,7 @@ assign_parms (tree fndecl)
 
              push_to_sequence (conversion_insns);
              entry_parm = convert_to_mode (nominal_mode, tempreg,
-                                           TREE_UNSIGNED (TREE_TYPE (parm)));
+                                           TYPE_UNSIGNED (TREE_TYPE (parm)));
              if (stack_parm)
                /* ??? This may need a big-endian conversion on sparc64.  */
                stack_parm = adjust_address (stack_parm, nominal_mode, 0);
@@ -5196,26 +5215,47 @@ assign_parms (tree fndecl)
        }
     }
 
-  if (SPLIT_COMPLEX_ARGS && fnargs != orig_fnargs)
+  if (targetm.calls.split_complex_arg && fnargs != orig_fnargs)
     {
       for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm))
        {
-         if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE)
+         if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
+             && targetm.calls.split_complex_arg (TREE_TYPE (parm)))
            {
-             SET_DECL_RTL (parm,
-                           gen_rtx_CONCAT (DECL_MODE (parm),
-                                           DECL_RTL (fnargs),
-                                           DECL_RTL (TREE_CHAIN (fnargs))));
-             DECL_INCOMING_RTL (parm)
-               = gen_rtx_CONCAT (DECL_MODE (parm),
-                                 DECL_INCOMING_RTL (fnargs),
-                                 DECL_INCOMING_RTL (TREE_CHAIN (fnargs)));
+             rtx tmp, real, imag;
+             enum machine_mode inner = GET_MODE_INNER (DECL_MODE (parm));
+
+             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);
+
+             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));
-             DECL_INCOMING_RTL (parm) = DECL_INCOMING_RTL (fnargs);
+             set_decl_incoming_rtl (parm, DECL_INCOMING_RTL (fnargs));
+
+             /* Set MEM_EXPR to the original decl, i.e. to PARM,
+                instead of the copy of decl, i.e. FNARGS.  */
+             if (DECL_INCOMING_RTL (parm)
+                 && MEM_P (DECL_INCOMING_RTL (parm)))
+               set_mem_expr (DECL_INCOMING_RTL (parm), parm);
            }
          fnargs = TREE_CHAIN (fnargs);
        }
@@ -5241,19 +5281,17 @@ assign_parms (tree fndecl)
       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
 
   current_function_args_size
     = ((current_function_args_size + STACK_BYTES - 1)
@@ -5330,8 +5368,12 @@ split_complex_args (tree args)
 
   /* 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;
+    {
+      tree type = TREE_TYPE (p);
+      if (TREE_CODE (type) == COMPLEX_TYPE
+         && targetm.calls.split_complex_arg (type))
+        goto found;
+    }
   return args;
 
  found:
@@ -5340,7 +5382,8 @@ split_complex_args (tree args)
   for (p = args; p; p = TREE_CHAIN (p))
     {
       tree type = TREE_TYPE (p);
-      if (TREE_CODE (type) == COMPLEX_TYPE)
+      if (TREE_CODE (type) == COMPLEX_TYPE
+         && targetm.calls.split_complex_arg (type))
        {
          tree decl;
          tree subtype = TREE_TYPE (type);
@@ -5381,12 +5424,12 @@ promoted_input_arg (unsigned int regno, enum machine_mode *pmode, int *punsigned
 
   for (arg = DECL_ARGUMENTS (current_function_decl); arg;
        arg = TREE_CHAIN (arg))
-    if (GET_CODE (DECL_INCOMING_RTL (arg)) == REG
+    if (REG_P (DECL_INCOMING_RTL (arg))
        && REGNO (DECL_INCOMING_RTL (arg)) == regno
        && TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
       {
        enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
-       int unsignedp = TREE_UNSIGNED (TREE_TYPE (arg));
+       int unsignedp = TYPE_UNSIGNED (TREE_TYPE (arg));
 
        mode = promote_mode (TREE_TYPE (arg), mode, &unsignedp, 1);
        if (mode == GET_MODE (DECL_INCOMING_RTL (arg))
@@ -5447,11 +5490,7 @@ locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs,
   int part_size_in_regs;
 
 #ifdef REG_PARM_STACK_SPACE
-#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 we have found a stack parm before we reach the end of the
      area reserved for registers, skip that area.  */
@@ -5647,49 +5686,30 @@ pad_below (struct args_size *offset_ptr, enum machine_mode passed_mode, tree siz
 }
 \f
 /* Walk the tree of blocks describing the binding levels within a function
-   and warn about uninitialized variables.
+   and warn about variables the might be killed by setjmp or vfork.
    This is done after calling flow_analysis and before global_alloc
    clobbers the pseudo-regs to hard regs.  */
 
 void
-uninitialized_vars_warning (tree block)
+setjmp_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
-         /* 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
-         && 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.
-
-            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 ("%J'%D' might be used uninitialized in this function",
-                decl, decl);
-      if (extra_warnings
-         && TREE_CODE (decl) == VAR_DECL
-         && DECL_RTL (decl) != 0
-         && GET_CODE (DECL_RTL (decl)) == REG
+      if (TREE_CODE (decl) == VAR_DECL
+         && DECL_RTL_SET_P (decl)
+         && REG_P (DECL_RTL (decl))
          && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
        warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'",
                 decl, decl);
     }
+
   for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
-    uninitialized_vars_warning (sub);
+    setjmp_vars_warning (sub);
 }
 
-/* Do the appropriate part of uninitialized_vars_warning
+/* Do the appropriate part of setjmp_vars_warning
    but for arguments instead of local variables.  */
 
 void
@@ -5699,7 +5719,7 @@ setjmp_args_warning (void)
   for (decl = DECL_ARGUMENTS (current_function_decl);
        decl; decl = TREE_CHAIN (decl))
     if (DECL_RTL (decl) != 0
-       && GET_CODE (DECL_RTL (decl)) == REG
+       && REG_P (DECL_RTL (decl))
        && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
       warning ("%Jargument '%D' might be clobbered by `longjmp' or `vfork'",
               decl, decl);
@@ -5716,8 +5736,8 @@ setjmp_protect (tree block)
     if ((TREE_CODE (decl) == VAR_DECL
         || TREE_CODE (decl) == PARM_DECL)
        && DECL_RTL (decl) != 0
-       && (GET_CODE (DECL_RTL (decl)) == REG
-           || (GET_CODE (DECL_RTL (decl)) == MEM
+       && (REG_P (DECL_RTL (decl))
+           || (MEM_P (DECL_RTL (decl))
                && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
        /* If this variable came from an inline function, it must be
           that its life doesn't overlap the setjmp.  If there was a
@@ -5749,8 +5769,8 @@ setjmp_protect_args (void)
     if ((TREE_CODE (decl) == VAR_DECL
         || TREE_CODE (decl) == PARM_DECL)
        && DECL_RTL (decl) != 0
-       && (GET_CODE (DECL_RTL (decl)) == REG
-           || (GET_CODE (DECL_RTL (decl)) == MEM
+       && (REG_P (DECL_RTL (decl))
+           || (MEM_P (DECL_RTL (decl))
                && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
        && (
            /* If longjmp doesn't restore the registers,
@@ -5763,33 +5783,6 @@ setjmp_protect_args (void)
       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 (tree decl)
-{
-  tree context = decl_function_context (decl);
-  tree link;
-
-  if (context == 0
-      || (TREE_CODE (decl) == FUNCTION_DECL && DECL_NO_STATIC_CHAIN (decl)))
-    return 0;
-
-  /* We treat inline_function_decl as an alias for the current function
-     because that is the inline function whose vars, types, etc.
-     are being merged into the current function.
-     See expand_inline_function.  */
-  if (context == current_function_decl || context == inline_function_decl)
-    return virtual_stack_vars_rtx;
-
-  for (link = context_display; link; link = TREE_CHAIN (link))
-    if (TREE_PURPOSE (link) == context)
-      return RTL_EXPR_RTL (TREE_VALUE (link));
-
-  abort ();
-}
-\f
 /* Convert a stack slot address ADDR for variable VAR
    (from a containing function)
    into an address valid in this function (using a static chain).  */
@@ -5804,65 +5797,22 @@ fix_lexical_addr (rtx addr, tree var)
   rtx base = 0;
 
   /* If this is the present function, we need not do anything.  */
-  if (context == current_function_decl || context == inline_function_decl)
+  if (context == current_function_decl)
     return addr;
 
   fp = find_function_data (context);
 
-  if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM)
+  if (GET_CODE (addr) == ADDRESSOF && MEM_P (XEXP (addr, 0)))
     addr = XEXP (XEXP (addr, 0), 0);
 
   /* Decode given address as base reg plus displacement.  */
-  if (GET_CODE (addr) == REG)
+  if (REG_P (addr))
     basereg = addr, displacement = 0;
   else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
     basereg = XEXP (addr, 0), displacement = INTVAL (XEXP (addr, 1));
   else
     abort ();
 
-  /* We accept vars reached via the containing function's
-     incoming arg pointer and via its stack variables pointer.  */
-  if (basereg == fp->internal_arg_pointer)
-    {
-      /* If reached via arg pointer, get the arg pointer value
-        out of that function's stack frame.
-
-        There are two cases:  If a separate ap is needed, allocate a
-        slot in the outer function for it and dereference it that way.
-        This is correct even if the real ap is actually a pseudo.
-        Otherwise, just adjust the offset from the frame pointer to
-        compensate.  */
-
-#ifdef NEED_SEPARATE_AP
-      rtx addr;
-
-      addr = get_arg_pointer_save_area (fp);
-      addr = fix_lexical_addr (XEXP (addr, 0), var);
-      addr = memory_address (Pmode, addr);
-
-      base = gen_rtx_MEM (Pmode, addr);
-      set_mem_alias_set (base, get_frame_alias_set ());
-      base = copy_to_reg (base);
-#else
-      displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET);
-      base = lookup_static_chain (var);
-#endif
-    }
-
-  else if (basereg == virtual_stack_vars_rtx)
-    {
-      /* This is the same code as lookup_static_chain, duplicated here to
-        avoid an extra call to decl_function_context.  */
-      tree link;
-
-      for (link = context_display; link; link = TREE_CHAIN (link))
-       if (TREE_PURPOSE (link) == context)
-         {
-           base = RTL_EXPR_RTL (TREE_VALUE (link));
-           break;
-         }
-    }
-
   if (base == 0)
     abort ();
 
@@ -5871,207 +5821,6 @@ fix_lexical_addr (rtx addr, tree var)
   return plus_constant (base, displacement);
 }
 \f
-/* Return the address of the trampoline for entering nested fn FUNCTION.
-   If necessary, allocate a trampoline (in the stack frame)
-   and emit rtl to initialize its contents (at entry to this function).  */
-
-rtx
-trampoline_address (tree function)
-{
-  tree link;
-  tree rtlexp;
-  rtx tramp;
-  struct function *fp;
-  tree fn_context;
-
-  /* Find an existing trampoline and return it.  */
-  for (link = trampoline_list; link; link = TREE_CHAIN (link))
-    if (TREE_PURPOSE (link) == function)
-      return
-       adjust_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
-
-  for (fp = outer_function_chain; fp; fp = fp->outer)
-    for (link = fp->x_trampoline_list; link; link = TREE_CHAIN (link))
-      if (TREE_PURPOSE (link) == function)
-       {
-         tramp = fix_lexical_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0),
-                                   function);
-         return adjust_trampoline_addr (tramp);
-       }
-
-  /* None exists; we must make one.  */
-
-  /* Find the `struct function' for the function containing FUNCTION.  */
-  fp = 0;
-  fn_context = decl_function_context (function);
-  if (fn_context != current_function_decl
-      && fn_context != inline_function_decl)
-    fp = find_function_data (fn_context);
-
-  /* Allocate run-time space for this trampoline.  */
-  /* If rounding needed, allocate extra space
-     to ensure we have TRAMPOLINE_SIZE bytes left after rounding up.  */
-#define TRAMPOLINE_REAL_SIZE \
-  (TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1)
-  tramp = assign_stack_local_1 (BLKmode, TRAMPOLINE_REAL_SIZE, 0,
-                               fp ? fp : cfun);
-  /* Record the trampoline for reuse and note it for later initialization
-     by expand_function_end.  */
-  if (fp != 0)
-    {
-      rtlexp = make_node (RTL_EXPR);
-      RTL_EXPR_RTL (rtlexp) = tramp;
-      fp->x_trampoline_list = tree_cons (function, rtlexp,
-                                        fp->x_trampoline_list);
-    }
-  else
-    {
-      /* Make the RTL_EXPR node temporary, not momentary, so that the
-        trampoline_list doesn't become garbage.  */
-      rtlexp = make_node (RTL_EXPR);
-
-      RTL_EXPR_RTL (rtlexp) = tramp;
-      trampoline_list = tree_cons (function, rtlexp, trampoline_list);
-    }
-
-  tramp = fix_lexical_addr (XEXP (tramp, 0), function);
-  return adjust_trampoline_addr (tramp);
-}
-
-/* Given a trampoline address,
-   round it to multiple of TRAMPOLINE_ALIGNMENT.  */
-
-static rtx
-round_trampoline_addr (rtx tramp)
-{
-  /* Round address up to desired boundary.  */
-  rtx temp = gen_reg_rtx (Pmode);
-  rtx addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
-  rtx mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
-
-  temp  = expand_simple_binop (Pmode, PLUS, tramp, addend,
-                              temp, 0, OPTAB_LIB_WIDEN);
-  tramp = expand_simple_binop (Pmode, AND, temp, mask,
-                              temp, 0, OPTAB_LIB_WIDEN);
-
-  return tramp;
-}
-
-/* Given a trampoline address, round it then apply any
-   platform-specific adjustments so that the result can be used for a
-   function call .  */
-
-static rtx
-adjust_trampoline_addr (rtx tramp)
-{
-  tramp = round_trampoline_addr (tramp);
-#ifdef TRAMPOLINE_ADJUST_ADDRESS
-  TRAMPOLINE_ADJUST_ADDRESS (tramp);
-#endif
-  return tramp;
-}
-\f
-/* Put all this function's BLOCK nodes including those that are chained
-   onto the first block into a vector, and return it.
-   Also store in each NOTE for the beginning or end of a block
-   the index of that block in the vector.
-   The arguments are BLOCK, the chain of top-level blocks of the function,
-   and INSNS, the insn chain of the function.  */
-
-void
-identify_blocks (void)
-{
-  int n_blocks;
-  tree *block_vector, *last_block_vector;
-  tree *block_stack;
-  tree block = DECL_INITIAL (current_function_decl);
-
-  if (block == 0)
-    return;
-
-  /* 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 = xmalloc (n_blocks * sizeof (tree));
-
-  last_block_vector = identify_blocks_1 (get_insns (),
-                                        block_vector + 1,
-                                        block_vector + n_blocks,
-                                        block_stack);
-
-  /* If we didn't use all of the subblocks, we've misplaced block notes.  */
-  /* ??? This appears to happen all the time.  Latent bugs elsewhere?  */
-  if (0 && last_block_vector != block_vector + n_blocks)
-    abort ();
-
-  free (block_vector);
-  free (block_stack);
-}
-
-/* Subroutine of identify_blocks.  Do the block substitution on the
-   insn chain beginning with INSNS.  Recurse for CALL_PLACEHOLDER chains.
-
-   BLOCK_STACK is pushed and popped for each BLOCK_BEGIN/BLOCK_END pair.
-   BLOCK_VECTOR is incremented for each block seen.  */
-
-static tree *
-identify_blocks_1 (rtx insns, tree *block_vector, tree *end_block_vector,
-                  tree *orig_block_stack)
-{
-  rtx insn;
-  tree *block_stack = orig_block_stack;
-
-  for (insn = insns; insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == NOTE)
-       {
-         if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
-           {
-             tree b;
-
-             /* If there are more block notes than BLOCKs, something
-                is badly wrong.  */
-             if (block_vector == end_block_vector)
-               abort ();
-
-             b = *block_vector++;
-             NOTE_BLOCK (insn) = b;
-             *block_stack++ = b;
-           }
-         else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
-           {
-             /* If there are more NOTE_INSN_BLOCK_ENDs than
-                NOTE_INSN_BLOCK_BEGs, something is badly wrong.  */
-             if (block_stack == orig_block_stack)
-               abort ();
-
-             NOTE_BLOCK (insn) = *--block_stack;
-           }
-       }
-      else if (GET_CODE (insn) == CALL_INSN
-              && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
-       {
-         rtx cp = PATTERN (insn);
-
-         block_vector = identify_blocks_1 (XEXP (cp, 0), block_vector,
-                                           end_block_vector, block_stack);
-         if (XEXP (cp, 1))
-           block_vector = identify_blocks_1 (XEXP (cp, 1), block_vector,
-                                             end_block_vector, block_stack);
-         if (XEXP (cp, 2))
-           block_vector = identify_blocks_1 (XEXP (cp, 2), block_vector,
-                                             end_block_vector, block_stack);
-       }
-    }
-
-  /* If there are more NOTE_INSN_BLOCK_BEGINs than NOTE_INSN_BLOCK_ENDs,
-     something is badly wrong.  */
-  if (block_stack != orig_block_stack)
-    abort ();
-
-  return block_vector;
-}
-
 /* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END},
    and create duplicate blocks.  */
 /* ??? Need an option to either create block fragments or to create
@@ -6090,7 +5839,7 @@ reorder_blocks (void)
   VARRAY_TREE_INIT (block_stack, 10, "block_stack");
 
   /* Reset the TREE_ASM_WRITTEN bit for all blocks.  */
-  reorder_blocks_0 (block);
+  clear_block_marks (block);
 
   /* Prune the old trees away, so that they don't get in the way.  */
   BLOCK_SUBBLOCKS (block) = NULL_TREE;
@@ -6106,13 +5855,13 @@ reorder_blocks (void)
 
 /* Helper function for reorder_blocks.  Reset TREE_ASM_WRITTEN.  */
 
-static void
-reorder_blocks_0 (tree block)
+void
+clear_block_marks (tree block)
 {
   while (block)
     {
       TREE_ASM_WRITTEN (block) = 0;
-      reorder_blocks_0 (BLOCK_SUBBLOCKS (block));
+      clear_block_marks (BLOCK_SUBBLOCKS (block));
       block = BLOCK_CHAIN (block);
     }
 }
@@ -6172,16 +5921,6 @@ reorder_blocks_1 (rtx insns, tree current_block, varray_type *p_block_stack)
              current_block = BLOCK_SUPERCONTEXT (current_block);
            }
        }
-      else if (GET_CODE (insn) == CALL_INSN
-              && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
-       {
-         rtx cp = PATTERN (insn);
-         reorder_blocks_1 (XEXP (cp, 0), current_block, p_block_stack);
-         if (XEXP (cp, 1))
-           reorder_blocks_1 (XEXP (cp, 1), current_block, p_block_stack);
-         if (XEXP (cp, 2))
-           reorder_blocks_1 (XEXP (cp, 2), current_block, p_block_stack);
-       }
     }
 }
 
@@ -6243,7 +5982,7 @@ reorder_fix_fragments (tree block)
 /* Reverse the order of elements in the chain T of blocks,
    and return the new head of the chain (old last element).  */
 
-static tree
+tree
 blocks_nreverse (tree t)
 {
   tree prev = 0, decl, next;
@@ -6361,6 +6100,7 @@ void
 allocate_struct_function (tree fndecl)
 {
   tree result;
+  tree fntype = fndecl ? TREE_TYPE (fndecl) : NULL_TREE;
 
   cfun = ggc_alloc_cleared (sizeof (struct function));
 
@@ -6375,22 +6115,17 @@ allocate_struct_function (tree fndecl)
 
   init_stmt_for_function ();
   init_eh_for_function ();
-  init_emit ();
-  init_expr ();
-  init_varasm_status (cfun);
 
-  (*lang_hooks.function.init) (cfun);
+  lang_hooks.function.init (cfun);
   if (init_machine_status)
     cfun->machine = (*init_machine_status) ();
 
   if (fndecl == NULL)
     return;
 
-  DECL_SAVED_INSNS (fndecl) = cfun;
+  DECL_STRUCT_FUNCTION (fndecl) = cfun;
   cfun->decl = fndecl;
 
-  current_function_name = (*lang_hooks.decl_printable_name) (fndecl, 2);
-
   result = DECL_RESULT (fndecl);
   if (aggregate_value_p (result, fndecl))
     {
@@ -6402,9 +6137,11 @@ allocate_struct_function (tree fndecl)
 
   current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result));
 
-  current_function_needs_context
-    = (decl_function_context (current_function_decl) != 0
-       && ! DECL_NO_STATIC_CHAIN (current_function_decl));
+  current_function_stdarg
+    = (fntype
+       && TYPE_ARG_TYPES (fntype) != 0
+       && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+          != void_type_node));
 }
 
 /* Reset cfun, and other non-struct-function variables to defaults as
@@ -6413,10 +6150,13 @@ allocate_struct_function (tree fndecl)
 static void
 prepare_function_start (tree fndecl)
 {
-  if (fndecl && DECL_SAVED_INSNS (fndecl))
-    cfun = DECL_SAVED_INSNS (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 ();
 
   cse_not_expected = ! optimize;
 
@@ -6458,14 +6198,11 @@ init_function_start (tree subr)
 {
   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 (DECL_SOURCE_LINE (subr))
+  if (! DECL_IS_BUILTIN (subr))
     emit_line_note (DECL_SOURCE_LOCATION (subr));
 
   /* Make sure first insn is a note even if we don't want linenums.
@@ -6572,19 +6309,12 @@ expand_pending_sizes (tree pending_sizes)
    the function's parameters, which must be run at any return statement.  */
 
 void
-expand_function_start (tree subr, int parms_have_cleanups)
+expand_function_start (tree subr)
 {
-  tree tem;
-  rtx last_ptr = NULL_RTX;
-
   /* Make sure volatile mem refs aren't considered
      valid operands of arithmetic insns.  */
   init_recog_no_volatile ();
 
-  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));
@@ -6592,27 +6322,6 @@ expand_function_start (tree subr, int parms_have_cleanups)
   current_function_limit_stack
     = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
 
-  /* If function gets a static chain arg, store it in the stack frame.
-     Do this first, so it gets the first stack slot offset.  */
-  if (current_function_needs_context)
-    {
-      last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-
-      /* Delay copying static chain if it is not a register to avoid
-        conflicts with regs used for parameters.  */
-      if (! SMALL_REGISTER_CLASSES
-         || GET_CODE (static_chain_incoming_rtx) == REG)
-       emit_move_insn (last_ptr, static_chain_incoming_rtx);
-    }
-
-  /* If the parameters of this function need cleaning up, get a label
-     for the beginning of the code which executes those cleanups.  This must
-     be done before doing anything with return_label.  */
-  if (parms_have_cleanups)
-    cleanup_label = gen_label_rtx ();
-  else
-    cleanup_label = 0;
-
   /* Make the label for return statements to jump to.  Do not special
      case machines with special return instructions -- they will be
      handled later during jump, ifcvt, or epilogue creation.  */
@@ -6685,15 +6394,40 @@ expand_function_start (tree subr, int parms_have_cleanups)
 
   /* Initialize rtx for parameters and local variables.
      In some cases this requires emitting insns.  */
-
   assign_parms (subr);
 
-  /* Copy the static chain now if it wasn't a register.  The delay is to
-     avoid conflicts with the parameter passing registers.  */
+  /* If function gets a static chain arg, store it.  */
+  if (cfun->static_chain_decl)
+    {
+      tree parm = cfun->static_chain_decl;
+      rtx local = gen_reg_rtx (Pmode);
+
+      set_decl_incoming_rtl (parm, static_chain_incoming_rtx);
+      SET_DECL_RTL (parm, local);
+      maybe_set_unchanging (local, parm);
+      mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
+
+      emit_move_insn (local, static_chain_incoming_rtx);
+    }
+
+  /* If the function receives a non-local goto, then store the
+     bits we need to restore the frame pointer.  */
+  if (cfun->nonlocal_goto_save_area)
+    {
+      tree t_save;
+      rtx r_save;
 
-  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);
+      /* ??? We need to do this save early.  Unfortunately here is
+        before the frame variable gets declared.  Help out...  */
+      expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0));
+
+      t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
+                     integer_zero_node, NULL_TREE, NULL_TREE);
+      r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
+
+      emit_move_insn (r_save, virtual_stack_vars_rtx);
+      update_nonlocal_goto_save_area ();
+    }
 
   /* The following was moved from init_function_start.
      The move is supposed to make sdb output more accurate.  */
@@ -6705,67 +6439,6 @@ expand_function_start (tree subr, int parms_have_cleanups)
     emit_note (NOTE_INSN_DELETED);
   parm_birth_insn = get_last_insn ();
 
-  context_display = 0;
-  if (current_function_needs_context)
-    {
-      /* Fetch static chain values for containing functions.  */
-      tem = decl_function_context (current_function_decl);
-      /* Copy the static chain pointer into a pseudo.  If we have
-        small register classes, copy the value from memory if
-        static_chain_incoming_rtx is a REG.  */
-      if (tem)
-       {
-         /* If the static chain originally came in a register, put it back
-            there, then move it out in the next insn.  The reason for
-            this peculiar code is to satisfy function integration.  */
-         if (SMALL_REGISTER_CLASSES
-             && GET_CODE (static_chain_incoming_rtx) == REG)
-           emit_move_insn (static_chain_incoming_rtx, last_ptr);
-         last_ptr = copy_to_reg (static_chain_incoming_rtx);
-       }
-
-      while (tem)
-       {
-         tree rtlexp = make_node (RTL_EXPR);
-
-         RTL_EXPR_RTL (rtlexp) = last_ptr;
-         context_display = tree_cons (tem, rtlexp, context_display);
-         tem = decl_function_context (tem);
-         if (tem == 0)
-           break;
-         /* Chain thru 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,
-                                   -(HOST_WIDE_INT) GET_MODE_SIZE (Pmode));
-#endif
-         last_ptr = gen_rtx_MEM (Pmode, memory_address (Pmode, last_ptr));
-         set_mem_alias_set (last_ptr, get_frame_alias_set ());
-         last_ptr = copy_to_reg (last_ptr);
-
-         /* If we are not optimizing, ensure that we know that this
-            piece of context is live over the entire function.  */
-         if (! optimize)
-           save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, last_ptr,
-                                               save_expr_regs);
-       }
-    }
-
-  if (current_function_instrument_entry_exit)
-    {
-      rtx fun = DECL_RTL (current_function_decl);
-      if (GET_CODE (fun) == MEM)
-       fun = XEXP (fun, 0);
-      else
-       abort ();
-      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
@@ -6812,7 +6485,7 @@ diddle_return_value (void (*doit) (rtx, void *), void *arg)
   if (! outgoing)
     return;
 
-  if (GET_CODE (outgoing) == REG)
+  if (REG_P (outgoing))
     (*doit) (outgoing, arg);
   else if (GET_CODE (outgoing) == PARALLEL)
     {
@@ -6822,7 +6495,7 @@ diddle_return_value (void (*doit) (rtx, void *), void *arg)
        {
          rtx x = XEXP (XVECEXP (outgoing, 0, i), 0);
 
-         if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+         if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
            (*doit) (x, arg);
        }
     }
@@ -6863,6 +6536,19 @@ use_return_register (void)
   diddle_return_value (do_use_return_reg, NULL);
 }
 
+/* Possibly warn about unused parameters.  */
+void
+do_warn_unused_parameter (tree fn)
+{
+  tree decl;
+
+  for (decl = DECL_ARGUMENTS (fn);
+       decl; decl = TREE_CHAIN (decl))
+    if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
+       && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))
+      warning ("%Junused parameter '%D'", decl, decl);
+}
+
 static GTY(()) rtx initial_trampoline;
 
 /* Generate RTL for the end of the current function.  */
@@ -6870,7 +6556,6 @@ static GTY(()) rtx initial_trampoline;
 void
 expand_function_end (void)
 {
-  tree link;
   rtx clobber_after;
 
   finish_expr_for_function ();
@@ -6892,45 +6577,6 @@ expand_function_end (void)
     }
 #endif
 
-  /* Initialize any trampolines required by this function.  */
-  for (link = trampoline_list; link; link = TREE_CHAIN (link))
-    {
-      tree function = TREE_PURPOSE (link);
-      rtx context ATTRIBUTE_UNUSED = lookup_static_chain (function);
-      rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link));
-#ifdef TRAMPOLINE_TEMPLATE
-      rtx blktramp;
-#endif
-      rtx seq;
-
-#ifdef TRAMPOLINE_TEMPLATE
-      /* First make sure this compilation has a template for
-        initializing trampolines.  */
-      if (initial_trampoline == 0)
-       {
-         initial_trampoline
-           = gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
-         set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
-       }
-#endif
-
-      /* Generate insns to initialize the trampoline.  */
-      start_sequence ();
-      tramp = round_trampoline_addr (XEXP (tramp, 0));
-#ifdef TRAMPOLINE_TEMPLATE
-      blktramp = replace_equiv_address (initial_trampoline, tramp);
-      emit_block_move (blktramp, initial_trampoline,
-                      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_insn_before (seq, tail_recursion_reentry);
-    }
-
   /* If we are doing stack checking and this function makes calls,
      do a stack probe at the start of the function to ensure we have enough
      space for another stack frame.  */
@@ -6951,34 +6597,28 @@ expand_function_end (void)
          }
     }
 
-  /* Possibly warn about unused parameters.  */
-  if (warn_unused_parameter)
-    {
-      tree decl;
-
-      for (decl = DECL_ARGUMENTS (current_function_decl);
-          decl; decl = TREE_CHAIN (decl))
-       if (! TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
-           && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
-          warning ("%Junused parameter '%D'", decl, decl);
-    }
-
-  /* Delete handlers for nonlocal gotos if nothing uses them.  */
-  if (nonlocal_goto_handler_slots != 0
-      && ! current_function_has_nonlocal_label)
-    delete_handlers ();
+  /* Possibly warn about unused parameters.
+     When frontend does unit-at-a-time, the warning is already
+     issued at finalization time.  */
+  if (warn_unused_parameter
+      && !lang_hooks.callgraph.expand_function)
+    do_warn_unused_parameter (current_function_decl);
 
   /* End any sequences that failed to be closed due to syntax errors.  */
   while (in_sequence_p ())
     end_sequence ();
 
-  /* Outside function body, can't compute type's actual size
-     until next function's body starts.  */
-  immediate_size_expand--;
-
   clear_pending_stack_adjust ();
   do_pending_stack_adjust ();
 
+  /* @@@ This is a kludge.  We want to ensure that instructions that
+     may trap are not moved into the epilogue by scheduling, because
+     we don't always emit unwind information for the epilogue.
+     However, not all machine descriptions define a blockage insn, so
+     emit an ASM_INPUT to act as one.  */
+  if (flag_non_call_exceptions)
+    emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
+
   /* Mark the end of the function body.
      If control reaches this insn, the function can drop through
      without returning a value.  */
@@ -7015,21 +6655,6 @@ expand_function_end (void)
   if (return_label)
     emit_label (return_label);
 
-  if (current_function_instrument_entry_exit)
-    {
-      rtx fun = DECL_RTL (current_function_decl);
-      if (GET_CODE (fun) == MEM)
-       fun = XEXP (fun, 0);
-      else
-       abort ();
-      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),
-                        Pmode);
-    }
-
   /* Let except.c know where it should emit the call to unregister
      the function context for sjlj exceptions.  */
   if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
@@ -7038,16 +6663,14 @@ expand_function_end (void)
   /* 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
@@ -7079,7 +6702,7 @@ expand_function_end (void)
             extension.  */
          if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
            {
-             int unsignedp = TREE_UNSIGNED (TREE_TYPE (decl_result));
+             int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
 
              if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
                promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
@@ -7154,9 +6777,6 @@ expand_function_end (void)
     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
@@ -7239,7 +6859,7 @@ record_insns (rtx insns, varray_type *vecp)
     }
 }
 
-/* Set the specified locator to the insn chain.  */
+/* Set the locator of the insn chain starting at INSN to LOC.  */
 static void
 set_insn_locators (rtx insn, int loc)
 {
@@ -7423,19 +7043,19 @@ keep_stack_depressed (rtx insns)
             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)
+         if (REG_P (retaddr))
            {
              emit_equiv_load (&info);
              add_insn (insn);
              insn = next;
              continue;
            }
-         else if (GET_CODE (retaddr) == MEM
-                  && GET_CODE (XEXP (retaddr, 0)) == REG)
+         else if (MEM_P (retaddr)
+                  && REG_P (XEXP (retaddr, 0)))
            base = gen_rtx_REG (Pmode, REGNO (XEXP (retaddr, 0))), offset = 0;
-         else if (GET_CODE (retaddr) == MEM
+         else if (MEM_P (retaddr)
                   && GET_CODE (XEXP (retaddr, 0)) == PLUS
-                  && GET_CODE (XEXP (XEXP (retaddr, 0), 0)) == REG
+                  && REG_P (XEXP (XEXP (retaddr, 0), 0))
                   && GET_CODE (XEXP (XEXP (retaddr, 0), 1)) == CONST_INT)
            {
              base = gen_rtx_REG (Pmode, REGNO (XEXP (XEXP (retaddr, 0), 0)));
@@ -7471,8 +7091,8 @@ keep_stack_depressed (rtx insns)
                    && !REGNO_REG_SET_P (EXIT_BLOCK_PTR->global_live_at_start,
                                         regno)
                    && !refers_to_regno_p (regno,
-                                          regno + HARD_REGNO_NREGS (regno,
-                                                                    Pmode),
+                                          regno + hard_regno_nregs[regno]
+                                                                  [Pmode],
                                           info.equiv_reg_src, NULL)
                    && info.const_equiv[regno] == 0)
                  break;
@@ -7560,7 +7180,7 @@ handle_epilogue_set (rtx set, struct epi_info *p)
          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
+         else if (REG_P (XEXP (SET_SRC (set), 1))
                   && REGNO (XEXP (SET_SRC (set), 1)) < FIRST_PSEUDO_REGISTER
                   && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))] != 0)
            p->new_sp_offset
@@ -7578,7 +7198,7 @@ handle_epilogue_set (rtx set, struct epi_info *p)
          p->new_sp_offset += p->sp_offset;
        }
 
-      if (p->new_sp_equiv_reg == 0 || GET_CODE (p->new_sp_equiv_reg) != REG)
+      if (p->new_sp_equiv_reg == 0 || !REG_P (p->new_sp_equiv_reg))
        abort ();
 
       return;
@@ -7595,8 +7215,8 @@ handle_epilogue_set (rtx set, struct epi_info *p)
   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
+         || !REG_P (p->new_sp_equiv_reg)
+         || !REG_P (SET_DEST (set))
          || GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) > BITS_PER_WORD
          || REGNO (p->new_sp_equiv_reg) != REGNO (SET_DEST (set)))
        abort ();
@@ -7627,14 +7247,37 @@ 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)
+  if (!REG_P (dest) || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
     return;
-  else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x))
-          || GET_CODE (SET_SRC (x)) != CONST_INT)
+
+  /* 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;
-  else
+
+  /* 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 (ARITHMETIC_P (SET_SRC (x))
+          && REG_P (XEXP (SET_SRC (x), 0))
+          && 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.  */
@@ -7805,20 +7448,20 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
        }
     }
 #endif
+  /* Find the edge that falls through to EXIT.  Other edges may exist
+     due to RETURN instructions, but those don't need epilogues.
+     There really shouldn't be a mixture -- either all should have
+     been converted or none, however...  */
+
+  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+    if (e->flags & EDGE_FALLTHRU)
+      break;
+  if (e == NULL)
+    goto epilogue_done;
+
 #ifdef HAVE_epilogue
   if (HAVE_epilogue)
     {
-      /* Find the edge that falls through to EXIT.  Other edges may exist
-        due to RETURN instructions, but those don't need epilogues.
-        There really shouldn't be a mixture -- either all should have
-        been converted or none, however...  */
-
-      for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
-      if (e == NULL)
-       goto epilogue_done;
-
       start_sequence ();
       epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
 
@@ -7844,7 +7487,26 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
       insert_insn_on_edge (seq, e);
       inserted = 1;
     }
+  else
 #endif
+    {
+      basic_block cur_bb;
+
+      if (! next_active_insn (BB_END (e->src)))
+       goto epilogue_done;
+      /* We have a fall-through edge to the exit block, the source is not
+         at the end of the function, and there will be an assembler epilogue
+         at the end of the function.
+         We can't use force_nonfallthru here, because that would try to
+         use return.  Inserting a jump 'by hand' is extremely messy, so
+        we take advantage of cfg_layout_finalize using
+       fixup_fallthru_exit_predecessor.  */
+      cfg_layout_initialize ();
+      FOR_EACH_BB (cur_bb)
+       if (cur_bb->index >= 0 && cur_bb->next_bb->index >= 0)
+         cur_bb->rbi->next = cur_bb->next_bb;
+      cfg_layout_finalize ();
+    }
 epilogue_done:
 
   if (inserted)
@@ -7880,6 +7542,7 @@ epilogue_done:
 #endif
 
 #ifdef HAVE_prologue
+  /* This is probably all useless now that we use locators.  */
   if (prologue_end)
     {
       rtx insn, prev;
@@ -7940,11 +7603,16 @@ epilogue_done:
 
       /* Similarly, move any line notes that appear after the epilogue.
          There is no need, however, to be quite so anal about the existence
-        of such a note.  */
+        of such a note.  Also move the NOTE_INSN_FUNCTION_END and (possibly)
+        NOTE_INSN_FUNCTION_BEG notes, as those can be relevant for debug
+        info generation.  */
       for (insn = epilogue_end; insn; insn = next)
        {
          next = NEXT_INSN (insn);
-         if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+         if (GET_CODE (insn) == NOTE 
+             && (NOTE_LINE_NUMBER (insn) > 0
+                 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG
+                 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END))
            reorder_insns (insn, insn, PREV_INSN (epilogue_end));
        }
     }
@@ -8053,4 +7721,64 @@ init_function_once (void)
   VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue");
 }
 
+/* Resets insn_block_boundaries array.  */
+
+void
+reset_block_changes (void)
+{
+  VARRAY_TREE_INIT (cfun->ib_boundaries_block, 100, "ib_boundaries_block");
+  VARRAY_PUSH_TREE (cfun->ib_boundaries_block, NULL_TREE);
+}
+
+/* Record the boundary for BLOCK.  */
+void
+record_block_change (tree block)
+{
+  int i, n;
+  tree last_block;
+
+  if (!block)
+    return;
+
+  last_block = VARRAY_TOP_TREE (cfun->ib_boundaries_block);
+  VARRAY_POP (cfun->ib_boundaries_block);
+  n = get_max_uid ();
+  for (i = VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block); i < n; i++)
+    VARRAY_PUSH_TREE (cfun->ib_boundaries_block, last_block);
+
+  VARRAY_PUSH_TREE (cfun->ib_boundaries_block, block);
+}
+
+/* Finishes record of boundaries.  */
+void finalize_block_changes (void)
+{
+  record_block_change (DECL_INITIAL (current_function_decl));
+}
+
+/* For INSN return the BLOCK it belongs to.  */ 
+void
+check_block_change (rtx insn, tree *block)
+{
+  unsigned uid = INSN_UID (insn);
+
+  if (uid >= VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block))
+    return;
+
+  *block = VARRAY_TREE (cfun->ib_boundaries_block, uid);
+}
+
+/* Releases the ib_boundaries_block records.  */
+void
+free_block_changes (void)
+{
+  cfun->ib_boundaries_block = NULL;
+}
+
+/* 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"