function.c (assign_parms): Save and restore setting of TREE_USED (parm).
[gcc.git] / gcc / function.c
index f69076f2b716c93008bda701433bfb36a8bc2120..1cb8c44bbcd3829d2c47d8cf45eeb56e5268edd7 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
-   Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -55,6 +55,11 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "basic-block.h"
 #include "obstack.h"
+#include "toplev.h"
+
+#if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
+#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
+#endif
 
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
@@ -137,6 +142,12 @@ int current_function_has_computed_jump;
 
 int current_function_contains_functions;
 
+/* 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. */
+
+int current_function_sp_is_unchanging;
+
 /* Nonzero if the current function is a thunk (a lightweight function that
    just adjusts one of its arguments and forwards to another function), so
    we should try to cut corners where we can.  */
@@ -213,6 +224,16 @@ int current_function_uses_pic_offset_table;
 /* The arg pointer hard register, or the pseudo into which it was copied.  */
 rtx current_function_internal_arg_pointer;
 
+/* Language-specific reason why the current function cannot be made inline.  */
+char *current_function_cannot_inline;
+
+/* Nonzero if instrumentation calls for function entry and exit should be
+   generated.  */
+int current_function_instrument_entry_exit;
+
+/* Nonzero if memory access checking be enabled in the current function.  */
+int current_function_check_memory_usage;
+
 /* The FUNCTION_DECL for an inline function currently being expanded.  */
 tree inline_function_decl;
 
@@ -226,10 +247,12 @@ int function_call_count;
 
 tree nonlocal_labels;
 
-/* RTX for stack slot that holds the current handler for nonlocal gotos.
+/* List (chain of EXPR_LIST) of stack slots that hold the current handlers
+   for nonlocal gotos.  There is one for every nonlocal label in the function;
+   this list matches the one in nonlocal_labels.
    Zero when function does not have nonlocal labels.  */
 
-rtx nonlocal_goto_handler_slot;
+rtx nonlocal_goto_handler_slots;
 
 /* RTX for stack slot that holds the stack pointer value to restore
    for a nonlocal goto.
@@ -360,7 +383,7 @@ struct temp_slot
      slot above.  May be an EXPR_LIST if multiple addresses exist.  */
   rtx address;
   /* The size, in units, of the slot.  */
-  int size;
+  HOST_WIDE_INT size;
   /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
   tree rtl_expr;
   /* Non-zero if this temporary is currently in use.  */
@@ -373,10 +396,10 @@ struct temp_slot
   int keep;
   /* The offset of the slot from the frame_pointer, including extra space
      for alignment.  This info is for combine_temp_slots.  */
-  int base_offset;
+  HOST_WIDE_INT base_offset;
   /* The size of the slot, including extra space for alignment.  This
      info is for combine_temp_slots.  */
-  int full_size;
+  HOST_WIDE_INT full_size;
 };
 
 /* List of all temporaries allocated, both available and in use.  */
@@ -386,6 +409,16 @@ struct temp_slot *temp_slots;
 /* Current nesting level for temporaries.  */
 
 int temp_slot_level;
+
+/* Current nesting level for variables in a block.  */
+
+int var_temp_slot_level;
+
+/* When temporaries are created by TARGET_EXPRs, they are created at
+   this level of temp_slot_level, so that they can remain allocated
+   until no longer needed.  CLEANUP_POINT_EXPRs define the lifetime
+   of TARGET_EXPRs.  */
+int target_temp_slot_level;
 \f
 /* This structure is used to record MEMs or pseudos used to replace VAR, any
    SUBREGs of VAR, and any MEMs containing VAR as an address.  We need to
@@ -401,10 +434,12 @@ struct fixup_replacement
    
 /* Forward declarations.  */
 
+static rtx assign_outer_stack_local PROTO ((enum machine_mode, HOST_WIDE_INT,
+                                           int, struct function *));
 static struct temp_slot *find_temp_slot_from_address  PROTO((rtx));
 static void put_reg_into_stack PROTO((struct function *, rtx, tree,
                                       enum machine_mode, enum machine_mode,
-                                      int, int));
+                                      int, int, int));
 static void fixup_var_refs     PROTO((rtx, enum machine_mode, int));
 static struct fixup_replacement
   *find_fixup_replacement      PROTO((struct fixup_replacement **, rtx));
@@ -426,16 +461,18 @@ static void pad_to_arg_alignment PROTO((struct args_size *, int));
 static void pad_below          PROTO((struct args_size *, enum  machine_mode,
                                       tree));
 #endif
+#ifdef ARGS_GROW_DOWNWARD
 static tree round_down         PROTO((tree, int));
+#endif
 static rtx round_trampoline_addr PROTO((rtx));
 static tree blocks_nreverse    PROTO((tree));
 static int all_blocks          PROTO((tree, tree *));
-static int *record_insns       PROTO((rtx));
 #if defined (HAVE_prologue) || defined (HAVE_epilogue)
+static int *record_insns       PROTO((rtx));
 static int contains            PROTO((rtx, int *));
 #endif /* HAVE_prologue || HAVE_epilogue */
 static void put_addressof_into_stack PROTO((rtx));
-static void purge_addressof_1  PROTO((rtx *, rtx, int));
+static void purge_addressof_1  PROTO((rtx *, rtx, int, int));
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
 struct function *outer_function_chain;
@@ -448,9 +485,11 @@ find_function_data (decl)
      tree decl;
 {
   struct function *p;
+
   for (p = outer_function_chain; p; p = p->next)
     if (p->decl == decl)
       return p;
+
   abort ();
 }
 
@@ -490,11 +529,12 @@ push_function_context_to (context)
   p->uses_const_pool = current_function_uses_const_pool;
   p->uses_pic_offset_table = current_function_uses_pic_offset_table;
   p->internal_arg_pointer = current_function_internal_arg_pointer;
+  p->cannot_inline = current_function_cannot_inline;
   p->max_parm_reg = max_parm_reg;
   p->parm_reg_stack_loc = parm_reg_stack_loc;
   p->outgoing_args_size = current_function_outgoing_args_size;
   p->return_rtx = current_function_return_rtx;
-  p->nonlocal_goto_handler_slot = nonlocal_goto_handler_slot;
+  p->nonlocal_goto_handler_slots = nonlocal_goto_handler_slots;
   p->nonlocal_goto_stack_level = nonlocal_goto_stack_level;
   p->nonlocal_labels = nonlocal_labels;
   p->cleanup_label = cleanup_label;
@@ -513,9 +553,13 @@ push_function_context_to (context)
   p->function_call_count = function_call_count;
   p->temp_slots = temp_slots;
   p->temp_slot_level = temp_slot_level;
+  p->target_temp_slot_level = target_temp_slot_level;
+  p->var_temp_slot_level = var_temp_slot_level;
   p->fixup_var_refs_queue = 0;
   p->epilogue_delay_list = current_function_epilogue_delay_list;
   p->args_info = current_function_args_info;
