OSDN Git Service

* machmode.def: Add BImode. Add a column for bitsize.
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index a0038d1..6a9bdc9 100644 (file)
@@ -19,7 +19,6 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-
 /* This file handles the generation of rtl code from tree structure
    at the level of the function as a whole.
    It creates the rtl expressions for parameters and auto variables
@@ -108,7 +107,7 @@ Boston, MA 02111-1307, USA.  */
 /* Nonzero if function being compiled doesn't contain any calls
    (ignoring the prologue and epilogue).  This is set prior to
    local register allocation and is valid for the remaining
-   compiler passes. */
+   compiler passes.  */
 int current_function_is_leaf;
 
 /* Nonzero if function being compiled doesn't contain any instructions
@@ -118,7 +117,7 @@ int current_function_nothrow;
 
 /* Nonzero if function being compiled doesn't modify the stack pointer
    (ignoring the prologue and epilogue).  This is only valid after
-   life_analysis has run. */
+   life_analysis has run.  */
 int current_function_sp_is_unchanging;
 
 /* Nonzero if the function being compiled is a leaf function which only
@@ -190,7 +189,7 @@ struct temp_slot
   /* The rtx used to represent the address if not the address of the
      slot above.  May be an EXPR_LIST if multiple addresses exist.  */
   rtx address;
-  /* The alignment (in bits) of the slot. */
+  /* The alignment (in bits) of the slot.  */
   int align;
   /* The size, in units, of the slot.  */
   HOST_WIDE_INT size;
@@ -204,7 +203,7 @@ struct temp_slot
      imposed on the memory.  For example, if the stack slot is the
      call frame for an inline functioned, we have no idea what alias
      sets will be assigned to various pieces of the call frame.  */
-  int alias_set;
+  HOST_WIDE_INT alias_set;
   /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
   tree rtl_expr;
   /* Non-zero if this temporary is currently in use.  */
@@ -234,7 +233,7 @@ struct fixup_replacement
   rtx new;
   struct fixup_replacement *next;
 };
-   
+
 struct insns_for_mem_entry {
   /* The KEY in HE will be a MEM.  */
   struct hash_entry he;
@@ -253,7 +252,10 @@ static void put_reg_into_stack     PARAMS ((struct function *, rtx, tree,
                                         enum machine_mode, enum machine_mode,
                                         int, unsigned int, int,
                                         struct hash_table *));
-static void fixup_var_refs     PARAMS ((rtx, enum machine_mode, int, 
+static void schedule_fixup_var_refs PARAMS ((struct function *, rtx, tree,
+                                            enum machine_mode,
+                                            struct hash_table *));
+static void fixup_var_refs     PARAMS ((rtx, enum machine_mode, int,
                                         struct hash_table *));
 static struct fixup_replacement
   *find_fixup_replacement      PARAMS ((struct fixup_replacement **, rtx));
@@ -276,9 +278,6 @@ static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
 static void pad_below          PARAMS ((struct args_size *, enum machine_mode,
                                         tree));
 #endif
-#ifdef ARGS_GROW_DOWNWARD
-static tree round_down         PARAMS ((tree, int));
-#endif
 static rtx round_trampoline_addr PARAMS ((rtx));
 static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
 static void reorder_blocks_1   PARAMS ((rtx, tree, varray_type *));
@@ -290,11 +289,14 @@ static tree *get_block_vector   PARAMS ((tree, int *));
 static void record_insns       PARAMS ((rtx, varray_type *)) ATTRIBUTE_UNUSED;
 static int contains            PARAMS ((rtx, varray_type));
 #ifdef HAVE_return
-static void emit_return_into_block PARAMS ((basic_block));
+static void emit_return_into_block PARAMS ((basic_block, rtx));
 #endif
 static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
-static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int, 
+static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
                                          struct hash_table *));
+#ifdef HAVE_epilogue
+static void keep_stack_depressed PARAMS ((rtx));
+#endif
 static int is_addressof                PARAMS ((rtx *, void *));
 static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *,
                                                         struct hash_table *,
@@ -411,6 +413,7 @@ pop_function_context_from (context)
   /* Reset variables that have known state during rtx generation.  */
   rtx_equal_function_value_matters = 1;
   virtuals_instantiated = 0;
+  generating_concat_p = 1;
 }
 
 void
@@ -492,7 +495,6 @@ free_after_compilation (f)
   f->inl_last_parm_insn = NULL;
   f->epilogue_delay_list = NULL;
 }
-
 \f
 /* Allocate fixed slots in the stack frame of the current function.  */
 
@@ -523,7 +525,7 @@ get_frame_size ()
 
 /* Allocate a stack slot of SIZE bytes and return a MEM rtx for it
    with machine mode MODE.
-   
+
    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,
@@ -554,9 +556,10 @@ assign_stack_local_1 (mode, size, align, function)
     {
       tree type;
 
-      alignment = GET_MODE_ALIGNMENT (mode);
       if (mode == BLKmode)
        alignment = BIGGEST_ALIGNMENT;
+      else
+       alignment = GET_MODE_ALIGNMENT (mode);
 
       /* Allow the target to (possibly) increase the alignment of this
         stack slot.  */
@@ -628,6 +631,7 @@ assign_stack_local_1 (mode, size, align, function)
 
 /* Wrapper around assign_stack_local_1;  assign a local stack slot for the
    current function.  */
+
 rtx
 assign_stack_local (mode, size, align)
      enum machine_mode mode;
@@ -650,7 +654,7 @@ assign_stack_local (mode, size, align)
    with this flag.  KEEP is 2 if we allocate a longer term temporary,
    whose lifetime is controlled by CLEANUP_POINT_EXPRs.  KEEP is 3
    if we are to allocate something at an inner level to be treated as
-   a variable in the block (e.g., a SAVE_EXPR).  
+   a variable in the block (e.g., a SAVE_EXPR).
 
    TYPE is the type that will be used for the stack slot.  */
 
@@ -662,7 +666,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
      tree type;
 {
   int align;
-  int alias_set;
+  HOST_WIDE_INT alias_set;
   struct temp_slot *p, *best_p = 0;
 
   /* If SIZE is -1 it means that somebody tried to allocate a temporary
@@ -675,15 +679,17 @@ assign_stack_temp_for_type (mode, size, keep, type)
      alias set for the memory.  */
   if (type)
     alias_set = get_alias_set (type);
-  else 
+  else
     alias_set = 0;
 
-  align = GET_MODE_ALIGNMENT (mode);
   if (mode == BLKmode)
     align = BIGGEST_ALIGNMENT;
+  else
+    align = GET_MODE_ALIGNMENT (mode);
 
   if (! type)
     type = type_for_mode (mode, 0);
+
   if (type)
     align = LOCAL_ALIGNMENT (type, align);
 
@@ -693,7 +699,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
   for (p = temp_slots; p; p = p->next)
     if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
        && ! p->in_use
-       && (!flag_strict_aliasing
+       && (! flag_strict_aliasing
            || (alias_set && p->alias_set == alias_set))
        && (best_p == 0 || best_p->size > p->size
            || (best_p->size == p->size && best_p->align > p->align)))
@@ -712,11 +718,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
       /* 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.  */
-      if (GET_MODE (best_p->slot) == BLKmode
-         /* We can't split slots if -fstrict-aliasing because the
-            information about the alias set for the new slot will be
-            lost.  */
-         && !flag_strict_aliasing)
+      if (GET_MODE (best_p->slot) == BLKmode)
        {
          int alignment = best_p->align / BITS_PER_UNIT;
          HOST_WIDE_INT rounded_size = CEIL_ROUND (size, alignment);
@@ -734,6 +736,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
              p->align = best_p->align;
              p->address = 0;
              p->rtl_expr = 0;
+             p->alias_set = best_p->alias_set;
              p->next = temp_slots;
              temp_slots = p;
 
@@ -747,7 +750,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
 
       p = best_p;
     }
-             
+
   /* If we still didn't find one, make a new temporary.  */
   if (p == 0)
     {
@@ -824,7 +827,11 @@ assign_stack_temp_for_type (mode, size, keep, type)
   RTX_UNCHANGING_P (p->slot) = 0;
   MEM_IN_STRUCT_P (p->slot) = 0;
   MEM_SCALAR_P (p->slot) = 0;
-  MEM_ALIAS_SET (p->slot) = 0;
+  MEM_ALIAS_SET (p->slot) = alias_set;
+
+  if (type != 0)
+    MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type));
+
   return p->slot;
 }
 
@@ -875,11 +882,10 @@ assign_temp (type, keep, memory_required, dont_promote)
         instead.  This is the case for Chill variable-sized strings.  */
       if (size == -1 && TREE_CODE (type) == ARRAY_TYPE
          && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE
-         && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type)) == INTEGER_CST)
-       size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type));
+         && host_integerp (TYPE_ARRAY_MAX_SIZE (type), 1))
+       size = tree_low_cst (TYPE_ARRAY_MAX_SIZE (type), 1);
 
       tmp = assign_stack_temp_for_type (mode, size, keep, type);