+  p->check_memory_usage = current_function_check_memory_usage;
+  p->instrument_entry_exit = current_function_instrument_entry_exit;
 
   save_tree_status (p, context);
   save_storage_status (p);
@@ -523,7 +567,6 @@ push_function_context_to (context)
   save_expr_status (p);
   save_stmt_status (p);
   save_varasm_status (p, context);
-
   if (save_machine_status)
     (*save_machine_status) (p);
 }
@@ -542,6 +585,7 @@ pop_function_context_from (context)
      tree context;
 {
   struct function *p = outer_function_chain;
+  struct var_refs_queue *queue;
 
   outer_function_chain = p->next;
 
@@ -569,11 +613,12 @@ pop_function_context_from (context)
   current_function_uses_const_pool = p->uses_const_pool;
   current_function_uses_pic_offset_table = p->uses_pic_offset_table;
   current_function_internal_arg_pointer = p->internal_arg_pointer;
+  current_function_cannot_inline = p->cannot_inline;
   max_parm_reg = p->max_parm_reg;
   parm_reg_stack_loc = p->parm_reg_stack_loc;
   current_function_outgoing_args_size = p->outgoing_args_size;
   current_function_return_rtx = p->return_rtx;
-  nonlocal_goto_handler_slot = p->nonlocal_goto_handler_slot;
+  nonlocal_goto_handler_slots = p->nonlocal_goto_handler_slots;
   nonlocal_goto_stack_level = p->nonlocal_goto_stack_level;
   nonlocal_labels = p->nonlocal_labels;
   cleanup_label = p->cleanup_label;
@@ -592,9 +637,13 @@ pop_function_context_from (context)
   function_call_count = p->function_call_count;
   temp_slots = p->temp_slots;
   temp_slot_level = p->temp_slot_level;
+  target_temp_slot_level = p->target_temp_slot_level;
+  var_temp_slot_level = p->var_temp_slot_level;
   current_function_epilogue_delay_list = p->epilogue_delay_list;
   reg_renumber = 0;
   current_function_args_info = p->args_info;
+  current_function_check_memory_usage = p->check_memory_usage;
+  current_function_instrument_entry_exit = p->instrument_entry_exit;
 
   restore_tree_status (p, context);
   restore_storage_status (p);
@@ -608,11 +657,8 @@ pop_function_context_from (context)
 
   /* Finish doing put_var_into_stack for any of our variables
      which became addressable during the nested function.  */
-  {
-    struct var_refs_queue *queue = p->fixup_var_refs_queue;
-    for (; queue; queue = queue->next)
-      fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp);
-  }
+  for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
+    fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp);
 
   free (p);
 
@@ -629,7 +675,7 @@ void pop_function_context ()
 /* Allocate fixed slots in the stack frame of the current function.  */
 
 /* Return size needed for stack frame based on slots so far allocated.
-   This size counts from zero.  It is not rounded to STACK_BOUNDARY;
+   This size counts from zero.  It is not rounded to PREFERRED_STACK_BOUNDARY;
    the caller may have to do that.  */
 
 HOST_WIDE_INT
@@ -655,7 +701,7 @@ get_frame_size ()
 rtx
 assign_stack_local (mode, size, align)
      enum machine_mode mode;
-     int size;
+     HOST_WIDE_INT size;
      int align;
 {
   register rtx x, addr;
@@ -721,10 +767,10 @@ assign_stack_local (mode, size, align)
    First three arguments are same as in preceding function.
    The last argument specifies the function to allocate in.  */
 
-rtx
+static rtx
 assign_outer_stack_local (mode, size, align, function)
      enum machine_mode mode;
-     int size;
+     HOST_WIDE_INT size;
      int align;
      struct function *function;
 {
@@ -792,13 +838,15 @@ assign_outer_stack_local (mode, size, align, function)
 
    KEEP is 1 if this slot is to be retained after a call to
    free_temp_slots.  Automatic variables for a block are allocated
-   with this flag.  KEEP is 2, if we allocate a longer term temporary,
-   whose lifetime is controlled by CLEANUP_POINT_EXPRs.  */
+   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).  */
 
 rtx
 assign_stack_temp (mode, size, keep)
      enum machine_mode mode;
-     int size;
+     HOST_WIDE_INT size;
      int keep;
 {
   struct temp_slot *p, *best_p = 0;
@@ -831,7 +879,7 @@ assign_stack_temp (mode, size, keep)
       if (GET_MODE (best_p->slot) == BLKmode)
        {
          int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
-         int rounded_size = CEIL_ROUND (size, alignment);
+         HOST_WIDE_INT rounded_size = CEIL_ROUND (size, alignment);
 
          if (best_p->size - rounded_size >= alignment)
            {
@@ -862,11 +910,14 @@ assign_stack_temp (mode, size, keep)
   /* If we still didn't find one, make a new temporary.  */
   if (p == 0)
     {
-      int frame_offset_old = frame_offset;
+      HOST_WIDE_INT frame_offset_old = frame_offset;
+
       p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
+
       /* If the temp slot mode doesn't indicate the alignment,
         use the largest possible, so no one will be disappointed.  */
       p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0);
+
       /* The following slot size computation is necessary because we don't
         know the actual size of the temporary slot until assign_stack_local
         has performed all the frame alignment and size rounding for the
@@ -879,6 +930,7 @@ assign_stack_temp (mode, size, keep)
 #else
       p->size = size;
 #endif
+
       /* Now define the fields used by combine_temp_slots.  */
 #ifdef FRAME_GROWS_DOWNWARD
       p->base_offset = frame_offset;
@@ -901,6 +953,11 @@ assign_stack_temp (mode, size, keep)
       p->level = target_temp_slot_level;
       p->keep = 0;
     }
+  else if (keep == 3)
+    {
+      p->level = var_temp_slot_level;
+      p->keep = 0;
+    }
   else
     {
       p->level = temp_slot_level;
@@ -911,6 +968,8 @@ assign_stack_temp (mode, size, keep)
      set from before.  */
   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;
   return p->slot;
 }
 \f
@@ -933,7 +992,7 @@ assign_temp (type, keep, memory_required, dont_promote)
 
   if (mode == BLKmode || memory_required)
     {
-      int size = int_size_in_bytes (type);
+      HOST_WIDE_INT size = int_size_in_bytes (type);
       rtx tmp;
 
       /* Unfortunately, we don't yet know how to allocate variable-sized
@@ -946,7 +1005,7 @@ assign_temp (type, keep, memory_required, dont_promote)
        size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type));
 
       tmp = assign_stack_temp (mode, size, keep);
-      MEM_IN_STRUCT_P (tmp) = AGGREGATE_TYPE_P (type);
+      MEM_SET_IN_STRUCT_P (tmp, AGGREGATE_TYPE_P (type));
       return tmp;
     }
 
@@ -969,12 +1028,19 @@ combine_temp_slots ()
 {
   struct temp_slot *p, *q;
   struct temp_slot *prev_p, *prev_q;
-  /* Determine where to free back to after this function.  */
-  rtx free_pointer = rtx_alloc (CONST_INT);
+  int num_slots;
+
+  /* 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++)
+      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)
     {
       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)
          {
@@ -1014,9 +1080,6 @@ combine_temp_slots ()
       else
        prev_p = p;
     }
-
-  /* Free all the RTL made by plus_constant.  */ 
-  rtx_free (free_pointer);
 }
 \f
 /* Find the temp slot corresponding to the object at address X.  */
@@ -1032,6 +1095,7 @@ find_temp_slot_from_address (x)
     {
       if (! p->in_use)
        continue;
+
       else if (XEXP (p->slot, 0) == x
               || p->address == x
               || (GET_CODE (x) == PLUS
@@ -1051,7 +1115,7 @@ find_temp_slot_from_address (x)
 }
       
 /* Indicate that NEW is an alternate way of referring to the temp slot
-   that previous was known by OLD.  */
+   that previously was known by OLD.  */
 
 void
 update_temp_slot_address (old, new)
@@ -1254,6 +1318,44 @@ push_temp_slots ()
   temp_slot_level++;
 }
 
+/* Likewise, but save the new level as the place to allocate variables
+   for blocks.  */
+
+void
+push_temp_slots_for_block ()
+{
+  push_temp_slots ();
+
+  var_temp_slot_level = temp_slot_level;
+}
+
+/* Likewise, but save the new level as the place to allocate temporaries
+   for TARGET_EXPRs.  */
+
+void
+push_temp_slots_for_target ()
+{
+  push_temp_slots ();
+
+  target_temp_slot_level = temp_slot_level;
+}
+
+/* Set and get the value of target_temp_slot_level.  The only
+   permitted use of these functions is to save and restore this value.  */
+
+int
+get_target_temp_slot_level ()
+{
+  return target_temp_slot_level;
+}
+
+void
+set_target_temp_slot_level (level)
+     int level;
+{
+  target_temp_slot_level = level;
+}
+
 /* Pop a temporary nesting level.  All slots in use in the current level
    are freed.  */
 
@@ -1279,6 +1381,7 @@ init_temp_slots ()
   /* We have not allocated any temporaries yet.  */
   temp_slots = 0;
   temp_slot_level = 0;
+  var_temp_slot_level = 0;
   target_temp_slot_level = 0;
 }
 \f
@@ -1297,7 +1400,7 @@ put_var_into_stack (decl)
 
   context = decl_function_context (decl);
 
-  /* Get the current rtl used for this object and it's original mode.  */
+  /* Get the current rtl used for this object and its original mode.  */
   reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl);
 
   /* No need to do anything if decl has no rtx yet
@@ -1332,6 +1435,7 @@ put_var_into_stack (decl)
 
   can_use_addressof
     = (function == 0
+       && optimize > 0
        /* FIXME make it work for promoted modes too */
        && decl_mode == promoted_mode
 #ifdef NON_SAVING_SETJMP
@@ -1357,7 +1461,9 @@ put_var_into_stack (decl)
       else
        put_reg_into_stack (function, reg, TREE_TYPE (decl),
                            promoted_mode, decl_mode,
-                           TREE_SIDE_EFFECTS (decl), 0);
+                           TREE_SIDE_EFFECTS (decl), 0,
+                           TREE_USED (decl)
+                           || DECL_INITIAL (decl) != 0);
     }
   else if (GET_CODE (reg) == CONCAT)
     {
@@ -1368,19 +1474,24 @@ put_var_into_stack (decl)
 #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);
+                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
+                         TREE_USED (decl) || DECL_INITIAL (decl) != 0);
       put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0);
+                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
+                         TREE_USED (decl) || DECL_INITIAL (decl) != 0);
 #else
       put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0);
+                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
+                         TREE_USED (decl) || DECL_INITIAL (decl) != 0);
       put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0);
+                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
+                         TREE_USED (decl) || DECL_INITIAL (decl) != 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);
 
       /* The two parts are in memory order already.
         Use the lower parts address as ours.  */
@@ -1392,7 +1503,7 @@ put_var_into_stack (decl)
   else
     return;
   
-  if (flag_check_memory_usage)
+  if (current_function_check_memory_usage)
     emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                       XEXP (reg, 0), ptr_mode,
                       GEN_INT (GET_MODE_SIZE (GET_MODE (reg))),
@@ -1405,17 +1516,19 @@ put_var_into_stack (decl)
    into the stack frame of FUNCTION (0 means the current function).
    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.  */
+   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.  */
 
 static void
 put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
-                   original_regno)
+                   original_regno, used_p)
      struct function *function;
      rtx reg;
      tree type;
      enum machine_mode promoted_mode, decl_mode;
      int volatile_p;
      int original_regno;
+     int used_p;
 {
   rtx new = 0;
   int regno = original_regno;
@@ -1450,11 +1563,14 @@ 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_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type) | MEM_IN_STRUCT_P (new);
+  MEM_SET_IN_STRUCT_P (reg,
+                      AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new));
+  MEM_ALIAS_SET (reg) = get_alias_set (type);
 
   /* Now make sure that all refs to the variable, previously made
      when it was a register, are fixed up to be valid again.  */
-  if (function)
+
+  if (used_p && function != 0)
     {
       struct var_refs_queue *temp;
 
@@ -1473,7 +1589,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
       function->fixup_var_refs_queue = temp;
       pop_obstacks ();
     }
-  else
+  else if (used_p)
     /* Variable is local; fix it up now.  */
     fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type));
 }