-      MEM_SET_IN_STRUCT_P (tmp, AGGREGATE_TYPE_P (type));
       return tmp;
     }
 
@@ -909,7 +915,7 @@ combine_temp_slots ()
   if (flag_strict_aliasing)
     return;
 
-  /* If there are a lot of temp slots, don't do anything unless 
+  /* If there are a lot of temp slots, don't do anything unless
      high levels of optimizaton.  */
   if (! flag_expensive_optimizations)
     for (p = temp_slots, num_slots = 0; p; p = p->next, num_slots++)
@@ -1004,7 +1010,7 @@ find_temp_slot_from_address (x)
 
   return 0;
 }
-      
+
 /* Indicate that NEW is an alternate way of referring to the temp slot
    that previously was known by OLD.  */
 
@@ -1050,7 +1056,7 @@ update_temp_slot_address (old, new)
       return;
     }
 
-  /* Otherwise add an alias for the temp's address. */
+  /* Otherwise add an alias for the temp's address.  */
   else if (p->address == 0)
     p->address = new;
   else
@@ -1333,6 +1339,9 @@ put_var_into_stack (decl)
   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)
+              || (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0));
 
   context = decl_function_context (decl);
 
@@ -1360,7 +1369,7 @@ put_var_into_stack (decl)
 
   /* If this is a variable-size object with a pseudo to address it,
      put that pseudo into the stack, if the var is nonlocal.  */
-  if (DECL_NONLOCAL (decl)
+  if (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)
       && GET_CODE (reg) == MEM
       && GET_CODE (XEXP (reg, 0)) == REG
       && REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)
@@ -1395,44 +1404,36 @@ put_var_into_stack (decl)
       if (can_use_addressof)
        gen_mem_addressof (reg, decl);
       else
-       put_reg_into_stack (function, reg, TREE_TYPE (decl),
-                           promoted_mode, decl_mode,
-                           TREE_SIDE_EFFECTS (decl), 0,
-                           TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                           0);
+       put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
+                           decl_mode, volatilep, 0, usedp, 0);
     }
   else if (GET_CODE (reg) == CONCAT)
     {
       /* A CONCAT contains two pseudos; put them both in the stack.
-        We do it so they end up consecutive.  */
+        We do it so they end up consecutive.
+        We fixup references to the parts only after we fixup references
+        to the whole CONCAT, lest we do double fixups for the latter
+        references.  */
       enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
       tree part_type = type_for_mode (part_mode, 0);
+      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, XEXP (reg, 1), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
-      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
+      put_reg_into_stack (function, hipart, part_type, part_mode,
+                         part_mode, volatilep, 0, 0, 0);
+      put_reg_into_stack (function, lopart, part_type, part_mode,
+                         part_mode, volatilep, 0, 0, 0);
 #else
-      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
-      put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
+      put_reg_into_stack (function, lopart, part_type, part_mode,
+                         part_mode, volatilep, 0, 0, 0);
+      put_reg_into_stack (function, hipart, part_type, part_mode,
+                         part_mode, volatilep, 0, 0, 0);
 #endif
 
       /* Change the CONCAT into a combined MEM for both parts.  */
       PUT_CODE (reg, MEM);
-      MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
-      MEM_ALIAS_SET (reg) = get_alias_set (decl);
-      MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (TREE_TYPE (decl)));
+      set_mem_attributes (reg, decl, 1);
 
       /* The two parts are in memory order already.
         Use the lower parts address as ours.  */
@@ -1440,13 +1441,20 @@ put_var_into_stack (decl)
       /* Prevent sharing of rtl that might lose.  */
       if (GET_CODE (XEXP (reg, 0)) == PLUS)
        XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
+      if (usedp)
+       {
+         schedule_fixup_var_refs (function, reg, TREE_TYPE (decl),
+                                  promoted_mode, 0);
+         schedule_fixup_var_refs (function, lopart, part_type, part_mode, 0);
+         schedule_fixup_var_refs (function, hipart, part_type, part_mode, 0);
+       }
     }
   else
     return;
-  
+
   if (current_function_check_memory_usage)
-    emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
-                      XEXP (reg, 0), Pmode,
+    emit_library_call (chkr_set_right_libfunc, LCT_CONST_MAKE_BLOCK, VOIDmode,
+                      3, XEXP (reg, 0), Pmode,
                       GEN_INT (GET_MODE_SIZE (GET_MODE (reg))),
                       TYPE_MODE (sizetype),
                       GEN_INT (MEMORY_USE_RW),
@@ -1496,14 +1504,30 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
      previously generated stack slot, then we need to copy the bit in
      case it was set for other reasons.  For instance, it is set for
      __builtin_va_alist.  */
-  MEM_SET_IN_STRUCT_P (reg,
-                      AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new));
-  MEM_ALIAS_SET (reg) = get_alias_set (type);
+  if (type)
+    {
+      MEM_SET_IN_STRUCT_P (reg,
+                          AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new));
+      MEM_ALIAS_SET (reg) = get_alias_set (type);
+    }
+  if (used_p)
+    schedule_fixup_var_refs (function, reg, type, promoted_mode, ht);
+}
 
-  /* Now make sure that all refs to the variable, previously made
-     when it was a register, are fixed up to be valid again.  */
+/* Make sure that all refs to the variable, previously made
+   when it was a register, are fixed up to be valid again.
+   See function above for meaning of arguments.  */
+static void
+schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
+     struct function *function;
+     rtx reg;
+     tree type;
+     enum machine_mode promoted_mode;
+     struct hash_table *ht;
+{
+  int unsigned_p = type ? TREE_UNSIGNED (type) : 0;
 
-  if (used_p && function != 0)
+  if (function != 0)
     {
       struct var_refs_queue *temp;
 
@@ -1511,13 +1535,13 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
        = (struct var_refs_queue *) xmalloc (sizeof (struct var_refs_queue));
       temp->modified = reg;
       temp->promoted_mode = promoted_mode;
-      temp->unsignedp = TREE_UNSIGNED (type);
+      temp->unsignedp = unsigned_p;
       temp->next = function->fixup_var_refs_queue;
       function->fixup_var_refs_queue = temp;
     }
-  else if (used_p)
+  else
     /* Variable is local; fix it up now.  */
-    fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type), ht);
+    fixup_var_refs (reg, promoted_mode, unsigned_p, ht);
 }
 \f
 static void
@@ -1534,7 +1558,7 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
   rtx insn;
 
   /* Must scan all insns for stack-refs that exceed the limit.  */
-  fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn, 
+  fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn,
                        stack == 0, ht);
   /* If there's a hash table, it must record all uses of VAR.  */
   if (ht)
@@ -1559,16 +1583,14 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
       if (seq != const0_rtx && seq != 0)
        {
          push_to_sequence (seq);
-         fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0,
-                               0);
+         fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0, 0);
          end_sequence ();
        }
     }
 
   /* Scan the catch clauses for exception handling too.  */
   push_to_full_sequence (catch_clauses, catch_clauses_last);
-  fixup_var_refs_insns (var, promoted_mode, unsignedp, catch_clauses,
-                       0, 0);
+  fixup_var_refs_insns (var, promoted_mode, unsignedp, catch_clauses, 0, 0);
   end_full_sequence (&catch_clauses, &catch_clauses_last);
 
   /* Scan sequences saved in CALL_PLACEHOLDERS too.  */