@@ -1561,7 +1677,9 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
   while (insn)
     {
       rtx next = NEXT_INSN (insn);
+      rtx set, prev, prev_set;
       rtx note;
+
       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
        {
          /* If this is a CLOBBER of VAR, delete it.
@@ -1569,7 +1687,10 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
             If it has a REG_LIBCALL note, delete the REG_LIBCALL
             and REG_RETVAL notes too.  */
          if (GET_CODE (PATTERN (insn)) == CLOBBER
-             && XEXP (PATTERN (insn), 0) == var)
+             && (XEXP (PATTERN (insn), 0) == var
+                 || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
+                     && (XEXP (XEXP (PATTERN (insn), 0), 0) == var
+                         || XEXP (XEXP (PATTERN (insn), 0), 1) == var))))
            {
              if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
                /* The REG_LIBCALL note will go away since we are going to
@@ -1587,14 +1708,22 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
            }
 
          /* The insn to load VAR from a home in the arglist
-            is now a no-op.  When we see it, just delete it.  */
+            is now a no-op.  When we see it, just delete it.
+            Similarly if this is storing VAR from a register from which
+            it was loaded in the previous insn.  This will occur
+            when an ADDRESSOF was made for an arglist slot.  */
          else if (toplevel
-                  && GET_CODE (PATTERN (insn)) == SET
-                  && SET_DEST (PATTERN (insn)) == var
+                  && (set = single_set (insn)) != 0
+                  && SET_DEST (set) == var
                   /* If this represents the result of an insn group,
                      don't delete the insn.  */
                   && find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0
-                  && rtx_equal_p (SET_SRC (PATTERN (insn)), var))
+                  && (rtx_equal_p (SET_SRC (set), var)
+                      || (GET_CODE (SET_SRC (set)) == REG
+                          && (prev = prev_nonnote_insn (insn)) != 0
+                          && (prev_set = single_set (prev)) != 0
+                          && SET_DEST (prev_set) == SET_SRC (set)
+                          && rtx_equal_p (SET_SRC (prev_set), var))))
            {
              /* In unoptimized compilation, we shouldn't call delete_insn
                 except in jump.c doing warnings.  */
@@ -1862,21 +1991,29 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            {
              enum machine_mode wanted_mode = VOIDmode;
              enum machine_mode is_mode = GET_MODE (tem);
-             int pos = INTVAL (XEXP (x, 2));
+             HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
 
 #ifdef HAVE_extzv
              if (GET_CODE (x) == ZERO_EXTRACT)
-               wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+               {
+                 wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+                 if (wanted_mode == VOIDmode)
+                   wanted_mode = word_mode;
+               }
 #endif
 #ifdef HAVE_extv
              if (GET_CODE (x) == SIGN_EXTRACT)
-               wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
+               {
+                 wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
+                 if (wanted_mode == VOIDmode)
+                   wanted_mode = word_mode;
+               }
 #endif
              /* If we have a narrower mode, we can do something.  */
              if (wanted_mode != VOIDmode
                  && GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
                {
-                 int offset = pos / BITS_PER_UNIT;
+                 HOST_WIDE_INT offset = pos / BITS_PER_UNIT;
                  rtx old_pos = XEXP (x, 2);
                  rtx newmem;
 
@@ -1891,8 +2028,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  newmem = gen_rtx_MEM (wanted_mode,
                                        plus_constant (XEXP (tem, 0), offset));
                  RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
-                 MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
-                 MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
+                 MEM_COPY_ATTRIBUTES (newmem, tem);
 
                  /* Make the change and see if the insn remains valid.  */
                  INSN_CODE (insn) = -1;
@@ -2059,15 +2195,18 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                && ! mode_dependent_address_p (XEXP (tem, 0))
                && ! MEM_VOLATILE_P (tem))
              {
-               enum machine_mode wanted_mode
-                 = insn_operand_mode[(int) CODE_FOR_insv][0];
+               enum machine_mode wanted_mode;
                enum machine_mode is_mode = GET_MODE (tem);
-               int pos = INTVAL (XEXP (outerdest, 2));
+               HOST_WIDE_INT pos = INTVAL (XEXP (outerdest, 2));
+
+               wanted_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
+               if (wanted_mode == VOIDmode)
+                 wanted_mode = word_mode;
 
                /* If we have a narrower mode, we can do something.  */
                if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
                  {
-                   int offset = pos / BITS_PER_UNIT;
+                   HOST_WIDE_INT offset = pos / BITS_PER_UNIT;
                    rtx old_pos = XEXP (outerdest, 2);
                    rtx newmem;
 
@@ -2080,8 +2219,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                    newmem = gen_rtx_MEM (wanted_mode,
                                          plus_constant (XEXP (tem, 0), offset));
                    RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
-                   MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
-                   MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
+                   MEM_COPY_ATTRIBUTES (newmem, tem);
 
                    /* Make the change and see if the insn remains valid.  */
                    INSN_CODE (insn) = -1;
@@ -2472,7 +2610,7 @@ optimize_bit_field (body, insn, equiv_mem)
             that we are now getting rid of,
             and then for which byte of the word is wanted.  */
 
-         register int offset = INTVAL (XEXP (bitfield, 2));
+         HOST_WIDE_INT offset = INTVAL (XEXP (bitfield, 2));
          rtx insns;
 
          /* Adjust OFFSET to count bits from low-address byte.  */
@@ -2579,6 +2717,7 @@ static int in_arg_offset;
 static int var_offset;
 static int dynamic_offset;
 static int out_arg_offset;
+static int cfa_offset;
 
 /* In most machines, the stack pointer register is equivalent to the bottom
    of the stack.  */
@@ -2617,6 +2756,13 @@ static int out_arg_offset;
 #endif
 #endif
 
+/* On a few machines, the CFA coincides with the arg pointer.  */
+
+#ifndef ARG_POINTER_CFA_OFFSET
+#define ARG_POINTER_CFA_OFFSET 0
+#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.
@@ -2628,17 +2774,22 @@ gen_mem_addressof (reg, decl)
      tree decl;
 {
   tree type = TREE_TYPE (decl);
-
   rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), REGNO (reg));
   SET_ADDRESSOF_DECL (r, decl);
+  /* If the original REG was a user-variable, then so is the REG whose
+     address is being taken.  */
+  REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
 
   XEXP (reg, 0) = r;
   PUT_CODE (reg, MEM);
   PUT_MODE (reg, DECL_MODE (decl));
   MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
-  MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);
+  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));
 
-  fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type));
   return reg;
 }
 
@@ -2670,18 +2821,23 @@ put_addressof_into_stack (r)
 
   put_reg_into_stack (0, reg, TREE_TYPE (decl), GET_MODE (reg),
                      DECL_MODE (decl), TREE_SIDE_EFFECTS (decl),
-                     ADDRESSOF_REGNO (r));
+                     ADDRESSOF_REGNO (r),
+                     TREE_USED (decl) || DECL_INITIAL (decl) != 0);
 }
 
+/* List of replacements made below in purge_addressof_1 when creating
+   bitfield insertions.  */
+static rtx purge_addressof_replacements;
+
 /* Helper function for purge_addressof.  See if the rtx expression at *LOC
    in INSN needs to be changed.  If FORCE, always put any ADDRESSOFs into
    the stack.  */
 
 static void
-purge_addressof_1 (loc, insn, force)
+purge_addressof_1 (loc, insn, force, store)
      rtx *loc;
      rtx insn;
-     int force;
+     int force, store;
 {
   rtx x;
   RTX_CODE code;
@@ -2713,27 +2869,164 @@ purge_addressof_1 (loc, insn, force)
                             0))
        abort ();
 
-      insns = get_insns ();
+      insns = gen_sequence ();
       end_sequence ();
-      emit_insns_before (insns, insn);
+      emit_insn_before (insns, insn);
       return;
     }
   else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
     {
       rtx sub = XEXP (XEXP (x, 0), 0);
+
       if (GET_CODE (sub) == MEM)
        sub = gen_rtx_MEM (GET_MODE (x), copy_rtx (XEXP (sub, 0)));
-      if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
+
+      if (GET_CODE (sub) == REG
+         && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
+       {
+         put_addressof_into_stack (XEXP (x, 0));
+         return;
+       }
+      else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
        {
-         if (! BYTES_BIG_ENDIAN && ! WORDS_BIG_ENDIAN)
+         int size_x, size_sub;
+
+         if (!insn)
            {
-             rtx sub2 = gen_rtx_SUBREG (GET_MODE (x), sub, 0);
-             if (validate_change (insn, loc, sub2, 0))
-               goto restart;
+             /* When processing REG_NOTES look at the list of
+                replacements done on the insn to find the register that X
+                was replaced by.  */
+             rtx tem;
+
+             for (tem = purge_addressof_replacements; tem != NULL_RTX;
+                  tem = XEXP (XEXP (tem, 1), 1))
+               {
+                 rtx y = XEXP (tem, 0);
+                 if (GET_CODE (y) == MEM
+                     && rtx_equal_p (XEXP (x, 0), XEXP (y, 0)))
+                   {
+                     /* 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.  */
+
+                     rtx z = XEXP (XEXP (tem, 1), 0);
+                     if (GET_MODE (x) != GET_MODE (y))
+                       {
+                         if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0)
+                           z = SUBREG_REG (z);
+
+                         /* ??? If we'd gotten into any of the really complex
+                            cases below, I'm not sure we can do a proper
+                            replacement.  Might we be able to delete the
+                            note in some cases?  */
+                         if (GET_MODE_SIZE (GET_MODE (x))
+                             < GET_MODE_SIZE (GET_MODE (y)))
+                           abort ();
+
+                         z = gen_lowpart (GET_MODE (x), z);
+                       }
+
+                     *loc = z;
+                     return;
+                   }
+               }
+
+             /* There should always be such a replacement.  */
+             abort ();
+           }
+
+         size_x = GET_MODE_BITSIZE (GET_MODE (x));
+         size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
+
+         /* Don't even consider working with paradoxical subregs,
+            or the moral equivalent seen here.  */
+         if (size_x <= size_sub
+             && int_mode_for_mode (GET_MODE (sub)) != BLKmode)
+           {
+             /* Do a bitfield insertion to mirror what would happen
+                in memory.  */
+
+             rtx val, seq;
+
+             if (store)
+               {
+                 rtx p;
+
+                 start_sequence ();
+                 val = gen_reg_rtx (GET_MODE (x));
+                 if (! validate_change (insn, loc, val, 0))
+                   {
+                     /* Discard the current sequence and put the
+                        ADDRESSOF on stack.  */
+                     end_sequence ();
+                     goto give_up;
+                   }
+                 seq = gen_sequence ();
+                 end_sequence ();
+                 emit_insn_before (seq, insn);
+             
+                 start_sequence ();
+                 store_bit_field (sub, size_x, 0, GET_MODE (x),
+                                  val, GET_MODE_SIZE (GET_MODE (sub)),
+                                  GET_MODE_SIZE (GET_MODE (sub)));
+
+                 /* Make sure to unshare any shared rtl that store_bit_field
+                    might have created.  */
+                 for (p = get_insns(); p; p = NEXT_INSN (p))
+                   {
+                     reset_used_flags (PATTERN (p));
+                     reset_used_flags (REG_NOTES (p));
+                     reset_used_flags (LOG_LINKS (p));
+                   }
+                 unshare_all_rtl (get_insns ());
+
+                 seq = gen_sequence ();
+                 end_sequence ();
+                 emit_insn_after (seq, insn);
+               }
+             else
+               {
+                 start_sequence ();
+                 val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX,
+                                          GET_MODE (x), GET_MODE (x),
+                                          GET_MODE_SIZE (GET_MODE (sub)),
+                                          GET_MODE_SIZE (GET_MODE (sub)));
+
+                 if (! validate_change (insn, loc, val, 0))
+                   {
+                     /* Discard the current sequence and put the
+                        ADDRESSOF on stack.  */
+                     end_sequence ();
+                     goto give_up;
+                   }
+
+                 seq = gen_sequence ();
+                 end_sequence ();
+                 emit_insn_before (seq, insn);
+               }
+
+             /* Remember the replacement so that the same one can be done
+                on the REG_NOTES.  */
+             purge_addressof_replacements
+               = gen_rtx_EXPR_LIST (VOIDmode, x,
+                                    gen_rtx_EXPR_LIST (VOIDmode, val,
+                                                       purge_addressof_replacements));
+
+             /* We replaced with a reg -- all done.  */
+             return;
            }
        }
       else if (validate_change (insn, loc, sub, 0))
-       goto restart;
+       {
+         /* Remember the replacement so that the same one can be done
+            on the REG_NOTES.  */
+         purge_addressof_replacements
+           = gen_rtx_EXPR_LIST (VOIDmode, x,
+                                gen_rtx_EXPR_LIST (VOIDmode, sub,
+                                                   purge_addressof_replacements));
+         goto restart;
+       }
+    give_up:;
       /* else give up and put it into the stack */
     }
   else if (code == ADDRESSOF)
@@ -2741,16 +3034,22 @@ purge_addressof_1 (loc, insn, force)
       put_addressof_into_stack (x);
       return;
     }
+  else if (code == SET)
+    {
+      purge_addressof_1 (&SET_DEST (x), insn, force, 1);
+      purge_addressof_1 (&SET_SRC (x), insn, force, 0);
+      return;
+    }
 
   /* Scan all subexpressions. */
   fmt = GET_RTX_FORMAT (code);
   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
     {
       if (*fmt == 'e')
-       purge_addressof_1 (&XEXP (x, i), insn, force);
+       purge_addressof_1 (&XEXP (x, i), insn, force, 0);
       else if (*fmt == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
-         purge_addressof_1 (&XVECEXP (x, i, j), insn, force);
+         purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0);
     }
 }
 
@@ -2768,9 +3067,10 @@ purge_addressof (insns)
        || GET_CODE (insn) == CALL_INSN)
       {
        purge_addressof_1 (&PATTERN (insn), insn,
-                          asm_noperands (PATTERN (insn)) > 0);
-       purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0);
+                          asm_noperands (PATTERN (insn)) > 0, 0);
+       purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0);
       }