@@ -1644,7 +1666,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
      to walk the entire instruction chain.  */
   if (ht)
     {
-      insn_list = ((struct insns_for_mem_entry *) 
+      insn_list = ((struct insns_for_mem_entry *)
                   hash_lookup (ht, var, /*create=*/0, /*copy=*/0))->insns;
       insn = insn_list ? XEXP (insn_list, 0) : NULL_RTX;
       insn_list = XEXP (insn_list, 1);
@@ -1656,7 +1678,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
       rtx set, prev, prev_set;
       rtx note;
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      if (INSN_P (insn))
        {
          /* Remember the notes in case we delete the insn.  */
          note = REG_NOTES (insn);
@@ -1665,7 +1687,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
 
             If it has a REG_LIBCALL note, delete the REG_LIBCALL
             and REG_RETVAL notes too.  */
-         if (GET_CODE (PATTERN (insn)) == CLOBBER
+         if (GET_CODE (PATTERN (insn)) == CLOBBER
              && (XEXP (PATTERN (insn), 0) == var
                  || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
                      && (XEXP (XEXP (PATTERN (insn), 0), 0) == var
@@ -1743,7 +1765,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
                      PATTERN (insn) = replace_rtx (PATTERN (insn),
                                                    call_dest, temp);
                    }
-             
+
                  if (GET_CODE (insn) == CALL_INSN
                      && GET_CODE (PATTERN (insn)) == SET)
                    call_dest = SET_DEST (PATTERN (insn));
@@ -1762,7 +1784,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
                 a list of struct fixup_replacements.  If fixup_var_refs_1
                 needs to allocate pseudos or replacement MEMs (for SUBREGs),
                 it will record them in this list.
-                
+
                 If it allocated a pseudo for any replacement, we copy into
                 it here.  */
 
@@ -1824,7 +1846,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
              if (GET_CODE (note) != INSN_LIST)
                XEXP (note, 0)
                  = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
-              note = XEXP (note, 1);
+             note = XEXP (note, 1);
            }
        }
 
@@ -1841,7 +1863,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
 }
 \f
 /* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE.
-   See if the rtx expression at *LOC in INSN needs to be changed.  
+   See if the rtx expression at *LOC in INSN needs to be changed.
 
    REPLACEMENTS is a pointer to a list head that starts out zero, but may
    contain a list of original rtx's and replacements. If we find that we need
@@ -1919,7 +1941,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
     case MEM:
       if (var == x)
        {
-         /* If we already have a replacement, use it.  Otherwise, 
+         /* If we already have a replacement, use it.  Otherwise,
             try to fix up this address in case it is invalid.  */
 
          replacement = find_fixup_replacement (replacements, var);
@@ -1933,7 +1955,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
          /* Unless we are forcing memory to register or we changed the mode,
             we can leave things the way they are if the insn is valid.  */
-            
+
          INSN_CODE (insn) = -1;
          if (! flag_force_mem && GET_MODE (x) == promoted_mode
              && recog_memoized (insn) >= 0)
@@ -1955,6 +1977,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            replacement->new = copy_most_rtx (x, var);
 
          *loc = x = replacement->new;
+         code = GET_CODE (x);
        }
       break;
 
@@ -2071,7 +2094,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          return;
        }
       break;
-             
+
     case SUBREG:
       if (SUBREG_REG (x) == var)
        {
@@ -2088,7 +2111,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            }
 
          /* If this SUBREG makes VAR wider, it has become a paradoxical
-            SUBREG with VAR in memory, but these aren't allowed at this 
+            SUBREG with VAR in memory, but these aren't allowed at this
             stage of the compilation.  So load VAR into a pseudo and take
             a SUBREG of that pseudo.  */
          if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (var)))
@@ -2110,7 +2133,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
              *loc = replacement->new;
              return;
            }
-         
+
          replacement->new = *loc = fixup_memory_subreg (x, insn, 0);
 
          INSN_CODE (insn) = -1;
@@ -2160,7 +2183,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                           insn);
          break;
        }
-         
+
       {
        rtx dest = SET_DEST (x);
        rtx src = SET_SRC (x);
@@ -2179,7 +2202,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
        /* If VAR does not appear at the top level of the SET
           just scan the lower levels of the tree.  */
 
-        if (src != var && dest != var)
+       if (src != var && dest != var)
          break;
 
        /* We will need to rerecognize this insn.  */
@@ -2243,10 +2266,10 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                    INSN_CODE (insn) = -1;
                    XEXP (outerdest, 0) = newmem;
                    XEXP (outerdest, 2) = GEN_INT (pos);
-                   
+
                    if (recog_memoized (insn) >= 0)
                      return;
-                   
+
                    /* Otherwise, restore old position.  XEXP (x, 0) will be
                       restored later.  */
                    XEXP (outerdest, 2) = old_pos;
@@ -2311,7 +2334,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
               copy SET_SRC (x) to SET_DEST (x) in some way.  So
               we generate the move and see whether it requires more
               than one insn.  If it does, we emit those insns and
-              delete INSN.  Otherwise, we an just replace the pattern 
+              delete INSN.  Otherwise, we an just replace the pattern
               of INSN; we have already verified above that INSN has
               no other function that to do X.  */
 
@@ -2463,7 +2486,7 @@ fixup_memory_subreg (x, insn, uncritical)
    If X itself is a (SUBREG (MEM ...) ...), return the replacement expression.
    Otherwise return X, with its contents possibly altered.
 
-   If any insns must be emitted to compute NEWADDR, put them before INSN. 
+   If any insns must be emitted to compute NEWADDR, put them before INSN.
 
    UNCRITICAL is as in fixup_memory_subreg.  */
 
@@ -2755,7 +2778,7 @@ static int cfa_offset;
 /* The bottom of the stack points to the actual arguments.  If
    REG_PARM_STACK_SPACE is defined, this includes the space for the register
    parameters.  However, if OUTGOING_REG_PARM_STACK space is not defined,
-   stack space for register parameters is not pushed by the caller, but 
+   stack space for register parameters is not pushed by the caller, but
    rather part of the fixed stack areas and hence not included in
    `current_function_outgoing_args_size'.  Nevertheless, we must allow
    for it when allocating stack dynamic objects.  */
@@ -2779,7 +2802,6 @@ static int cfa_offset;
 #define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL)
 #endif
 
-
 /* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just had
    its address taken.  DECL is the decl for the object stored in the
    register, for later use if we do need to force REG into the stack.
@@ -2790,7 +2812,6 @@ gen_mem_addressof (reg, decl)
      rtx reg;
      tree decl;
 {
-  tree type = TREE_TYPE (decl);
   rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)),
                             REGNO (reg), decl);
 
@@ -2800,14 +2821,26 @@ gen_mem_addressof (reg, decl)
   RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
 
   PUT_CODE (reg, MEM);
-  PUT_MODE (reg, DECL_MODE (decl));
   XEXP (reg, 0) = r;
-  MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
-  MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (type));
-  MEM_ALIAS_SET (reg) = get_alias_set (decl);
+  if (decl)
+    {
+      tree type = TREE_TYPE (decl);
 
-  if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
-    fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), 0);
+      PUT_MODE (reg, DECL_MODE (decl));
+      MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
+      MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (type));
+      MEM_ALIAS_SET (reg) = get_alias_set (decl);
+
+      if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
+       fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), 0);
+    }
+  else
+    {
+      /* We have no alias information about this newly created MEM.  */
+      MEM_ALIAS_SET (reg) = 0;
+
+      fixup_var_refs (reg, GET_MODE (reg), 0, 0);
+    }
 
   return reg;
 }
@@ -2833,16 +2866,33 @@ put_addressof_into_stack (r, ht)
      rtx r;
      struct hash_table *ht;
 {
-  tree decl = ADDRESSOF_DECL (r);
+  tree decl, type;
+  int volatile_p, used_p;
+
   rtx reg = XEXP (r, 0);
 
   if (GET_CODE (reg) != REG)
     abort ();
 
-  put_reg_into_stack (0, reg, TREE_TYPE (decl), GET_MODE (reg),
-                     DECL_MODE (decl), TREE_SIDE_EFFECTS (decl),
-                     ADDRESSOF_REGNO (r),
-                     TREE_USED (decl) || DECL_INITIAL (decl) != 0, ht);
+  decl = ADDRESSOF_DECL (r);
+  if (decl)
+    {
+      type = TREE_TYPE (decl);
+      volatile_p = (TREE_CODE (decl) != SAVE_EXPR
+                   && TREE_THIS_VOLATILE (decl));
+      used_p = (TREE_USED (decl)
+               || (TREE_CODE (decl) != SAVE_EXPR
+                   && DECL_INITIAL (decl) != 0));
+    }
+  else
+    {
+      type = NULL_TREE;
+      volatile_p = 0;
+      used_p = 1;
+    }
+
+  put_reg_into_stack (0, reg, type, GET_MODE (reg), GET_MODE (reg),
+                     volatile_p, ADDRESSOF_REGNO (r), used_p, ht);
 }
 
 /* List of replacements made below in purge_addressof_1 when creating
@@ -2854,7 +2904,7 @@ static rtx purge_bitfield_addressof_replacements;
    corresponding (ADDRESSOF (REG ...)) and value is a substitution for
    the all pattern.  List PURGE_BITFIELD_ADDRESSOF_REPLACEMENTS is not
    enough in complex cases, e.g. when some field values can be
-   extracted by usage MEM with narrower mode. */
+   extracted by usage MEM with narrower mode.  */
 static rtx purge_addressof_replacements;
 
 /* Helper function for purge_addressof.  See if the rtx expression at *LOC
@@ -2904,7 +2954,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
       if (validate_change (insn, loc, sub, 0)
          || validate_replace_rtx (x, sub, insn))
        return true;
-  
+
       start_sequence ();
       sub = force_operand (sub, NULL_RTX);
       if (! validate_change (insn, loc, sub, 0)
@@ -2951,7 +3001,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
                    return true;
                  }
 
-             /* See comment for purge_addressof_replacements. */
+             /* See comment for purge_addressof_replacements.  */
              for (tem = purge_addressof_replacements;
                   tem != NULL_RTX;
                   tem = XEXP (XEXP (tem, 1), 1))
@@ -2967,17 +3017,17 @@ purge_addressof_1 (loc, insn, force, store, ht)
                    /* It can happen that the note may speak of things
                       in a wider (or just different) mode than the
                       code did.  This is especially true of
-                      REG_RETVAL. */
+                      REG_RETVAL.  */
 
                    if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0)
                      z = SUBREG_REG (z);
-                   
+
                    if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
                        && (GET_MODE_SIZE (GET_MODE (x))
                            > GET_MODE_SIZE (GET_MODE (z))))
                      {
                        /* This can occur as a result in invalid
-                          pointer casts, e.g. float f; ... 
+                          pointer casts, e.g. float f; ...
                           *(long long int *)&f.
                           ??? We could emit a warning here, but
                           without a line number that wouldn't be
@@ -3030,9 +3080,9 @@ purge_addressof_1 (loc, insn, force, store, ht)
                  seq = gen_sequence ();
                  end_sequence ();
                  emit_insn_before (seq, insn);
-                 compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (), 
+                 compute_insns_for_mem (p ? NEXT_INSN (p) : get_insns (),
                                         insn, ht);
-             
+
                  start_sequence ();
                  store_bit_field (sub, size_x, 0, GET_MODE (x),
                                   val, GET_MODE_SIZE (GET_MODE (sub)),
@@ -3046,7 +3096,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
                  end_sequence ();
                  p = emit_insn_after (seq, insn);
                  if (NEXT_INSN (insn))
-                   compute_insns_for_mem (NEXT_INSN (insn), 
+                   compute_insns_for_mem (NEXT_INSN (insn),
                                           p ? NEXT_INSN (p) : NULL_RTX,
                                           ht);
                }
@@ -3128,7 +3178,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
       return result;
     }
 
-  /* Scan all subexpressions. */
+  /* Scan all subexpressions.  */
   fmt = GET_RTX_FORMAT (code);
   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
     {
@@ -3204,7 +3254,7 @@ insns_for_mem_walk (r, data)
      rtx *r;
      void *data;
 {
-  struct insns_for_mem_walk_info *ifmwi 
+  struct insns_for_mem_walk_info *ifmwi
     = (struct insns_for_mem_walk_info *) data;
 
   if (ifmwi->pass == 0 && *r && GET_CODE (*r) == ADDRESSOF
@@ -3213,7 +3263,7 @@ insns_for_mem_walk (r, data)
   else if (ifmwi->pass == 1 && *r && GET_CODE (*r) == REG)
     {
       /* Lookup this MEM in the hashtable, creating it if necessary.  */
-      struct insns_for_mem_entry *ifme 
+      struct insns_for_mem_entry *ifme
        = (struct insns_for_mem_entry *) hash_lookup (ifmwi->ht,
                                                      *r,
                                                      /*create=*/0,
@@ -3228,7 +3278,7 @@ insns_for_mem_walk (r, data)
             the hash table since this memory will not be used once
             the hash table is deallocated.  */
          push_obstacks (&ifmwi->ht->memory, &ifmwi->ht->memory);
-         ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn, 
+         ifme->insns = gen_rtx_EXPR_LIST (VOIDmode, ifmwi->insn,
                                           ifme->insns);
          pop_obstacks ();
        }
@@ -3252,7 +3302,7 @@ compute_insns_for_mem (insns, last_insn, ht)
 
   for (ifmwi.pass = 0; ifmwi.pass < 2; ++ifmwi.pass)
     for (insn = insns; insn != last_insn; insn = NEXT_INSN (insn))
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      if (INSN_P (insn))
        {
          ifmwi.insn = insn;
          for_each_rtx (&insn, insns_for_mem_walk, &ifmwi);
@@ -3263,10 +3313,10 @@ compute_insns_for_mem (insns, last_insn, ht)
    Returns true iff the rtl is an ADDRESSOF.  */
 static int
 is_addressof (rtl, data)
-     rtx * rtl;
-     void * data ATTRIBUTE_UNUSED;
+     rtx *rtl;
+     void *data ATTRIBUTE_UNUSED;
 {
-  return GET_CODE (* rtl) == ADDRESSOF;
+  return GET_CODE (*rtl) == ADDRESSOF;
 }
 
 /* Eliminate all occurrences of ADDRESSOF from INSNS.  Elide any remaining
@@ -3279,7 +3329,7 @@ purge_addressof (insns)
 {
   rtx insn;
   struct hash_table ht;
-  
+
   /* When we actually purge ADDRESSOFs, we turn REGs into MEMs.  That
      requires a fixup pass over the instruction stream to correct
      INSNs that depended on the REG being a REG, and not a MEM.  But,
@@ -3287,7 +3337,7 @@ purge_addressof (insns)
      mentioned in very many instructions.  So, we speed up the process
      by pre-calculating which REGs occur in which INSNs; that allows
      us to perform the fixup passes much more quickly.  */
-  hash_table_init (&ht, 
+  hash_table_init (&ht,
                   insns_for_mem_newfunc,
                   insns_for_mem_hash,
                   insns_for_mem_comp);
@@ -3302,7 +3352,7 @@ purge_addressof (insns)
          /* If we could not replace the ADDRESSOFs in the insn,
             something is wrong.  */
          abort ();
-       
+
        if (! purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0, &ht))
          {
            /* If we could not replace the ADDRESSOFs in the insn's notes,
@@ -3317,7 +3367,7 @@ purge_addressof (insns)
                   safe to delete the notes here, and instead we abort.  */
                if (REG_NOTE_KIND (note) == REG_RETVAL)
                  abort ();
-               if (for_each_rtx (& note, is_addressof, NULL))
+               if (for_each_rtx (&note, is_addressof, NULL))
                  remove_note (insn, note);
              }
          }
@@ -3420,7 +3470,7 @@ instantiate_decls (fndecl, valid_only)
     {
       HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
 
-      instantiate_decl (DECL_RTL (decl), size, valid_only);    
+      instantiate_decl (DECL_RTL (decl), size, valid_only);
 
       /* If the parameter was promoted, then the incoming RTL mode may be
         larger than the declared type size.  We must use the larger of
@@ -3536,7 +3586,7 @@ instantiate_decl (x, size, valid_only)
    is not valid.
 
    Return 1 if we either had nothing to do or if we were able to do the
-   needed replacement.  Return 0 otherwise; we only return zero if 
+   needed replacement.  Return 0 otherwise; we only return zero if
    EXTRA_INSNS is zero.
 
    We first try some simple transformations to avoid the creation of extra
@@ -3588,15 +3638,15 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
         appropriate offset.  This is used, for example, in the handling
         of non-local gotos.  */
       if (SET_DEST (x) == virtual_incoming_args_rtx)
-       new = arg_pointer_rtx, offset = - in_arg_offset;
+       new = arg_pointer_rtx, offset = -in_arg_offset;
       else if (SET_DEST (x) == virtual_stack_vars_rtx)
-       new = frame_pointer_rtx, offset = - var_offset;
+       new = frame_pointer_rtx, offset = -var_offset;
       else if (SET_DEST (x) == virtual_stack_dynamic_rtx)
-       new = stack_pointer_rtx, offset = - dynamic_offset;
+       new = stack_pointer_rtx, offset = -dynamic_offset;
       else if (SET_DEST (x) == virtual_outgoing_args_rtx)
-       new = stack_pointer_rtx, offset = - out_arg_offset;
+       new = stack_pointer_rtx, offset = -out_arg_offset;
       else if (SET_DEST (x) == virtual_cfa_rtx)
-       new = arg_pointer_rtx, offset = - cfa_offset;
+       new = arg_pointer_rtx, offset = -cfa_offset;
 
       if (new)
        {
@@ -3652,7 +3702,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
              else if (inner == virtual_outgoing_args_rtx)
                new = stack_pointer_rtx, offset = out_arg_offset;
              else if (inner == virtual_cfa_rtx)
-               new = arg_pointer_rtx, offset = cfa_offset;
+               new = arg_pointer_rtx, offset = cfa_offset;
              else
                {
                  loc = &XEXP (x, 0);
@@ -3672,8 +3722,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
            new = stack_pointer_rtx, offset = dynamic_offset;
          else if (XEXP (x, 0) == virtual_outgoing_args_rtx)
            new = stack_pointer_rtx, offset = out_arg_offset;
-          else if (XEXP (x, 0) == virtual_cfa_rtx)
-            new = arg_pointer_rtx, offset = cfa_offset;
+         else if (XEXP (x, 0) == virtual_cfa_rtx)
+           new = arg_pointer_rtx, offset = cfa_offset;
          else
            {
              /* We know the second operand is a constant.  Unless the
@@ -3766,12 +3816,12 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
       /* Most cases of MEM that convert to valid addresses have already been
         handled by our scan of decls.  The only special handling we
         need here is to make a copy of the rtx to ensure it isn't being
-        shared if we have to change it to a pseudo. 
+        shared if we have to change it to a pseudo.
 
         If the rtx is a simple reference to an address via a virtual register,
         it can potentially be shared.  In such cases, first try to make it
         a valid address, which can also be shared.  Otherwise, copy it and
-        proceed normally. 
+        proceed normally.
 
         First check for common cases that need no processing.  These are
         usually due to instantiation already being done on a previous instance
@@ -3857,7 +3907,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
     case CLOBBER:
       /* If the operand is a MEM, see if the change is a valid MEM.  If not,
         go ahead and make the invalid one, but do it to a copy.  For a REG,
-        just make the recursive call, since there's no chance of a problem. */
+        just make the recursive call, since there's no chance of a problem.  */
 
       if ((GET_CODE (XEXP (x, 0)) == MEM
           && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
@@ -3882,7 +3932,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
       else if (x == virtual_outgoing_args_rtx)
        new = stack_pointer_rtx, offset = out_arg_offset;
       else if (x == virtual_cfa_rtx)
-        new = arg_pointer_rtx, offset = cfa_offset;
+       new = arg_pointer_rtx, offset = cfa_offset;
 
       if (new)
        {
@@ -3919,7 +3969,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
          return 1;
        }
       break;
-      
+
     default:
       break;
     }
@@ -4091,7 +4141,7 @@ assign_parms (fndecl)
   tree fnargs = DECL_ARGUMENTS (fndecl);
   /* This is used for the arg pointer when referring to stack args.  */
   rtx internal_arg_pointer;
-  /* This is a dummy PARM_DECL that we used for the function result if 
+  /* This is a dummy PARM_DECL that we used for the function result if
      the function returns a structure.  */
   tree function_result_decl = 0;
 #ifdef SETUP_INCOMING_VARARGS
@@ -4152,7 +4202,7 @@ assign_parms (fndecl)
       TREE_CHAIN (function_result_decl) = fnargs;
       fnargs = function_result_decl;
     }
-                              
+
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
   parm_reg_stack_loc = (rtx *) xcalloc (max_parm_reg, sizeof (rtx));
 
@@ -4168,7 +4218,6 @@ assign_parms (fndecl)
 
   for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
     {
-      int aggregate = AGGREGATE_TYPE_P (TREE_TYPE (parm));
       struct args_size stack_offset;
       struct args_size arg_size;
       int passed_pointer = 0;
@@ -4221,7 +4270,8 @@ assign_parms (fndecl)
         type of the first field for the tests below.  We have already
         verified that the modes are the same.  */
       if (DECL_TRANSPARENT_UNION (parm)
-         || TYPE_TRANSPARENT_UNION (passed_type))
+         || (TREE_CODE (passed_type) == UNION_TYPE
+             && TYPE_TRANSPARENT_UNION (passed_type)))
        passed_type = TREE_TYPE (TYPE_FIELDS (passed_type));
 
       /* See if this arg was passed by invisible reference.  It is if
@@ -4312,7 +4362,7 @@ assign_parms (fndecl)
 #endif
 #endif
                           fndecl, &stack_args_size, &stack_offset, &arg_size,
-                           &alignment_pad);
+                          &alignment_pad);
 
       {
        rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
@@ -4325,12 +4375,7 @@ assign_parms (fndecl)
                                                  internal_arg_pointer,
                                                  offset_rtx));
 
-       /* If this is a memory ref that contains aggregate components,
-          mark it as such for cse and loop optimize.  Likewise if it
-          is readonly.  */
-       MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
-       RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
-       MEM_ALIAS_SET (stack_parm) = get_alias_set (parm);
+       set_mem_attributes (stack_parm, parm, 1);
       }
 
       /* If this parameter was passed both in registers and in the stack,
@@ -4365,7 +4410,7 @@ assign_parms (fndecl)
                emit_group_store (validize_mem (stack_parm), entry_parm,
                                  int_size_in_bytes (TREE_TYPE (parm)),
                                  TYPE_ALIGN (TREE_TYPE (parm)));
-                                 
+
              else
                move_block_from_reg (REGNO (entry_parm),
                                     validize_mem (stack_parm), nregs,
@@ -4435,38 +4480,6 @@ assign_parms (fndecl)
          && nominal_mode != BLKmode && nominal_mode != passed_mode)
        stack_parm = 0;
 
-#if 0
-      /* Now adjust STACK_PARM to the mode and precise location
-        where this parameter should live during execution,
-        if we discover that it must live in the stack during execution.
-        To make debuggers happier on big-endian machines, we store
-        the value in the last bytes of the space available.  */
-
-      if (nominal_mode != BLKmode && nominal_mode != passed_mode
-         && stack_parm != 0)
-       {
-         rtx offset_rtx;
-
-         if (BYTES_BIG_ENDIAN
-             && GET_MODE_SIZE (nominal_mode) < UNITS_PER_WORD)
-           stack_offset.constant += (GET_MODE_SIZE (passed_mode)
-                                     - GET_MODE_SIZE (nominal_mode));
-
-         offset_rtx = ARGS_SIZE_RTX (stack_offset);
-         if (offset_rtx == const0_rtx)
-           stack_parm = gen_rtx_MEM (nominal_mode, internal_arg_pointer);
-         else
-           stack_parm = gen_rtx_MEM (nominal_mode,
-                                     gen_rtx_PLUS (Pmode,
-                                                   internal_arg_pointer,
-                                                   offset_rtx));
-
-         /* If this is a memory ref that contains aggregate components,
-            mark it as such for cse and loop optimize.  */
-         MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
-       }
-#endif /* 0 */
-
       /* ENTRY_PARM is an RTX for the parameter as it arrives,
         in the mode in which it arrives.
         STACK_PARM is an RTX for a stack slot where the parameter can live
@@ -4506,18 +4519,12 @@ assign_parms (fndecl)
                  stack_parm
                    = assign_stack_local (GET_MODE (entry_parm),
                                          size_stored, 0);
-
-                 /* If this is a memory ref that contains aggregate
-                    components, mark it as such for cse and loop optimize.  */
-                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
+                 set_mem_attributes (stack_parm, parm, 1);
                }
 
              else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
                abort ();
 
-             if (TREE_READONLY (parm))
-               RTX_UNCHANGING_P (stack_parm) = 1;
-
              /* Handle calls that pass values in multiple non-contiguous
                 locations.  The Irix 6 ABI has examples of this.  */
              if (GET_CODE (entry_parm) == PARALLEL)
@@ -4566,7 +4573,7 @@ assign_parms (fndecl)
            {
              DECL_RTL (parm)
                = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
-             MEM_SET_IN_STRUCT_P (DECL_RTL (parm), aggregate);
+             set_mem_attributes (DECL_RTL (parm), parm, 1);
            }
          else
            DECL_RTL (parm) = parmreg;
@@ -4577,7 +4584,7 @@ assign_parms (fndecl)
            {
              int save_tree_used;
              /* ENTRY_PARM has been converted to PROMOTED_MODE, its
-                mode, by the caller.  We now have to convert it to 
+                mode, by the caller.  We now have to convert it to
                 NOMINAL_MODE, if different.  However, PARMREG may be in
                 a different mode than NOMINAL_MODE if it is being stored
                 promoted.
@@ -4672,13 +4679,13 @@ assign_parms (fndecl)
              else
                copy = assign_stack_temp (TYPE_MODE (type),
                                          int_size_in_bytes (type), 1);
-             MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
-             RTX_UNCHANGING_P (copy) = TREE_READONLY (parm);
+             set_mem_attributes (copy, parm, 1);
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
              if (current_function_check_memory_usage)
-               emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+               emit_library_call (chkr_set_right_libfunc,
+                                  LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
                                   XEXP (copy, 0), Pmode,
                                   GEN_INT (int_size_in_bytes (type)),
                                   TYPE_MODE (sizetype),
@@ -4691,7 +4698,7 @@ assign_parms (fndecl)
 #endif /* FUNCTION_ARG_CALLEE_COPIES */
 
          /* In any case, record the parm's desired stack location
-            in case we later discover it must live in the stack. 
+            in case we later discover it must live in the stack.
 
             If it is a COMPLEX value, store the stack location for both
             halves.  */
@@ -4780,7 +4787,7 @@ assign_parms (fndecl)
                  }
              else if ((set = single_set (linsn)) != 0
                       && SET_DEST (set) == parmreg)
-               REG_NOTES (linsn)
+               REG_NOTES (linsn)
                  = gen_rtx_EXPR_LIST (REG_EQUIV,
                                       stack_parm, REG_NOTES (linsn));
            }
@@ -4824,9 +4831,7 @@ assign_parms (fndecl)
                  stack_parm
                    = assign_stack_local (GET_MODE (entry_parm),
                                          GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
-                 /* If this is a memory ref that contains aggregate components,
-                    mark it as such for cse and loop optimize.  */
-                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
+                 set_mem_attributes (stack_parm, parm, 1);
                }
 
              if (promoted_mode != nominal_mode)
@@ -4844,9 +4849,9 @@ assign_parms (fndecl)
          if (current_function_check_memory_usage)
            {
              push_to_sequence (conversion_insns);
-             emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
-                                XEXP (stack_parm, 0), Pmode,
-                                GEN_INT (GET_MODE_SIZE (GET_MODE 
+             emit_library_call (chkr_set_right_libfunc, LCT_CONST_MAKE_BLOCK,
+                                VOIDmode, 3, XEXP (stack_parm, 0), Pmode,
+                                GEN_INT (GET_MODE_SIZE (GET_MODE
                                                         (entry_parm))),
                                 TYPE_MODE (sizetype),
                                 GEN_INT (MEMORY_USE_RW),
@@ -4857,25 +4862,18 @@ assign_parms (fndecl)
            }
          DECL_RTL (parm) = stack_parm;
        }
-      
+
       /* If this "parameter" was the place where we are receiving the
         function's incoming structure pointer, set up the result.  */
       if (parm == function_result_decl)
        {
          tree result = DECL_RESULT (fndecl);
-         tree restype = TREE_TYPE (result);
 
          DECL_RTL (result)
            = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
 
-         MEM_SET_IN_STRUCT_P (DECL_RTL (result), 
-                              AGGREGATE_TYPE_P (restype));
+         set_mem_attributes (DECL_RTL (result), result, 1);
        }
-
-      if (TREE_THIS_VOLATILE (parm))
-       MEM_VOLATILE_P (DECL_RTL (parm)) = 1;
-      if (TREE_READONLY (parm))
-       RTX_UNCHANGING_P (DECL_RTL (parm)) = 1;
     }
 
   /* Output all parameter conversion instructions (possibly including calls)
@@ -4902,13 +4900,13 @@ assign_parms (fndecl)
   current_function_args_size
     = ((current_function_args_size + STACK_BYTES - 1)
        / STACK_BYTES) * STACK_BYTES;
-#endif  
+#endif
 
 #ifdef ARGS_GROW_DOWNWARD
   current_function_arg_offset_rtx
     = (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
-       : expand_expr (size_diffop (stack_args_size.var,        
-                                  size_int (-stack_args_size.constant)),   
+       : expand_expr (size_diffop (stack_args_size.var,
+                                  size_int (-stack_args_size.constant)),
                      NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD));
 #else
   current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
@@ -4998,7 +4996,7 @@ promoted_input_arg (regno, pmode, punsignedp)
    initial offset is not affected by this rounding, while the size always
    is and the starting offset may be.  */
 
-/*  offset_ptr will be negative for ARGS_GROW_DOWNWARD case; 
+/*  offset_ptr will be negative for ARGS_GROW_DOWNWARD case;
     initial_offset_ptr is positive because locate_and_pad_parm's
     callers pass in the total size of args so far as
     initial_offset_ptr. arg_size_ptr is always positive.*/
@@ -5006,7 +5004,7 @@ promoted_input_arg (regno, pmode, punsignedp)
 void
 locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
                     initial_offset_ptr, offset_ptr, arg_size_ptr,
-                     alignment_pad)
+                    alignment_pad)
      enum machine_mode passed_mode;
      tree type;
      int in_regs ATTRIBUTE_UNUSED;
@@ -5061,7 +5059,7 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     }
   else
     {
-      offset_ptr->constant = - initial_offset_ptr->constant;
+      offset_ptr->constant = -initial_offset_ptr->constant;
       offset_ptr->var = 0;
     }
   if (where_pad != none
@@ -5079,8 +5077,8 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
                                    offset_ptr->var);
 
   else
-    arg_size_ptr->constant = (- initial_offset_ptr->constant
-                             - offset_ptr->constant); 
+    arg_size_ptr->constant = (-initial_offset_ptr->constant
+                             - offset_ptr->constant);
 
 #else /* !ARGS_GROW_DOWNWARD */
   pad_to_arg_alignment (initial_offset_ptr, boundary, alignment_pad);
@@ -5121,7 +5119,7 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
   HOST_WIDE_INT save_constant = 0;
 
   int boundary_in_bytes = boundary / BITS_PER_UNIT;
-  
+
   if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
     {
       save_var = offset_ptr->var;
@@ -5135,9 +5133,9 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
     {
       if (offset_ptr->var)
        {
-         offset_ptr->var  =
+         offset_ptr->var =
 #ifdef ARGS_GROW_DOWNWARD
-           round_down 
+           round_down
 #else
            round_up
 #endif
@@ -5149,16 +5147,16 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
                                             save_var);
        }
       else
-        {
+       {
          offset_ptr->constant =
 #ifdef ARGS_GROW_DOWNWARD
            FLOOR_ROUND (offset_ptr->constant, boundary_in_bytes);
 #else
            CEIL_ROUND (offset_ptr->constant, boundary_in_bytes);
 #endif
-          if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
-            alignment_pad->constant = offset_ptr->constant - save_constant;
-        }
+           if (boundary > PARM_BOUNDARY && boundary > STACK_BOUNDARY)
+             alignment_pad->constant = offset_ptr->constant - save_constant;
+       }
     }
 }
 
@@ -5248,7 +5246,8 @@ setjmp_args_warning ()
     if (DECL_RTL (decl) != 0
        && GET_CODE (DECL_RTL (decl)) == REG
        && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl))))