+  purge_addressof_replacements = 0;
 }
 \f
 /* Pass through the INSNS of function FNDECL and convert virtual register
@@ -2789,6 +3089,7 @@ instantiate_virtual_regs (fndecl, insns)
   var_offset = STARTING_FRAME_OFFSET;
   dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
   out_arg_offset = STACK_POINTER_OFFSET;
+  cfa_offset = ARG_POINTER_CFA_OFFSET;
 
   /* Scan all variables and parameters of this function.  For each that is
      in memory, instantiate all virtual registers if the result is a valid
@@ -2847,7 +3148,8 @@ instantiate_decls (fndecl, valid_only)
   /* Process all parameters of the function.  */
   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
     {
-      int size = int_size_in_bytes (TREE_TYPE (decl));
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
       instantiate_decl (DECL_RTL (decl), size, valid_only);    
 
       /* If the parameter was promoted, then the incoming RTL mode may be
@@ -2977,7 +3279,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
   rtx x;
   RTX_CODE code;
   rtx new = 0;
-  int offset;
+  HOST_WIDE_INT offset;
   rtx temp;
   rtx seq;
   int i, j;
@@ -3010,7 +3312,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
 
     case SET:
       /* We are allowed to set the virtual registers.  This means that
-        that the actual register should receive the source minus the
+        the actual register should receive the source minus the
         appropriate offset.  This is used, for example, in the handling
         of non-local gotos.  */
       if (SET_DEST (x) == virtual_incoming_args_rtx)
@@ -3021,6 +3323,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        new = stack_pointer_rtx, offset = - dynamic_offset;
       else if (SET_DEST (x) == virtual_outgoing_args_rtx)
        new = stack_pointer_rtx, offset = - out_arg_offset;
+      else if (SET_DEST (x) == virtual_cfa_rtx)
+       new = arg_pointer_rtx, offset = - cfa_offset;
 
       if (new)
        {
@@ -3072,6 +3376,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
                new = stack_pointer_rtx, offset = dynamic_offset;
              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;
              else
                {
                  loc = &XEXP (x, 0);
@@ -3091,6 +3397,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
            {
              /* We know the second operand is a constant.  Unless the
@@ -3298,6 +3606,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        new = stack_pointer_rtx, offset = dynamic_offset;
       else if (x == virtual_outgoing_args_rtx)
        new = stack_pointer_rtx, offset = out_arg_offset;
+      else if (x == virtual_cfa_rtx)
+        new = arg_pointer_rtx, offset = cfa_offset;
 
       if (new)
        {
@@ -3390,13 +3700,22 @@ delete_handlers ()
                TREE_CHAIN (last_t) = TREE_CHAIN (t);
            }
        }
-      if (GET_CODE (insn) == INSN
-         && ((nonlocal_goto_handler_slot != 0
-              && reg_mentioned_p (nonlocal_goto_handler_slot, PATTERN (insn)))
+      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_insn (insn);
+                                     PATTERN (insn))))
+           delete_insn (insn);
+       }
     }
 }
 
@@ -3652,17 +3971,7 @@ assign_parms (fndecl, second_time)
       /* 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.  */
-#ifdef STRICT_ARGUMENT_NAMING
-      int named_arg = 1;
-#else
-      int named_arg = ! last_named;
-#endif
-      /* If this is a varargs function, then we want to treat the last named
-        argument as if it was an aggregate, because it might be accessed as
-        one by the va_arg macros.  This is necessary to make the aliasing
-        code handle this parm correctly.  */
-      if (hide_last_arg && last_named)
-       aggregate = 1;
+      int named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named;
 
       if (TREE_TYPE (parm) == error_mark_node
          /* This can happen after weird syntax errors
@@ -3724,6 +4033,7 @@ assign_parms (fndecl, second_time)
 
 #ifdef PROMOTE_FUNCTION_ARGS
       /* Compute the mode in which the arg is actually extended to.  */
+      unsignedp = TREE_UNSIGNED (passed_type);
       promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
 #endif
 
@@ -3805,8 +4115,9 @@ assign_parms (fndecl, second_time)
          /* 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_IN_STRUCT_P (stack_parm) = aggregate;
+         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);
        }
 
       /* If this parameter was passed both in registers and in the stack,
@@ -3840,8 +4151,10 @@ assign_parms (fndecl, second_time)
                  /* Handle calls that pass values in multiple non-contiguous
                     locations.  The Irix 6 ABI has examples of this.  */
                  if (GET_CODE (entry_parm) == PARALLEL)
-                   emit_group_store (validize_mem (stack_parm),
-                                        entry_parm);
+                   emit_group_store (validize_mem (stack_parm), entry_parm,
+                                     int_size_in_bytes (TREE_TYPE (parm)),
+                                     (TYPE_ALIGN (TREE_TYPE (parm))
+                                      / BITS_PER_UNIT));
                  else
                    move_block_from_reg (REGNO (entry_parm),
                                         validize_mem (stack_parm), nregs,
@@ -3942,7 +4255,7 @@ assign_parms (fndecl, second_time)
 
          /* If this is a memory ref that contains aggregate components,
             mark it as such for cse and loop optimize.  */
-         MEM_IN_STRUCT_P (stack_parm) = aggregate;
+         MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
        }
 #endif /* 0 */
 
@@ -3999,7 +4312,7 @@ assign_parms (fndecl, second_time)
 
                  /* If this is a memory ref that contains aggregate
                     components, mark it as such for cse and loop optimize.  */
-                 MEM_IN_STRUCT_P (stack_parm) = aggregate;
+                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
                }
 
              else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
@@ -4011,7 +4324,10 @@ assign_parms (fndecl, second_time)
              /* Handle calls that pass values in multiple non-contiguous
                 locations.  The Irix 6 ABI has examples of this.  */
              if (GET_CODE (entry_parm) == PARALLEL)
-               emit_group_store (validize_mem (stack_parm), entry_parm);
+               emit_group_store (validize_mem (stack_parm), entry_parm,
+                                 int_size_in_bytes (TREE_TYPE (parm)),
+                                 (TYPE_ALIGN (TREE_TYPE (parm))
+                                  / BITS_PER_UNIT));
              else
                move_block_from_reg (REGNO (entry_parm),
                                     validize_mem (stack_parm),
@@ -4037,7 +4353,7 @@ assign_parms (fndecl, second_time)
             may need to do it in a wider mode.  */
 
          register rtx parmreg;
-         int regno, regnoi, regnor;
+         int regno, regnoi = 0, regnor = 0;
 
          unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
 
@@ -4053,7 +4369,7 @@ assign_parms (fndecl, second_time)
            {
              DECL_RTL (parm)
                = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
-             MEM_IN_STRUCT_P (DECL_RTL (parm)) = aggregate;
+             MEM_SET_IN_STRUCT_P (DECL_RTL (parm), aggregate);
            }
          else
            DECL_RTL (parm) = parmreg;
@@ -4062,6 +4378,7 @@ assign_parms (fndecl, second_time)
          if (nominal_mode != passed_mode
              || promoted_nominal_mode != promoted_mode)
            {
+             int save_tree_used;
              /* ENTRY_PARM has been converted to PROMOTED_MODE, its
                 mode, by the caller.  We now have to convert it to 
                 NOMINAL_MODE, if different.  However, PARMREG may be in
@@ -4088,8 +4405,11 @@ assign_parms (fndecl, second_time)
              push_to_sequence (conversion_insns);
              tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
 
+             /* TREE_USED gets set erroneously during expand_assignment.  */
+             save_tree_used = TREE_USED (parm);
              expand_assignment (parm,
                                 make_tree (nominal_type, tempreg), 0, 0);
+             TREE_USED (parm) = save_tree_used;
              conversion_insns = get_insns ();
              did_conversion = 1;
              end_sequence ();
@@ -4154,12 +4474,12 @@ assign_parms (fndecl, second_time)
              else
                copy = assign_stack_temp (TYPE_MODE (type),
                                          int_size_in_bytes (type), 1);
-             MEM_IN_STRUCT_P (copy) = AGGREGATE_TYPE_P (type);
+             MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
              RTX_UNCHANGING_P (copy) = TREE_READONLY (parm);
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
-             if (flag_check_memory_usage)
+             if (current_function_check_memory_usage)
                emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                                   XEXP (copy, 0), ptr_mode,
                                   GEN_INT (int_size_in_bytes (type)),
@@ -4269,7 +4589,7 @@ assign_parms (fndecl, second_time)
            }
 
          /* For pointer data type, suggest pointer register.  */
-         if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
+         if (POINTER_TYPE_P (TREE_TYPE (parm)))
            mark_reg_pointer (parmreg,
                              (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm)))
                               / BITS_PER_UNIT));
@@ -4309,7 +4629,7 @@ assign_parms (fndecl, second_time)
                                          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_IN_STRUCT_P (stack_parm) = aggregate;
+                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
                }
 
              if (promoted_mode != nominal_mode)
@@ -4324,9 +4644,7 @@ assign_parms (fndecl, second_time)
                emit_move_insn (validize_mem (stack_parm),
                                validize_mem (entry_parm));
            }