-      warning_with_decl (decl, "argument `%s' might be clobbered by `longjmp' or `vfork'");
+      warning_with_decl (decl,
+                        "argument `%s' might be clobbered by `longjmp' or `vfork'");
 }
 
 /* If this function call setjmp, put all vars into the stack
@@ -5398,7 +5397,9 @@ fix_lexical_addr (addr, var)
       addr = fix_lexical_addr (XEXP (fp->x_arg_pointer_save_area, 0), var);
       addr = memory_address (Pmode, addr);
 
-      base = copy_to_reg (gen_rtx_MEM (Pmode, addr));
+      base = gen_rtx_MEM (Pmode, addr);
+      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);
@@ -5526,7 +5527,7 @@ round_trampoline_addr (tramp)
                       GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1),
                       temp, 0, OPTAB_LIB_WIDEN);
   tramp = expand_binop (Pmode, and_optab, temp,
-                       GEN_INT (- TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT),
+                       GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT),
                        temp, 0, OPTAB_LIB_WIDEN);
 #endif
   return tramp;
@@ -5555,9 +5556,9 @@ identify_blocks ()
   block_vector = get_block_vector (block, &n_blocks);
   block_stack = (tree *) xmalloc (n_blocks * sizeof (tree));
 
-  last_block_vector = identify_blocks_1 (get_insns (), 
+  last_block_vector = identify_blocks_1 (get_insns (),
                                         block_vector + 1,
-                                        block_vector + n_blocks, 
+                                        block_vector + n_blocks,
                                         block_stack);
 
   /* If we didn't use all of the subblocks, we've misplaced block notes.  */
@@ -5611,14 +5612,14 @@ identify_blocks_1 (insns, block_vector, end_block_vector, orig_block_stack)
 
              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);
+         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);
@@ -5637,7 +5638,7 @@ identify_blocks_1 (insns, block_vector, end_block_vector, orig_block_stack)
 }
 
 /* Identify BLOCKs referenced by more than one
-   NOTE_INSN_BLOCK_{BEG,END}, and create duplicate blocks. */
+   NOTE_INSN_BLOCK_{BEG,END}, and create duplicate blocks.  */
 
 void
 reorder_blocks ()
@@ -5656,8 +5657,7 @@ reorder_blocks ()
 
   reorder_blocks_1 (get_insns (), block, &block_stack);
 
-  BLOCK_SUBBLOCKS (block)
-    = blocks_nreverse (BLOCK_SUBBLOCKS (block));
+  BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block));
 
   VARRAY_FREE (block_stack);
 }
@@ -5688,7 +5688,7 @@ reorder_blocks_1 (insns, current_block, p_block_stack)
                }
              BLOCK_SUBBLOCKS (block) = 0;
              TREE_ASM_WRITTEN (block) = 1;
-             BLOCK_SUPERCONTEXT (block) = current_block; 
+             BLOCK_SUPERCONTEXT (block) = current_block;
              BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
              BLOCK_SUBBLOCKS (current_block) = block;
              current_block = block;
@@ -5754,7 +5754,7 @@ all_blocks (block, vector)
        vector[n_blocks] = block;
 
       ++n_blocks;
-      
+
       /* Record the subblocks, and their subblocks...  */
       n_blocks += all_blocks (BLOCK_SUBBLOCKS (block),
                              vector ? vector + n_blocks : 0);