-         if (flag_check_memory_usage
-             && entry_parm != stack_parm
-             && promoted_mode != nominal_mode)
+         if (current_function_check_memory_usage)
            {
              push_to_sequence (conversion_insns);
              emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
@@ -4353,7 +4671,8 @@ assign_parms (fndecl, second_time)
          DECL_RTL (result)
            = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
 
-         MEM_IN_STRUCT_P (DECL_RTL (result)) = AGGREGATE_TYPE_P (restype);
+         MEM_SET_IN_STRUCT_P (DECL_RTL (result), 
+                              AGGREGATE_TYPE_P (restype));
        }
 
       if (TREE_THIS_VOLATILE (parm))
@@ -4380,8 +4699,8 @@ assign_parms (fndecl, second_time)
 #endif
 #endif
 
-#ifdef STACK_BOUNDARY
-#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
+#ifdef PREFERRED_STACK_BOUNDARY
+#define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
 
   current_function_args_size
     = ((current_function_args_size + STACK_BYTES - 1)
@@ -4655,6 +4974,7 @@ pad_below (offset_ptr, passed_mode, sizetree)
 }
 #endif
 
+#ifdef ARGS_GROW_DOWNWARD
 static tree
 round_down (value, divisor)
      tree value;
@@ -4664,6 +4984,7 @@ round_down (value, divisor)
                     size_binop (FLOOR_DIV_EXPR, value, size_int (divisor)),
                     size_int (divisor));
 }
+#endif
 \f
 /* Walk the tree of blocks describing the binding levels within a function
    and warn about uninitialized variables.
@@ -4685,6 +5006,14 @@ uninitialized_vars_warning (block)
          && ! 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.
+
+            We do not care about the actual value in DECL_INITIAL, so we do
+            not worry that it may be a dangling pointer.  */
+         && DECL_INITIAL (decl) == NULL_TREE
          && regno_uninitialized (REGNO (DECL_RTL (decl))))
        warning_with_decl (decl,
                           "`%s' might be used uninitialized in this function");
@@ -4730,7 +5059,7 @@ setjmp_protect (block)
            || (GET_CODE (DECL_RTL (decl)) == MEM
                && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
        /* If this variable came from an inline function, it must be
-          that it's life doesn't overlap the setjmp.  If there was a
+          that its life doesn't overlap the setjmp.  If there was a
           setjmp in the function, it would already be in memory.  We
           must exclude such variable because their DECL_RTL might be
           set to strange things such as virtual_stack_vars_rtx.  */
@@ -4811,7 +5140,7 @@ fix_lexical_addr (addr, var)
      tree var;
 {
   rtx basereg;
-  int displacement;
+  HOST_WIDE_INT displacement;
   tree context = decl_function_context (var);
   struct function *fp;
   rtx base = 0;
@@ -5041,8 +5370,8 @@ identify_blocks (block, insns)
          }
        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
          {
-           current_block_number = block_stack[--depth];
            NOTE_BLOCK_NUMBER (insn) = current_block_number;
+           current_block_number = block_stack[--depth];
          }
       }
 
@@ -5173,7 +5502,7 @@ init_function_start (subr, filename, line)
   stack_slot_list = 0;
 
   /* There is no stack slot for handling nonlocal gotos.  */
-  nonlocal_goto_handler_slot = 0;
+  nonlocal_goto_handler_slots = 0;
   nonlocal_goto_stack_level = 0;
 
   /* No labels have been declared for nonlocal use.  */
@@ -5216,6 +5545,7 @@ init_function_start (subr, filename, line)
   current_function_has_nonlocal_label = 0;
   current_function_has_nonlocal_goto = 0;
   current_function_contains_functions = 0;
+  current_function_sp_is_unchanging = 0;
   current_function_is_thunk = 0;
 
   current_function_returns_pcc_struct = 0;
@@ -5223,6 +5553,7 @@ init_function_start (subr, filename, line)
   current_function_epilogue_delay_list = 0;
   current_function_uses_const_pool = 0;
   current_function_uses_pic_offset_table = 0;
+  current_function_cannot_inline = 0;
 
   /* We have not yet needed to make a label to jump to for tail-recursion.  */
   tail_recursion_label = 0;
@@ -5255,8 +5586,10 @@ init_function_start (subr, filename, line)
   current_function_outgoing_args_size = 0;
 
   /* Prevent ever trying to delete the first instruction of a function.
-     Also tell final how to output a linenum before the function prologue.  */
-  emit_line_note (filename, line);
+     Also tell final how to output a linenum before the function prologue.
+     Note linenums could be missing, e.g. when compiling a Java .class file. */
+  if (line > 0)
+    emit_line_note (filename, line);
 
   /* Make sure first insn is a note even if we don't want linenums.
      This makes sure the first insn will never be deleted.
@@ -5336,12 +5669,21 @@ expand_function_start (subr, parms_have_cleanups)
 {
   register int i;
   tree tem;
-  rtx last_ptr;
+  rtx last_ptr = NULL_RTX;
 
   /* Make sure volatile mem refs aren't considered
      valid operands of arithmetic insns.  */
   init_recog_no_volatile ();
 