@@ -5768,7 +5768,7 @@ all_blocks (block, vector)
    number of elements in the vector is stored in N_BLOCKS_P.  The
    vector is dynamically allocated; it is the caller's responsibility
    to call `free' on the pointer returned.  */
-  
+
 static tree *
 get_block_vector (block, n_blocks_p)
      tree block;
@@ -5814,7 +5814,6 @@ number_blocks (fn)
 
   return;
 }
-
 \f
 /* Allocate a function structure and reset its contents to the defaults.  */
 static void
@@ -5857,7 +5856,7 @@ prepare_function_start ()
   /* Initialize the queue of pending postincrement and postdecrements,
      and some other info in expr.c.  */
   init_expr ();
-  
+
   /* We haven't done register allocation yet.  */
   reg_renumber = 0;
 
@@ -5866,7 +5865,7 @@ prepare_function_start ()
   /* Clear out data used for inlining.  */
   cfun->inlinable = 0;
   cfun->original_decl_initial = 0;
-  cfun->original_arg_vector = 0;  
+  cfun->original_arg_vector = 0;
 
 #ifdef STACK_BOUNDARY
   cfun->stack_alignment_needed = STACK_BOUNDARY;
@@ -5923,6 +5922,9 @@ prepare_function_start ()
   /* Indicate that we have not instantiated virtual registers yet.  */
   virtuals_instantiated = 0;
 
+  /* Indicate that we want CONCATs now.  */
+  generating_concat_p = 1;
+
   /* Indicate we have no need of a frame pointer yet.  */
   frame_pointer_needed = 0;
 
@@ -5968,7 +5970,7 @@ init_function_start (subr, filename, line)
   /* Remember this function for later.  */
   cfun->next_global = all_functions;
   all_functions = cfun;
-  
+
   current_function_name = (*decl_printable_name) (subr, 2);
   cfun->decl = subr;
 
@@ -5983,7 +5985,7 @@ init_function_start (subr, filename, line)
 
   /* Prevent ever trying to delete the first instruction of a function.
      Also tell final how to output a linenum before the function prologue.
-     Note linenums could be missing, e.g. when compiling a Java .class file. */
+     Note linenums could be missing, e.g. when compiling a Java .class file.  */
   if (line > 0)
     emit_line_note (filename, line);
 
@@ -6091,7 +6093,7 @@ expand_function_start (subr, parms_have_cleanups)
         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);
+       emit_move_insn (last_ptr, static_chain_incoming_rtx);
     }
 
   /* If the parameters of this function need cleaning up, get a label
@@ -6149,10 +6151,8 @@ expand_function_start (subr, parms_have_cleanups)
        {
          DECL_RTL (DECL_RESULT (subr))
            = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
-         MEM_SET_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)),
-                              AGGREGATE_TYPE_P (TREE_TYPE
-                                                (DECL_RESULT
-                                                 (subr))));
+         set_mem_attributes (DECL_RTL (DECL_RESULT (subr)),
+                             DECL_RESULT (subr), 1);
        }
     }
   else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
@@ -6245,11 +6245,11 @@ expand_function_start (subr, parms_have_cleanups)
          /* 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, - GET_MODE_SIZE (Pmode));
+         last_ptr = plus_constant (last_ptr, -GET_MODE_SIZE (Pmode));
 #endif
-         last_ptr = copy_to_reg (gen_rtx_MEM (Pmode,
-                                              memory_address (Pmode,
-                                                              last_ptr)));
+         last_ptr = gen_rtx_MEM (Pmode, memory_address (Pmode, last_ptr));
+         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.  */
@@ -6319,14 +6319,25 @@ diddle_return_value (doit, arg)
      void *arg;
 {
   rtx outgoing = current_function_return_rtx;
+  int pcc;
 
   if (! outgoing)
     return;
 
-  if (GET_CODE (outgoing) == REG
-      && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
+  pcc = (current_function_returns_struct
+        || current_function_returns_pcc_struct);
+
+  if ((GET_CODE (outgoing) == REG
+       && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
+      || pcc)
     {
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
+
+      /* A PCC-style return returns a pointer to the memory in which
+        the structure is stored.  */
+      if (pcc)
+       type = build_pointer_type (type);
+
 #ifdef FUNCTION_OUTGOING_VALUE
       outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
 #else
@@ -6337,6 +6348,7 @@ diddle_return_value (doit, arg)
       if (GET_MODE (outgoing) == BLKmode)
        PUT_MODE (outgoing,
                  GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
+      REG_FUNCTION_VALUE_P (outgoing) = 1;
     }
 
   if (GET_CODE (outgoing) == REG)
@@ -6384,14 +6396,14 @@ use_return_register ()
 }
 
 /* Generate RTL for the end of the current function.
-   FILENAME and LINE are the current position in the source file. 
+   FILENAME and LINE are the current position in the source file.
 
    It is up to language-specific callers to do cleanups for parameters--
    or else, supply 1 for END_BINDINGS and we will call expand_end_bindings.  */
 
 void
 expand_function_end (filename, line, end_bindings)
-     char *filename;
+     const char *filename;
      int line;
      int end_bindings;
 {
@@ -6492,7 +6504,11 @@ expand_function_end (filename, line, end_bindings)
     }
 
   /* Warn about unused parms if extra warnings were specified.  */
-  if (warn_unused && extra_warnings)
+  /* Either ``-W -Wunused'' or ``-Wunused-parameter'' enables this
+     warning.  WARN_UNUSED_PARAMETER is negative when set by
+     -Wunused.  */
+  if (warn_unused_parameter > 0
+      || (warn_unused_parameter < 0 && extra_warnings))
     {
       tree decl;
 
@@ -6650,7 +6666,8 @@ expand_function_end (filename, line, end_bindings)
   if (current_function_returns_struct
       || current_function_returns_pcc_struct)
     {
-      rtx value_address = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+      rtx value_address =
+       XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
 #ifdef FUNCTION_OUTGOING_VALUE
       rtx outgoing
@@ -6675,7 +6692,7 @@ expand_function_end (filename, line, end_bindings)
      instead of using the general framework.  */
   use_return_register ();
 
-  /* If this is an implementation of __throw, do what's necessary to 
+  /* If this is an implementation of __throw, do what's necessary to
      communicate between __builtin_eh_return and the epilogue.  */
   expand_eh_return ();
 
@@ -6770,7 +6787,7 @@ prologue_epilogue_contains (insn)
 
 int
 sibcall_epilogue_contains (insn)
-      rtx insn;
+     rtx insn;
 {
   if (sibcall_epilogue)
     return contains (insn, sibcall_epilogue);
@@ -6782,24 +6799,91 @@ sibcall_epilogue_contains (insn)
    block_for_insn appropriately.  */
 
 static void
-emit_return_into_block (bb)
+emit_return_into_block (bb, line_note)
      basic_block bb;
+     rtx line_note;
 {
   rtx p, end;
 
+  p = NEXT_INSN (bb->end);
   end = emit_jump_insn_after (gen_return (), bb->end);
-  p = NEXT_INSN (bb->end); 
+  if (line_note)
+    emit_line_note_after (NOTE_SOURCE_FILE (line_note),
+                         NOTE_LINE_NUMBER (line_note), bb->end);
+
   while (1)
     {
       set_block_for_insn (p, bb);
-      if (p == end)
+      if (p == bb->end)
        break;
-      p = NEXT_INSN (p);
+      p = PREV_INSN (p);
     }
   bb->end = end;
 }
 #endif /* HAVE_return */
 
+#ifdef HAVE_epilogue
+
+/* Modify SEQ, a SEQUENCE that is part of the epilogue, to no modifications
+   to the stack pointer.  */
+
+static void
+keep_stack_depressed (seq)
+     rtx seq;
+{
+  int i;
+  rtx sp_from_reg = 0;
+  int sp_modified_unknown = 0;
+
+  /* If the epilogue is just a single instruction, it's OK as is */
+
+  if (GET_CODE (seq) != SEQUENCE) return;
+
+  /* Scan all insns in SEQ looking for ones that modified the stack
+     pointer.  Record if it modified the stack pointer by copying it
+     from the frame pointer or if it modified it in some other way.
+     Then modify any subsequent stack pointer references to take that
+     into account.  We start by only allowing SP to be copied from a
+     register (presumably FP) and then be subsequently referenced.  */
+
+  for (i = 0; i < XVECLEN (seq, 0); i++)
+    {
+      rtx insn = XVECEXP (seq, 0, i);
+
+      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       continue;
+
+      if (reg_set_p (stack_pointer_rtx, insn))
+       {
+         rtx set = single_set (insn);
+
+         /* If SP is set as a side-effect, we can't support this.  */
+         if (set == 0)
+           abort ();
+
+         if (GET_CODE (SET_SRC (set)) == REG)
+           sp_from_reg = SET_SRC (set);
+         else
+           sp_modified_unknown = 1;
+
+         /* Don't allow the SP modification to happen.  */
+         PUT_CODE (insn, NOTE);
+         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+         NOTE_SOURCE_FILE (insn) = 0;
+       }
+      else if (reg_referenced_p (stack_pointer_rtx, PATTERN (insn)))
+       {
+         if (sp_modified_unknown)
+           abort ();
+
+         else if (sp_from_reg != 0)
+           PATTERN (insn)
+             = replace_rtx (PATTERN (insn), stack_pointer_rtx, sp_from_reg);
+       }
+    }
+}
+#endif
+
 /* Generate the prologue and epilogue RTL if the machine supports it.  Thread
    this into place with notes indicating where the prologue ends and where
    the epilogue begins.  Update the basic block information when possible.  */
@@ -6808,43 +6892,28 @@ void
 thread_prologue_and_epilogue_insns (f)
      rtx f ATTRIBUTE_UNUSED;
 {
-  int insertted = 0;
+  int inserted = 0;
   edge e;
   rtx seq;
+#ifdef HAVE_prologue
+  rtx prologue_end = NULL_RTX;
+#endif
+#if defined (HAVE_epilogue) || defined(HAVE_return)
+  rtx epilogue_end = NULL_RTX;
+#endif
 
 #ifdef HAVE_prologue
   if (HAVE_prologue)
     {
-      rtx insn;
-
       start_sequence ();
-      seq = gen_prologue();
+      seq = gen_prologue ();
       emit_insn (seq);
 
       /* Retain a map of the prologue insns.  */
       if (GET_CODE (seq) != SEQUENCE)
        seq = get_insns ();
       record_insns (seq, &prologue);
-      emit_note (NULL, NOTE_INSN_PROLOGUE_END);
-
-      /* GDB handles `break f' by setting a breakpoint on the first
-        line note *after* the prologue.  That means that we should
-        insert a line note here; otherwise, if the next line note
-        comes part way into the next block, GDB will skip all the way
-        to that point.  */
-      insn = next_nonnote_insn (f);
-      while (insn)
-       {
-         if (GET_CODE (insn) == NOTE 
-             && NOTE_LINE_NUMBER (insn) >= 0)
-           {
-             emit_line_note_force (NOTE_SOURCE_FILE (insn),
-                                   NOTE_LINE_NUMBER (insn));
-             break;
-           }
-
-         insn = PREV_INSN (insn);
-       }
+      prologue_end = emit_note (NULL, NOTE_INSN_PROLOGUE_END);
 
       seq = gen_sequence ();
       end_sequence ();
@@ -6858,7 +6927,7 @@ thread_prologue_and_epilogue_insns (f)
            abort ();
 
          insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
-         insertted = 1;
+         inserted = 1;
        }
       else
        emit_insn_after (seq, f);
@@ -6867,7 +6936,7 @@ thread_prologue_and_epilogue_insns (f)
 
   /* If the exit block has no non-fake predecessors, we don't need
      an epilogue.  */
-  for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
     if ((e->flags & EDGE_FAKE) == 0)
       break;
   if (e == NULL)
@@ -6878,15 +6947,15 @@ thread_prologue_and_epilogue_insns (f)
     {
       /* If we're allowed to generate a simple return instruction,
         then by definition we don't need a full epilogue.  Examine
-        the block that falls through to EXIT.   If it does not 
-        contain any code, examine its predecessors and try to 
+        the block that falls through to EXIT.   If it does not
+        contain any code, examine its predecessors and try to
         emit (conditional) return instructions.  */
 
       basic_block last;
       edge e_next;
       rtx label;
 
-      for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+      for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
        if (e->flags & EDGE_FALLTHRU)
          break;
       if (e == NULL)
@@ -6904,7 +6973,20 @@ thread_prologue_and_epilogue_insns (f)
 
       if (last->head == label && GET_CODE (label) == CODE_LABEL)
        {
-         for (e = last->pred; e ; e = e_next)
+         rtx epilogue_line_note = NULL_RTX;
+
+         /* Locate the line number associated with the closing brace,
+            if we can find one.  */
+         for (seq = get_last_insn ();
+              seq && ! active_insn_p (seq);
+              seq = PREV_INSN (seq))
+           if (GET_CODE (seq) == NOTE && NOTE_LINE_NUMBER (seq) > 0)
+             {
+               epilogue_line_note = seq;
+               break;
+             }
+
+         for (e = last->pred; e; e = e_next)
            {
              basic_block bb = e->src;
              rtx jump;
@@ -6921,7 +7003,7 @@ thread_prologue_and_epilogue_insns (f)
                 with a simple return instruction.  */
              if (simplejump_p (jump))
                {
-                 emit_return_into_block (bb);
+                 emit_return_into_block (bb, epilogue_line_note);
                  flow_delete_insn (jump);
                }
 
@@ -6942,40 +7024,28 @@ thread_prologue_and_epilogue_insns (f)
                    continue;
                  if (JUMP_LABEL (jump))
                    LABEL_NUSES (JUMP_LABEL (jump))--;
-                                 
+
                  /* If this block has only one successor, it both jumps
                     and falls through to the fallthru block, so we can't
                     delete the edge.  */
-                 if (bb->succ->succ_next == NULL)
-                   continue;
+                 if (bb->succ->succ_next == NULL)
+                   continue;
                }
              else
                continue;
 
              /* Fix up the CFG for the successful change we just made.  */
-             remove_edge (e);
-             make_edge (NULL, bb, EXIT_BLOCK_PTR, 0);
+             redirect_edge_succ (e, EXIT_BLOCK_PTR);
            }
 
          /* Emit a return insn for the exit fallthru block.  Whether
             this is still reachable will be determined later.  */
 
          emit_barrier_after (last->end);
-         emit_return_into_block (last);
+         emit_return_into_block (last, epilogue_line_note);
+         epilogue_end = last->end;
+         goto epilogue_done;
        }
-      else 
-       {
-         /* The exit block wasn't empty.  We have to use insert_insn_on_edge,
-            as it may be the exit block can go elsewhere as well
-            as exiting.  */
-         start_sequence ();
-         emit_jump_insn (gen_return ());
-         seq = gen_sequence ();
-         end_sequence ();
-         insert_insn_on_edge (seq, e);
-         insertted = 1;
-       }
-      goto epilogue_done;
     }
 #endif
 #ifdef HAVE_epilogue
@@ -6986,16 +7056,23 @@ thread_prologue_and_epilogue_insns (f)
         There really shouldn't be a mixture -- either all should have
         been converted or none, however...  */
 
-      for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+      for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
        if (e->flags & EDGE_FALLTHRU)
          break;
       if (e == NULL)
        goto epilogue_done;
 
       start_sequence ();
-      emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
+      epilogue_end = emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
 
       seq = gen_epilogue ();
+
+      /* If this function returns with the stack depressed, massage
+        the epilogue to actually do that.  */
+      if (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
+         && TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (current_function_decl)))
+       keep_stack_depressed (seq);
+
       emit_jump_insn (seq);
 
       /* Retain a map of the epilogue insns.  */
@@ -7004,20 +7081,20 @@ thread_prologue_and_epilogue_insns (f)
       record_insns (seq, &epilogue);
 
       seq = gen_sequence ();
-      end_sequence();
+      end_sequence ();
 
       insert_insn_on_edge (seq, e);
-      insertted = 1;
+      inserted = 1;
     }
 #endif
 epilogue_done:
 
-  if (insertted)
+  if (inserted)
     commit_edge_insertions ();
 
 #ifdef HAVE_sibcall_epilogue
   /* Emit sibling epilogues before any sibling call sites.  */
-  for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
     {
       basic_block bb = e->src;
       rtx insn = bb->end;
@@ -7045,6 +7122,73 @@ epilogue_done:
                    ? seq : newinsn, &sibcall_epilogue);
     }
 #endif
+
+#ifdef HAVE_prologue
+  if (prologue_end)
+    {
+      rtx insn, prev;
+
+      /* GDB handles `break f' by setting a breakpoint on the first
+        line note after the prologue.  Which means (1) that if
+        there are line number notes before where we inserted the
+        prologue we should move them, and (2) we should generate a
+        note before the end of the first basic block, if there isn't
+        one already there.  */
+
+      for (insn = prologue_end; insn; insn = prev)
+       {
+         prev = PREV_INSN (insn);
+         if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+           {
+             /* Note that we cannot reorder the first insn in the
+                chain, since rest_of_compilation relies on that
+                remaining constant.  */
+             if (prev == NULL)
+               break;
+             reorder_insns (insn, insn, prologue_end);
+           }
+       }
+
+      /* Find the last line number note in the first block.  */
+      for (insn = BASIC_BLOCK (0)->end;
+          insn != prologue_end;
+          insn = PREV_INSN (insn))
+       if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+         break;
+
+      /* If we didn't find one, make a copy of the first line number
+        we run across.  */
+      if (! insn)
+       {
+         for (insn = next_active_insn (prologue_end);
+              insn;
+              insn = PREV_INSN (insn))
+           if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+             {
+               emit_line_note_after (NOTE_SOURCE_FILE (insn),
+                                     NOTE_LINE_NUMBER (insn),
+                                     prologue_end);
+               break;
+             }
+       }
+    }
+#endif
+#ifdef HAVE_epilogue
+  if (epilogue_end)
+    {
+      rtx insn, next;
+
+      /* Similarly, move any line notes that appear after the epilogue.
+         There is no need, however, to be quite so anal about the existance
+        of such a note.  */
+      for (insn = epilogue_end; insn; insn = next)
+       {
+         next = NEXT_INSN (insn);
+         if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+           reorder_insns (insn, insn, PREV_INSN (epilogue_end));
+       }
+    }
+#endif
 }
 
 /* Reposition the prologue-end and epilogue-begin notes after instruction
@@ -7086,7 +7230,7 @@ reposition_prologue_and_epilogue_notes (f)
 
              next = NEXT_INSN (note);
 
-             /* Whether or not we can depend on BLOCK_HEAD, 
+             /* Whether or not we can depend on BLOCK_HEAD,
                 attempt to keep it up-to-date.  */
              if (BLOCK_HEAD (0) == note)
                BLOCK_HEAD (0) = next;
@@ -7123,7 +7267,7 @@ reposition_prologue_and_epilogue_notes (f)
                      break;
                }
 
-             /* Whether or not we can depend on BLOCK_HEAD, 
+             /* Whether or not we can depend on BLOCK_HEAD,
                 attempt to keep it up-to-date.  */
              if (n_basic_blocks
                  && BLOCK_HEAD (n_basic_blocks-1) == insn)
@@ -7141,7 +7285,7 @@ reposition_prologue_and_epilogue_notes (f)
 
 static void
 mark_temp_slot (t)
-  struct temp_slot *t;
+     struct temp_slot *t;
 {
   while (t)
     {