+  /* Set this before generating any memory accesses.  */
+  current_function_check_memory_usage
+    = (flag_check_memory_usage
+       && ! DECL_NO_CHECK_MEMORY_USAGE (current_function_decl));
+
+  current_function_instrument_entry_exit
+    = (flag_instrument_function_entry_exit
+       && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
+
   /* 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)
@@ -5368,6 +5710,7 @@ expand_function_start (subr, parms_have_cleanups)
      or if it returns a structure, or if it has parm cleanups.  */
 #ifdef HAVE_return
   if (cleanup_label == 0 && HAVE_return
+      && ! current_function_instrument_entry_exit
       && ! current_function_returns_pcc_struct
       && ! (current_function_returns_struct && ! optimize))
     return_label = 0;
@@ -5409,14 +5752,16 @@ expand_function_start (subr, parms_have_cleanups)
        {
          DECL_RTL (DECL_RESULT (subr))
            = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
-         MEM_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)))
-           = AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr)));
+         MEM_SET_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)),
+                              AGGREGATE_TYPE_P (TREE_TYPE
+                                                (DECL_RESULT
+                                                 (subr))));
        }
     }
   else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
     /* If return mode is void, this decl rtl should not be used.  */
     DECL_RTL (DECL_RESULT (subr)) = 0;
-  else if (parms_have_cleanups)
+  else if (parms_have_cleanups || current_function_instrument_entry_exit)
     {
       /* If function will end with cleanup code for parms,
         compute the return values into a pseudo reg,
@@ -5534,6 +5879,21 @@ expand_function_start (subr, parms_have_cleanups)
        }
     }
 
+  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, 0, VOIDmode, 2,
+                        fun, Pmode,
+                        expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+                                                    0,
+                                                    hard_frame_pointer_rtx),
+                        Pmode);
+    }
+
   /* After the display initializations is where the tail-recursion label
      should go, if we end up needing one.   Ensure we have a NOTE here
      since some things (like trampolines) get placed before this.  */
@@ -5597,7 +5957,9 @@ expand_function_end (filename, line, end_bindings)
       tree function = TREE_PURPOSE (link);
       rtx context = lookup_static_chain (function);
       rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link));
+#ifdef TRAMPOLINE_TEMPLATE
       rtx blktramp;
+#endif
       rtx seq;
 
 #ifdef TRAMPOLINE_TEMPLATE
@@ -5662,7 +6024,8 @@ expand_function_end (filename, line, end_bindings)
     }
 
   /* Delete handlers for nonlocal gotos if nothing uses them.  */
-  if (nonlocal_goto_handler_slot != 0 && !current_function_has_nonlocal_label)
+  if (nonlocal_goto_handler_slots != 0
+      && ! current_function_has_nonlocal_label)
     delete_handlers ();
 
   /* End any sequences that failed to be closed due to syntax errors.  */
@@ -5745,6 +6108,21 @@ expand_function_end (filename, line, end_bindings)
       }
   }
 
+  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, 0, VOIDmode, 2,
+                        fun, Pmode,
+                        expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+                                                    0,
+                                                    hard_frame_pointer_rtx),
+                        Pmode);
+    }
+
   /* 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.  */
@@ -5822,6 +6200,10 @@ expand_function_end (filename, line, end_bindings)
       use_variable (outgoing);
     }
 
+  /* If this is an implementation of __throw, do what's necessary to 
+     communicate between __builtin_eh_return and the epilogue.  */
+  expand_eh_return ();
+
   /* Output a return insn if we are using one.
      Otherwise, let the rtl chain end here, to drop through
      into the epilogue.  */
@@ -5852,6 +6234,7 @@ static int *epilogue;
 /* Create an array that records the INSN_UIDs of INSNS (either a sequence
    or a single insn).  */
 
+#if defined (HAVE_prologue) || defined (HAVE_epilogue)
 static int *
 record_insns (insns)
      rtx insns;
@@ -5877,7 +6260,6 @@ record_insns (insns)
 
 /* Determine how many INSN_UIDs in VEC are part of INSN.  */
 
-#if defined (HAVE_prologue) || defined (HAVE_epilogue)
 static int
 contains (insn, vec)
      rtx insn;
@@ -5911,7 +6293,7 @@ contains (insn, vec)
 
 void
 thread_prologue_and_epilogue_insns (f)
-     rtx f;
+     rtx f ATTRIBUTE_UNUSED;
 {
 #ifdef HAVE_prologue
   if (HAVE_prologue)
@@ -5926,9 +6308,9 @@ thread_prologue_and_epilogue_insns (f)
 
       /* Include the new prologue insns in the first block.  Ignore them
         if they form a basic block unto themselves.  */
-      if (basic_block_head && n_basic_blocks
-         && GET_CODE (basic_block_head[0]) != CODE_LABEL)
-       basic_block_head[0] = NEXT_INSN (f);
+      if (x_basic_block_head && n_basic_blocks
+         && GET_CODE (BLOCK_HEAD (0)) != CODE_LABEL)
+       BLOCK_HEAD (0) = NEXT_INSN (f);
 
       /* Retain a map of the prologue insns.  */
       prologue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : head);
@@ -5994,9 +6376,9 @@ thread_prologue_and_epilogue_insns (f)
 
          /* Include the new epilogue insns in the last block.  Ignore
             them if they form a basic block unto themselves.  */
-         if (basic_block_end && n_basic_blocks
-             && GET_CODE (basic_block_end[n_basic_blocks - 1]) != JUMP_INSN)
-           basic_block_end[n_basic_blocks - 1] = tail;
+         if (x_basic_block_end && n_basic_blocks
+             && GET_CODE (BLOCK_END (n_basic_blocks - 1)) != JUMP_INSN)
+           BLOCK_END (n_basic_blocks - 1) = tail;
 
          /* Retain a map of the epilogue insns.  */
          epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail);
@@ -6012,7 +6394,7 @@ thread_prologue_and_epilogue_insns (f)
 
 void
 reposition_prologue_and_epilogue_notes (f)
-     rtx f;
+     rtx f ATTRIBUTE_UNUSED;
 {
 #if defined (HAVE_prologue) || defined (HAVE_epilogue)
   /* Reposition the prologue and epilogue notes.  */
@@ -6048,12 +6430,19 @@ reposition_prologue_and_epilogue_notes (f)
                            && NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
                          break;
                    }
+
                  next = NEXT_INSN (note);
                  prev = PREV_INSN (note);
                  if (prev)
                    NEXT_INSN (prev) = next;
                  if (next)
                    PREV_INSN (next) = prev;
+
+                 /* 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;
+
                  add_insn_after (note, insn);
                }
            }
@@ -6092,7 +6481,14 @@ reposition_prologue_and_epilogue_notes (f)
                    NEXT_INSN (prev) = next;
                  if (next)
                    PREV_INSN (next) = prev;
-                 add_insn_after (note, PREV_INSN (insn));
+
+                 /* Whether or not we can depend on BLOCK_HEAD, 
+                    attempt to keep it up-to-date.  */
+                 if (n_basic_blocks
+                     && BLOCK_HEAD (n_basic_blocks-1) == insn)
+                   BLOCK_HEAD (n_basic_blocks-1) = note;
+
+                 add_insn_before (note, insn);
                }
            }
        }