OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 582c4ca..d2eab67 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
-   Copyright (C) 1987, 88, 89, 91-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -39,7 +39,7 @@ Boston, MA 02111-1307, USA.  */
    then scans all the RTL instructions so far generated to correct them.  */
 
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -55,8 +55,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "basic-block.h"
 #include "obstack.h"
-#include "bytecode.h"
-#include "bc-emit.h"
+#include "toplev.h"
 
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
@@ -128,10 +127,23 @@ int current_function_has_nonlocal_label;
 
 int current_function_has_nonlocal_goto;
 
+/* Nonzero if this function has a computed goto.
+
+   It is computed during find_basic_blocks or during stupid life
+   analysis.  */
+
+int current_function_has_computed_jump;
+
 /* Nonzero if function being compiled contains nested functions.  */
 
 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.  */
@@ -191,10 +203,10 @@ CUMULATIVE_ARGS current_function_args_info;
 
 char *current_function_name;
 
-/* If non-zero, an RTL expression for that location at which the current
-   function returns its result.  Always equal to
-   DECL_RTL (DECL_RESULT (current_function_decl)), but provided
-   independently of the tree structures.  */
+/* If non-zero, an RTL expression for the location at which the current 
+   function returns its result.  If the current function returns its
+   result in a register, current_function_return_rtx will always be
+   the hard register containing the result.  */
 
 rtx current_function_return_rtx;
 
@@ -208,6 +220,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;
 
@@ -300,14 +322,15 @@ static int invalid_stack_slot;
 /* Last insn of those whose job was to put parms into their nominal homes.  */
 static rtx last_parm_insn;
 
-/* 1 + last pseudo register number used for loading a copy
-   of a parameter of this function.  */
-static int max_parm_reg;
+/* 1 + last pseudo register number possibly used for loading a copy
+   of a parameter of this function. */
+int max_parm_reg;
 
 /* Vector indexed by REGNO, containing location on stack in which
    to put the parm which is nominally in pseudo register REGNO,
-   if we discover that that parm must go in the stack.  */
-static rtx *parm_reg_stack_loc;
+   if we discover that that parm must go in the stack.  The highest
+   element in this vector is one less than MAX_PARM_REG, above.  */
+rtx *parm_reg_stack_loc;
 
 /* Nonzero once virtual register instantiation has been done.
    assign_stack_local uses frame_pointer_rtx when this is nonzero.  */
@@ -354,7 +377,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.  */
@@ -367,10 +390,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.  */
@@ -380,32 +403,17 @@ struct temp_slot *temp_slots;
 /* Current nesting level for temporaries.  */
 
 int temp_slot_level;
-\f
-/* The FUNCTION_DECL node for the current function.  */
-static tree this_function_decl;
-
-/* Callinfo pointer for the current function.  */
-static rtx this_function_callinfo;
-
-/* The label in the bytecode file of this function's actual bytecode.
-   Not an rtx.  */
-static char *this_function_bytecode;
-
-/* The call description vector for the current function.  */
-static rtx this_function_calldesc;
 
-/* Size of the local variables allocated for the current function.  */
-int local_vars_size;
+/* Current nesting level for variables in a block.  */
 
-/* Current depth of the bytecode evaluation stack.  */
-int stack_depth;
-
-/* Maximum depth of the evaluation stack in this function.  */
-int max_stack_depth;
-
-/* Current depth in statement expressions.  */
-static int stmt_expr_depth;
+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
    maintain this list in case two operands of an insn were required to match;
@@ -420,10 +428,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));
 static void fixup_var_refs     PROTO((rtx, enum machine_mode, int));
 static struct fixup_replacement
   *find_fixup_replacement      PROTO((struct fixup_replacement **, rtx));
@@ -441,14 +451,22 @@ static void instantiate_decl      PROTO((rtx, int, int));
 static int instantiate_virtual_regs_1 PROTO((rtx *, rtx, int));
 static void delete_handlers    PROTO((void));
 static void pad_to_arg_alignment PROTO((struct args_size *, int));
+#ifndef ARGS_GROW_DOWNWARD
 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 *));
+#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, int));
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
 struct function *outer_function_chain;
@@ -461,9 +479,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 ();
 }
 
@@ -503,6 +523,7 @@ 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;
@@ -526,18 +547,20 @@ 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);
   save_emit_status (p);
-  init_emit ();
   save_expr_status (p);
   save_stmt_status (p);
-  save_varasm_status (p);
-
+  save_varasm_status (p, context);
   if (save_machine_status)
     (*save_machine_status) (p);
 }
@@ -556,6 +579,7 @@ pop_function_context_from (context)
      tree context;
 {
   struct function *p = outer_function_chain;
+  struct var_refs_queue *queue;
 
   outer_function_chain = p->next;
 
@@ -583,6 +607,7 @@ 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;
@@ -606,11 +631,15 @@ 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);
+  restore_tree_status (p, context);
   restore_storage_status (p);
   restore_expr_status (p);
   restore_emit_status (p);
@@ -622,11 +651,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);
 
@@ -669,7 +695,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;
@@ -724,9 +750,9 @@ assign_stack_local (mode, size, align)
   frame_offset += size;
 #endif
 
-  x = gen_rtx (MEM, mode, addr);
+  x = gen_rtx_MEM (mode, addr);
 
-  stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, x, stack_slot_list);
+  stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, x, stack_slot_list);
 
   return x;
 }
@@ -735,10 +761,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;
 {
@@ -786,10 +812,10 @@ assign_outer_stack_local (mode, size, align, function)
   function->frame_offset += size;
 #endif
 
-  x = gen_rtx (MEM, mode, addr);
+  x = gen_rtx_MEM (mode, addr);
 
   function->stack_slot_list
-    = gen_rtx (EXPR_LIST, VOIDmode, x, function->stack_slot_list);
+    = gen_rtx_EXPR_LIST (VOIDmode, x, function->stack_slot_list);
 
   pop_obstacks ();
 
@@ -806,13 +832,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;
@@ -845,7 +873,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)
            {
@@ -854,16 +882,16 @@ assign_stack_temp (mode, size, keep)
              p->size = best_p->size - rounded_size;
              p->base_offset = best_p->base_offset + rounded_size;
              p->full_size = best_p->full_size - rounded_size;
-             p->slot = gen_rtx (MEM, BLKmode,
-                                plus_constant (XEXP (best_p->slot, 0),
-                                               rounded_size));
+             p->slot = gen_rtx_MEM (BLKmode,
+                                    plus_constant (XEXP (best_p->slot, 0),
+                                                   rounded_size));
              p->address = 0;
              p->rtl_expr = 0;
              p->next = temp_slots;
              temp_slots = p;
 
-             stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, p->slot,
-                                        stack_slot_list);
+             stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, p->slot,
+                                                  stack_slot_list);
 
              best_p->size = rounded_size;
              best_p->full_size = rounded_size;
@@ -876,11 +904,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
@@ -893,6 +924,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;
@@ -915,6 +947,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;
@@ -947,7 +984,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
@@ -983,12 +1020,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)
          {
@@ -1028,9 +1072,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.  */
@@ -1046,6 +1087,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
@@ -1065,7 +1107,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)
@@ -1081,9 +1123,9 @@ update_temp_slot_address (old, new)
   else
     {
       if (GET_CODE (p->address) != EXPR_LIST)
-       p->address = gen_rtx (EXPR_LIST, VOIDmode, p->address, NULL_RTX);
+       p->address = gen_rtx_EXPR_LIST (VOIDmode, p->address, NULL_RTX);
 
-      p->address = gen_rtx (EXPR_LIST, VOIDmode, new, p->address);
+      p->address = gen_rtx_EXPR_LIST (VOIDmode, new, p->address);
     }
 }
 
@@ -1245,7 +1287,7 @@ free_temps_for_rtl_expr (t)
   combine_temp_slots ();
 }
 
-/* Mark all temporaries ever allocated in this functon as not suitable
+/* Mark all temporaries ever allocated in this function as not suitable
    for reuse until the current level is exited.  */
 
 void
@@ -1268,6 +1310,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.  */
 
@@ -1293,6 +1373,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
@@ -1307,13 +1388,11 @@ put_var_into_stack (decl)
   enum machine_mode promoted_mode, decl_mode;
   struct function *function = 0;
   tree context;
+  int can_use_addressof;
 
-  if (output_bytecode)
-    return;
-  
   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
@@ -1330,7 +1409,7 @@ put_var_into_stack (decl)
 
   /* If this variable comes from an outer function,
      find that function's saved context.  */
-  if (context != current_function_decl)
+  if (context != current_function_decl && context != inline_function_decl)
     for (function = outer_function_chain; function; function = function->next)
       if (function->decl == context)
        break;
@@ -1346,11 +1425,38 @@ put_var_into_stack (decl)
       decl_mode = promoted_mode = GET_MODE (reg);
     }
 
+  can_use_addressof
+    = (function == 0
+       && optimize > 0
+       /* FIXME make it work for promoted modes too */
+       && decl_mode == promoted_mode
+#ifdef NON_SAVING_SETJMP
+       && ! (NON_SAVING_SETJMP && current_function_calls_setjmp)
+#endif
+       );
+
+  /* If we can't use ADDRESSOF, make sure we see through one we already
+     generated.  */
+  if (! can_use_addressof && GET_CODE (reg) == MEM
+      && GET_CODE (XEXP (reg, 0)) == ADDRESSOF)
+    reg = XEXP (XEXP (reg, 0), 0);
+
   /* Now we should have a value that resides in one or more pseudo regs.  */
 
   if (GET_CODE (reg) == REG)
-    put_reg_into_stack (function, reg, TREE_TYPE (decl),
-                       promoted_mode, decl_mode, TREE_SIDE_EFFECTS (decl));
+    {
+      /* If this variable lives in the current function and we don't need
+        to put things in the stack for the sake of setjmp, try to keep it
+        in a register until we know we actually need the address.  */
+      if (can_use_addressof)
+       gen_mem_addressof (reg, decl);
+      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);
+    }
   else if (GET_CODE (reg) == CONCAT)
     {
       /* A CONCAT contains two pseudos; put them both in the stack.
@@ -1360,19 +1466,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));
+                         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));
+                         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));
+                         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));
+                         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.  */
@@ -1381,36 +1492,54 @@ put_var_into_stack (decl)
       if (GET_CODE (XEXP (reg, 0)) == PLUS)
        XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
     }
+  else
+    return;
+  
+  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))),
+                      TYPE_MODE (sizetype),
+                      GEN_INT (MEMORY_USE_RW),
+                      TYPE_MODE (integer_type_node));
 }
 
 /* Subroutine of put_var_into_stack.  This puts a single pseudo reg REG
    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)
+put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
+                   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;
+
+  if (regno == 0)
+    regno = REGNO (reg);
 
   if (function)
     {
-      if (REGNO (reg) < function->max_parm_reg)
-       new = function->parm_reg_stack_loc[REGNO (reg)];
+      if (regno < function->max_parm_reg)
+       new = function->parm_reg_stack_loc[regno];
       if (new == 0)
        new = assign_outer_stack_local (decl_mode, GET_MODE_SIZE (decl_mode),
                                        0, function);
     }
   else
     {
-      if (REGNO (reg) < max_parm_reg)
-       new = parm_reg_stack_loc[REGNO (reg)];
+      if (regno < max_parm_reg)
+       new = parm_reg_stack_loc[regno];
       if (new == 0)
        new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);
     }
@@ -1422,12 +1551,17 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p)
   PUT_CODE (reg, MEM);
 
   /* If this is a memory ref that contains aggregate components,
-     mark it as such for cse and loop optimize.  */
-  MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);
+     mark it as such for cse and loop optimize.  If we are reusing a
+     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_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;
 
@@ -1446,7 +1580,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));
 }
@@ -1534,7 +1668,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.
@@ -1542,7 +1678,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
@@ -1560,14 +1699,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.  */
@@ -1582,22 +1729,21 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
              struct fixup_replacement *replacements = 0;
              rtx next_insn = NEXT_INSN (insn);
 
-#ifdef SMALL_REGISTER_CLASSES
-             /* If the insn that copies the results of a CALL_INSN
-                into a pseudo now references VAR, we have to use an
-                intermediate pseudo since we want the life of the
-                return value register to be only a single insn.
+             if (SMALL_REGISTER_CLASSES)
+               {
+                 /* If the insn that copies the results of a CALL_INSN
+                    into a pseudo now references VAR, we have to use an
+                    intermediate pseudo since we want the life of the
+                    return value register to be only a single insn.
 
-                If we don't use an intermediate pseudo, such things as
-                address computations to make the address of VAR valid
-                if it is not can be placed between the CALL_INSN and INSN.
+                    If we don't use an intermediate pseudo, such things as
+                    address computations to make the address of VAR valid
+                    if it is not can be placed between the CALL_INSN and INSN.
 
-                To make sure this doesn't happen, we record the destination
-                of the CALL_INSN and see if the next insn uses both that
-                and VAR.  */
+                    To make sure this doesn't happen, we record the destination
+                    of the CALL_INSN and see if the next insn uses both that
+                    and VAR.  */
 
-             if (SMALL_REGISTER_CLASSES)
-               {
                  if (call_dest != 0 && GET_CODE (insn) == INSN
                      && reg_mentioned_p (var, PATTERN (insn))
                      && reg_mentioned_p (call_dest, PATTERN (insn)))
@@ -1620,7 +1766,6 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
                  else
                    call_dest = 0;
                }
-#endif
 
              /* See if we have to do anything to INSN now that VAR is in
                 memory.  If it needs to be loaded into a pseudo, use a single
@@ -1723,6 +1868,27 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
   switch (code)
     {
+    case ADDRESSOF:
+      if (XEXP (x, 0) == var)
+       {
+         /* Prevent sharing of rtl that might lose.  */
+         rtx sub = copy_rtx (XEXP (var, 0));
+
+         start_sequence ();
+
+         if (! validate_change (insn, loc, sub, 0))
+           {
+             rtx y = force_operand (sub, NULL_RTX);
+
+             if (! validate_change (insn, loc, y, 0))
+               *loc = copy_to_reg (y);
+           }
+
+         emit_insn_before (gen_sequence (), insn);
+         end_sequence ();
+       }
+      return;
+
     case MEM:
       if (var == x)
        {
@@ -1816,22 +1982,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 width = INTVAL (XEXP (x, 1));
-             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;
 
@@ -1843,8 +2016,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
                  pos %= GET_MODE_BITSIZE (wanted_mode);
 
-                 newmem = gen_rtx (MEM, wanted_mode,
-                                   plus_constant (XEXP (tem, 0), offset));
+                 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);
@@ -1965,7 +2138,9 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
       {
        rtx dest = SET_DEST (x);
        rtx src = SET_SRC (x);
+#ifdef HAVE_insv
        rtx outerdest = dest;
+#endif
 
        while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
               || GET_CODE (dest) == SIGN_EXTRACT
@@ -2012,16 +2187,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 width = INTVAL (XEXP (outerdest, 1));
-               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;
 
@@ -2031,8 +2208,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
                    pos %= GET_MODE_BITSIZE (wanted_mode);
 
-                   newmem = gen_rtx (MEM, wanted_mode,
-                                     plus_constant (XEXP (tem, 0), offset));
+                   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);
@@ -2197,6 +2374,9 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            SET_DEST (x) = temp;
          }
       }
+
+    default:
+      break;
     }
 
   /* Nothing special about this RTX; fix its operands.  */
@@ -2232,7 +2412,7 @@ fixup_memory_subreg (x, insn, uncritical)
   int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
   rtx addr = XEXP (SUBREG_REG (x), 0);
   enum machine_mode mode = GET_MODE (x);
-  rtx saved, result;
+  rtx result;
 
   /* Paradoxical SUBREGs are usually invalid during RTL generation.  */
   if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
@@ -2322,6 +2502,12 @@ fixup_stack_1 (x, insn)
          && GET_CODE (XEXP (ad, 0)) == REG
          && ((REGNO (XEXP (ad, 0)) >= FIRST_VIRTUAL_REGISTER
               && REGNO (XEXP (ad, 0)) <= LAST_VIRTUAL_REGISTER)
+             || REGNO (XEXP (ad, 0)) == FRAME_POINTER_REGNUM
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+             || REGNO (XEXP (ad, 0)) == HARD_FRAME_POINTER_REGNUM
+#endif
+             || REGNO (XEXP (ad, 0)) == STACK_POINTER_REGNUM
+             || REGNO (XEXP (ad, 0)) == ARG_POINTER_REGNUM
              || XEXP (ad, 0) == current_function_internal_arg_pointer)
          && GET_CODE (XEXP (ad, 1)) == CONST_INT)
        {
@@ -2417,7 +2603,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.  */
@@ -2524,6 +2710,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.  */
@@ -2562,6 +2749,278 @@ 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.
+   REG is overwritten by the MEM like in put_reg_into_stack.  */
+
+rtx
+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));
+  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_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));
+
+  return reg;
+}
+
+/* If DECL has an RTL that is an ADDRESSOF rtx, put it into the stack.  */
+
+void
+flush_addressof (decl)
+     tree decl;
+{
+  if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
+      && DECL_RTL (decl) != 0
+      && GET_CODE (DECL_RTL (decl)) == MEM
+      && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF
+      && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG)
+    put_addressof_into_stack (XEXP (DECL_RTL (decl), 0));
+}
+
+/* Force the register pointed to by R, an ADDRESSOF rtx, into the stack.  */
+
+static void
+put_addressof_into_stack (r)
+     rtx r;
+{
+  tree decl = ADDRESSOF_DECL (r);
+  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);
+}
+
+/* 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, store)
+     rtx *loc;
+     rtx insn;
+     int force, store;
+{
+  rtx x;
+  RTX_CODE code;
+  int i, j;
+  char *fmt;
+
+  /* Re-start here to avoid recursion in common cases.  */
+ restart:
+
+  x = *loc;
+  if (x == 0)
+    return;
+
+  code = GET_CODE (x);
+
+  if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
+    {
+      rtx insns;
+      /* We must create a copy of the rtx because it was created by
+        overwriting a REG rtx which is always shared.  */
+      rtx sub = copy_rtx (XEXP (XEXP (x, 0), 0));
+
+      if (validate_change (insn, loc, sub, 0))
+       return;
+
+      start_sequence ();
+      if (! validate_change (insn, loc,
+                            force_operand (sub, NULL_RTX),
+                            0))
+       abort ();
+
+      insns = gen_sequence ();
+      end_sequence ();
+      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
+         && (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))
+       {
+         int size_x, size_sub;
+
+         if (!insn)
+           {
+             /* 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))
+               if (rtx_equal_p (x, XEXP (tem, 0)))
+                 {
+                   *loc = XEXP (XEXP (tem, 1), 0);
+                   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)
+               {
+                 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)));
+
+                 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;
+    give_up:;
+      /* else give up and put it into the stack */
+    }
+  else if (code == ADDRESSOF)
+    {
+      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, 0);
+      else if (*fmt == 'E')
+       for (j = 0; j < XVECLEN (x, i); j++)
+         purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0);
+    }
+}
+
+/* Eliminate all occurrences of ADDRESSOF from INSNS.  Elide any remaining
+   (MEM (ADDRESSOF)) patterns, and force any needed registers into the
+   stack.  */
+
+void
+purge_addressof (insns)
+     rtx insns;
+{
+  rtx insn;
+  for (insn = insns; insn; insn = NEXT_INSN (insn))
+    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+       || GET_CODE (insn) == CALL_INSN)
+      {
+       purge_addressof_1 (&PATTERN (insn), insn,
+                          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
    references to hard register references.  */
 
@@ -2571,12 +3030,14 @@ instantiate_virtual_regs (fndecl, insns)
      rtx insns;
 {
   rtx insn;
+  int i;
 
   /* Compute the offsets to use for this function.  */
   in_arg_offset = FIRST_PARM_OFFSET (fndecl);
   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
@@ -2597,6 +3058,12 @@ instantiate_virtual_regs (fndecl, insns)
        instantiate_virtual_regs_1 (&REG_NOTES (insn), NULL_RTX, 0);
       }
 
+  /* Instantiate the stack slots for the parm registers, for later use in
+     addressof elimination.  */
+  for (i = 0; i < max_parm_reg; ++i)
+    if (parm_reg_stack_loc[i])
+      instantiate_virtual_regs_1 (&parm_reg_stack_loc[i], NULL_RTX, 0);
+
   /* Now instantiate the remaining register equivalences for debugging info.
      These will not be valid addresses.  */
   instantiate_decls (fndecl, 0);
@@ -2629,7 +3096,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
@@ -2694,6 +3162,7 @@ instantiate_decl (x, size, valid_only)
 
   addr = XEXP (x, 0);
   if (CONSTANT_P (addr)
+      || (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == REG)
       || (GET_CODE (addr) == REG
          && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
              || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
@@ -2758,7 +3227,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;
@@ -2791,7 +3260,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)
@@ -2802,6 +3271,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)
        {
@@ -2823,7 +3294,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
          emit_insns_before (seq, object);
          SET_DEST (x) = new;
 
-         if (!validate_change (object, &SET_SRC (x), temp, 0)
+         if (! validate_change (object, &SET_SRC (x), temp, 0)
              || ! extra_insns)
            abort ();
 
@@ -2853,6 +3324,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);
@@ -2861,7 +3334,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
 
              instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
                                          extra_insns);
-             new = gen_rtx (PLUS, Pmode, new, XEXP (XEXP (x, 0), 1));
+             new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
            }
 
          else if (XEXP (x, 0) == virtual_incoming_args_rtx)
@@ -2872,6 +3345,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
@@ -2924,7 +3399,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
                     register containing the sum.  */
 
                  XEXP (x, 0) = old;
-                 new = gen_rtx (PLUS, Pmode, new, new_offset);
+                 new = gen_rtx_PLUS (Pmode, new, new_offset);
 
                  start_sequence ();
                  temp = force_operand (new, NULL_RTX);
@@ -3079,6 +3554,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)
        {
@@ -3101,6 +3578,23 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        }
 
       return 1;
+
+    case ADDRESSOF:
+      if (GET_CODE (XEXP (x, 0)) == REG)
+       return 1;
+
+      else if (GET_CODE (XEXP (x, 0)) == MEM)
+       {
+         /* If we have a (addressof (mem ..)), do any instantiation inside
+            since we know we'll be making the inside valid when we finally
+            remove the ADDRESSOF.  */
+         instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), NULL_RTX, 0);
+         return 1;
+       }
+      break;
+      
+    default:
+      break;
     }
 
   /* Scan all subexpressions.  */
@@ -3174,7 +3668,7 @@ nonlocal_label_rtx_list ()
   rtx x = 0;
 
   for (t = nonlocal_labels; t; t = TREE_CHAIN (t))
-    x = gen_rtx (EXPR_LIST, VOIDmode, label_rtx (TREE_VALUE (t)), x);
+    x = gen_rtx_EXPR_LIST (VOIDmode, label_rtx (TREE_VALUE (t)), x);
 
   return x;
 }
@@ -3189,14 +3683,14 @@ use_variable (rtl)
 {
   if (GET_CODE (rtl) == REG)
     /* This is a register variable.  */
-    emit_insn (gen_rtx (USE, VOIDmode, rtl));
+    emit_insn (gen_rtx_USE (VOIDmode, rtl));
   else if (GET_CODE (rtl) == MEM
           && GET_CODE (XEXP (rtl, 0)) == REG
           && (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
               || REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
           && XEXP (rtl, 0) != current_function_internal_arg_pointer)
     /* This is a variable-sized structure.  */
-    emit_insn (gen_rtx (USE, VOIDmode, XEXP (rtl, 0)));
+    emit_insn (gen_rtx_USE (VOIDmode, XEXP (rtl, 0)));
 }
 
 /* Like use_variable except that it outputs the USEs after INSN
@@ -3208,14 +3702,14 @@ use_variable_after (rtl, insn)
 {
   if (GET_CODE (rtl) == REG)
     /* This is a register variable.  */
-    emit_insn_after (gen_rtx (USE, VOIDmode, rtl), insn);
+    emit_insn_after (gen_rtx_USE (VOIDmode, rtl), insn);
   else if (GET_CODE (rtl) == MEM
           && GET_CODE (XEXP (rtl, 0)) == REG
           && (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
               || REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
           && XEXP (rtl, 0) != current_function_internal_arg_pointer)
     /* This is a variable-sized structure.  */
-    emit_insn_after (gen_rtx (USE, VOIDmode, XEXP (rtl, 0)), insn);
+    emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (rtl, 0)), insn);
 }
 \f
 int
@@ -3271,7 +3765,7 @@ aggregate_value_p (exp)
 
   if (RETURN_IN_MEMORY (type))
     return 1;
-  /* Types that are TREE_ADDRESSABLE must be contructed in memory,
+  /* Types that are TREE_ADDRESSABLE must be constructed in memory,
      and thus can't be returned in registers.  */
   if (TREE_ADDRESSABLE (type))
     return 1;
@@ -3327,7 +3821,6 @@ assign_parms (fndecl, second_time)
   /* This is a dummy PARM_DECL that we used for the function result if 
      the function returns a structure.  */
   tree function_result_decl = 0;
-  int nparmregs = list_length (fnargs) + LAST_VIRTUAL_REGISTER + 1;
   int varargs_setup = 0;
   rtx conversion_insns = 0;
 
@@ -3385,8 +3878,9 @@ assign_parms (fndecl, second_time)
       fnargs = function_result_decl;
     }
                               
-  parm_reg_stack_loc = (rtx *) oballoc (nparmregs * sizeof (rtx));
-  bzero ((char *) parm_reg_stack_loc, nparmregs * sizeof (rtx));
+  max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
+  parm_reg_stack_loc = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
+  bzero ((char *) parm_reg_stack_loc, max_parm_reg * sizeof (rtx));
 
 #ifdef INIT_CUMULATIVE_INCOMING_ARGS
   INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
@@ -3409,10 +3903,14 @@ assign_parms (fndecl, second_time)
       tree nominal_type = TREE_TYPE (parm);
 
       /* Set LAST_NAMED if this is last named arg before some
-        anonymous args.  We treat it as if it were anonymous too.  */
+        anonymous args.  */
       int last_named = ((TREE_CHAIN (parm) == 0
                         || DECL_NAME (TREE_CHAIN (parm)) == 0)
                        && (stdarg || current_function_varargs));
+      /* Set NAMED_ARG if this arg should be treated as a named arg.  For
+        most machines, if this is a varargs/stdarg function, then we treat
+        the last named arg as if it were anonymous too.  */
+      int named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named;
 
       if (TREE_TYPE (parm) == error_mark_node
          /* This can happen after weird syntax errors
@@ -3420,8 +3918,8 @@ assign_parms (fndecl, second_time)
          || TREE_CODE (parm) != PARM_DECL
          || passed_type == NULL)
        {
-         DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = gen_rtx (MEM, BLKmode,
-                                                               const0_rtx);
+         DECL_INCOMING_RTL (parm) = DECL_RTL (parm)
+           = gen_rtx_MEM (BLKmode, const0_rtx);
          TREE_USED (parm) = 1;
          continue;
        }
@@ -3461,7 +3959,7 @@ assign_parms (fndecl, second_time)
          || TREE_ADDRESSABLE (passed_type)
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
          || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
-                                             passed_type, ! last_named)
+                                             passed_type, named_arg)
 #endif
          )
        {
@@ -3474,6 +3972,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
 
@@ -3481,10 +3980,10 @@ assign_parms (fndecl, second_time)
         0 means it arrives on the stack.  */
 #ifdef FUNCTION_INCOMING_ARG
       entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
-                                         passed_type, ! last_named);
+                                         passed_type, named_arg);
 #else
       entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
-                                passed_type, ! last_named);
+                                passed_type, named_arg);
 #endif
 
       if (entry_parm == 0)
@@ -3530,12 +4029,12 @@ assign_parms (fndecl, second_time)
 #ifdef FUNCTION_INCOMING_ARG
                           FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
                                                  passed_type,
-                                                 (! last_named
+                                                 (named_arg
                                                   || varargs_setup)) != 0,
 #else
                           FUNCTION_ARG (args_so_far, promoted_mode,
                                         passed_type,
-                                        ! last_named || varargs_setup) != 0,
+                                        named_arg || varargs_setup) != 0,
 #endif
 #endif
                           fndecl, &stack_args_size, &stack_offset, &arg_size);
@@ -3545,17 +4044,19 @@ assign_parms (fndecl, second_time)
          rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
 
          if (offset_rtx == const0_rtx)
-           stack_parm = gen_rtx (MEM, promoted_mode, internal_arg_pointer);
+           stack_parm = gen_rtx_MEM (promoted_mode, internal_arg_pointer);
          else
-           stack_parm = gen_rtx (MEM, promoted_mode,
-                                 gen_rtx (PLUS, Pmode,
-                                          internal_arg_pointer, offset_rtx));
+           stack_parm = gen_rtx_MEM (promoted_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.  Likewise if it
             is readonly.  */
          MEM_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,
@@ -3575,7 +4076,7 @@ assign_parms (fndecl, second_time)
       if (entry_parm)
        {
          int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
-                                                 passed_type, ! last_named);
+                                                 passed_type, named_arg);
 
          if (nregs > 0)
            {
@@ -3589,8 +4090,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,
@@ -3640,7 +4143,7 @@ assign_parms (fndecl, second_time)
       /* Update info on where next arg arrives in registers.  */
 
       FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
-                           passed_type, ! last_named);
+                           passed_type, named_arg);
 
       /* If this is our second time through, we are done with this parm.  */
       if (second_time)
@@ -3682,11 +4185,12 @@ assign_parms (fndecl, second_time)
 
          offset_rtx = ARGS_SIZE_RTX (stack_offset);
          if (offset_rtx == const0_rtx)
-           stack_parm = gen_rtx (MEM, nominal_mode, internal_arg_pointer);
+           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));
+           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.  */
@@ -3702,7 +4206,7 @@ assign_parms (fndecl, second_time)
         have been optimised away.  */
 
       if (GET_CODE (entry_parm) == REG && !(hide_last_arg && last_named))
-         emit_insn (gen_rtx (USE, GET_MODE (entry_parm), entry_parm));
+         emit_insn (gen_rtx_USE (GET_MODE (entry_parm), entry_parm));
 #endif
 
       /* ENTRY_PARM is an RTX for the parameter as it arrives,
@@ -3759,7 +4263,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),
@@ -3785,7 +4292,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));
 
@@ -3800,7 +4307,7 @@ assign_parms (fndecl, second_time)
          if (passed_pointer)
            {
              DECL_RTL (parm)
-               = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
+               = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
              MEM_IN_STRUCT_P (DECL_RTL (parm)) = aggregate;
            }
          else
@@ -3813,7 +4320,7 @@ assign_parms (fndecl, second_time)
              /* 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
-                a diffent mode than NOMINAL_MODE if it is being stored
+                a different mode than NOMINAL_MODE if it is being stored
                 promoted.
 
                 If ENTRY_PARM is a hard register, it might be in a register
@@ -3881,7 +4388,7 @@ assign_parms (fndecl, second_time)
                   && FUNCTION_ARG_CALLEE_COPIES (args_so_far,
                                                  TYPE_MODE (DECL_ARG_TYPE (parm)),
                                                  DECL_ARG_TYPE (parm),
-                                                 ! last_named)
+                                                 named_arg)
                   && ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
            {
              rtx copy;
@@ -3895,17 +4402,25 @@ assign_parms (fndecl, second_time)
              if (TYPE_SIZE (type) == 0
                  || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
                /* This is a variable sized object.  */
-               copy = gen_rtx (MEM, BLKmode,
-                               allocate_dynamic_stack_space
-                               (expr_size (parm), NULL_RTX,
-                                TYPE_ALIGN (type)));
+               copy = gen_rtx_MEM (BLKmode,
+                                   allocate_dynamic_stack_space
+                                   (expr_size (parm), NULL_RTX,
+                                    TYPE_ALIGN (type)));
              else
                copy = assign_stack_temp (TYPE_MODE (type),
                                          int_size_in_bytes (type), 1);
              MEM_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 (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)),
+                                  TYPE_MODE (sizetype),
+                                  GEN_INT (MEMORY_USE_RW),
+                                  TYPE_MODE (integer_type_node));
              conversion_insns = get_insns ();
              did_conversion = 1;
              end_sequence ();
@@ -3923,17 +4438,20 @@ assign_parms (fndecl, second_time)
          else
            regno = REGNO (parmreg);
 
-         if (regno >= nparmregs)
+         if (regno >= max_parm_reg)
            {
              rtx *new;
-             int old_nparmregs = nparmregs;
+             int old_max_parm_reg = max_parm_reg;
 
-             nparmregs = regno + 5;
-             new = (rtx *) oballoc (nparmregs * sizeof (rtx));
+             /* It's slow to expand this one register at a time,
+                but it's also rare and we need max_parm_reg to be
+                precisely correct.  */
+             max_parm_reg = regno + 1;
+             new = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
              bcopy ((char *) parm_reg_stack_loc, (char *) new,
-                    old_nparmregs * sizeof (rtx));
-             bzero ((char *) (new + old_nparmregs),
-                    (nparmregs - old_nparmregs) * sizeof (rtx));
+                    old_max_parm_reg * sizeof (rtx));
+             bzero ((char *) (new + old_max_parm_reg),
+                    (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
              parm_reg_stack_loc = new;
            }
 
@@ -3988,25 +4506,25 @@ assign_parms (fndecl, second_time)
                    if (set != 0
                        && SET_DEST (set) == regno_reg_rtx [regnoi])
                      REG_NOTES (sinsn)
-                       = gen_rtx (EXPR_LIST, REG_EQUIV,
-                                  parm_reg_stack_loc[regnoi],
-                                  REG_NOTES (sinsn));
+                       = gen_rtx_EXPR_LIST (REG_EQUIV,
+                                            parm_reg_stack_loc[regnoi],
+                                            REG_NOTES (sinsn));
                    else if (set != 0
                             && SET_DEST (set) == regno_reg_rtx [regnor])
                      REG_NOTES (sinsn)
-                       = gen_rtx (EXPR_LIST, REG_EQUIV,
-                                  parm_reg_stack_loc[regnor],
-                                  REG_NOTES (sinsn));
+                       = gen_rtx_EXPR_LIST (REG_EQUIV,
+                                            parm_reg_stack_loc[regnor],
+                                            REG_NOTES (sinsn));
                  }
              else if ((set = single_set (linsn)) != 0
                       && SET_DEST (set) == parmreg)
                REG_NOTES (linsn)
-                 = gen_rtx (EXPR_LIST, REG_EQUIV,
-                            stack_parm, REG_NOTES (linsn));
+                 = gen_rtx_EXPR_LIST (REG_EQUIV,
+                                      stack_parm, REG_NOTES (linsn));
            }
 
          /* 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));
@@ -4026,6 +4544,12 @@ assign_parms (fndecl, second_time)
              push_to_sequence (conversion_insns);
              entry_parm = convert_to_mode (nominal_mode, tempreg,
                                            TREE_UNSIGNED (TREE_TYPE (parm)));
+             if (stack_parm)
+               {
+                 /* ??? This may need a big-endian conversion on sparc64.  */
+                 stack_parm = change_address (stack_parm, nominal_mode,
+                                              NULL_RTX);
+               }
              conversion_insns = get_insns ();
              did_conversion = 1;
              end_sequence ();
@@ -4055,7 +4579,20 @@ assign_parms (fndecl, second_time)
                emit_move_insn (validize_mem (stack_parm),
                                validize_mem (entry_parm));
            }
+         if (current_function_check_memory_usage)
+           {
+             push_to_sequence (conversion_insns);
+             emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+                                XEXP (stack_parm, 0), ptr_mode,
+                                GEN_INT (GET_MODE_SIZE (GET_MODE 
+                                                        (entry_parm))),
+                                TYPE_MODE (sizetype),
+                                GEN_INT (MEMORY_USE_RW),
+                                TYPE_MODE (integer_type_node));
 
+             conversion_insns = get_insns ();
+             end_sequence ();
+           }
          DECL_RTL (parm) = stack_parm;
        }
       
@@ -4067,7 +4604,7 @@ assign_parms (fndecl, second_time)
          tree restype = TREE_TYPE (result);
 
          DECL_RTL (result)
-           = gen_rtx (MEM, DECL_MODE (result), DECL_RTL (parm));
+           = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
 
          MEM_IN_STRUCT_P (DECL_RTL (result)) = AGGREGATE_TYPE_P (restype);
        }
@@ -4082,7 +4619,6 @@ assign_parms (fndecl, second_time)
      now that all parameters have been copied out of hard registers.  */
   emit_insns (conversion_insns);
 
-  max_parm_reg = max_reg_num ();
   last_parm_insn = get_last_insn ();
 
   current_function_args_size = stack_args_size.constant;
@@ -4110,7 +4646,7 @@ assign_parms (fndecl, second_time)
     = (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
        : expand_expr (size_binop (MINUS_EXPR, stack_args_size.var,     
                                  size_int (-stack_args_size.constant)),   
-                     NULL_RTX, VOIDmode, 0));
+                     NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD));
 #else
   current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
 #endif
@@ -4219,14 +4755,14 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
   enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
   int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
-  int boundary_in_bytes = boundary / BITS_PER_UNIT;
-  int reg_parm_stack_space = 0;
 
 #ifdef REG_PARM_STACK_SPACE
   /* If we have found a stack parm before we reach the end of the
      area reserved for registers, skip that area.  */
   if (! in_regs)
     {
+      int reg_parm_stack_space = 0;
+
 #ifdef MAYBE_REG_PARM_STACK_SPACE
       reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
 #else
@@ -4342,6 +4878,7 @@ pad_to_arg_alignment (offset_ptr, boundary)
     }
 }
 
+#ifndef ARGS_GROW_DOWNWARD
 static void
 pad_below (offset_ptr, passed_mode, sizetree)
      struct args_size *offset_ptr;
@@ -4369,7 +4906,9 @@ pad_below (offset_ptr, passed_mode, sizetree)
        }
     }
 }
+#endif
 
+#ifdef ARGS_GROW_DOWNWARD
 static tree
 round_down (value, divisor)
      tree value;
@@ -4379,6 +4918,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.
@@ -4400,6 +4940,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");
@@ -4441,9 +4989,11 @@ setjmp_protect (block)
     if ((TREE_CODE (decl) == VAR_DECL
         || TREE_CODE (decl) == PARM_DECL)
        && DECL_RTL (decl) != 0
-       && GET_CODE (DECL_RTL (decl)) == REG
+       && (GET_CODE (DECL_RTL (decl)) == REG
+           || (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.  */
@@ -4466,13 +5016,15 @@ setjmp_protect (block)
 void
 setjmp_protect_args ()
 {
-  register tree decl, sub;
+  register tree decl;
   for (decl = DECL_ARGUMENTS (current_function_decl);
        decl; decl = TREE_CHAIN (decl))
     if ((TREE_CODE (decl) == VAR_DECL
         || TREE_CODE (decl) == PARM_DECL)
        && DECL_RTL (decl) != 0
-       && GET_CODE (DECL_RTL (decl)) == REG
+       && (GET_CODE (DECL_RTL (decl)) == REG
+           || (GET_CODE (DECL_RTL (decl)) == MEM
+               && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
        && (
            /* If longjmp doesn't restore the registers,
               don't put anything in them.  */
@@ -4522,7 +5074,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;
@@ -4538,6 +5090,9 @@ fix_lexical_addr (addr, var)
   if (fp == 0)
     abort ();
 
+  if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM)
+    addr = XEXP (XEXP (addr, 0), 0);
+
   /* Decode given address as base reg plus displacement.  */
   if (GET_CODE (addr) == REG)
     basereg = addr, displacement = 0;
@@ -4569,7 +5124,7 @@ fix_lexical_addr (addr, var)
       addr = fix_lexical_addr (XEXP (fp->arg_pointer_save_area, 0), var);
       addr = memory_address (Pmode, addr);
 
-      base = copy_to_reg (gen_rtx (MEM, Pmode, addr));
+      base = copy_to_reg (gen_rtx_MEM (Pmode, addr));
 #else
       displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET);
       base = lookup_static_chain (var);
@@ -4632,7 +5187,8 @@ trampoline_address (function)
   /* Find the `struct function' for the function containing FUNCTION.  */
   fp = 0;
   fn_context = decl_function_context (function);
-  if (fn_context != current_function_decl)
+  if (fn_context != current_function_decl
+      && fn_context != inline_function_decl)
     for (fp = outer_function_chain; fp; fp = fp->next)
       if (fp->decl == fn_context)
        break;
@@ -4748,8 +5304,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];
          }
       }
 
@@ -4859,50 +5415,6 @@ all_blocks (block, vector)
   return n_blocks;
 }
 \f
-/* Build bytecode call descriptor for function SUBR.  */
-
-rtx
-bc_build_calldesc (subr)
-  tree subr;
-{
-  tree calldesc = 0, arg;
-  int nargs = 0;
-
-  /* Build the argument description vector in reverse order.  */
-  DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr));
-  nargs = 0;
-
-  for (arg = DECL_ARGUMENTS (subr); arg; arg = TREE_CHAIN (arg))
-    {
-      ++nargs;
-
-      calldesc = tree_cons ((tree) 0, size_in_bytes (TREE_TYPE (arg)), calldesc);
-      calldesc = tree_cons ((tree) 0, bc_runtime_type_code (TREE_TYPE (arg)), calldesc);
-    }
-
-  DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr));
-
-  /* Prepend the function's return type.  */
-  calldesc = tree_cons ((tree) 0,
-                       size_in_bytes (TREE_TYPE (TREE_TYPE (subr))),
-                       calldesc);
-
-  calldesc = tree_cons ((tree) 0,
-                       bc_runtime_type_code (TREE_TYPE (TREE_TYPE (subr))),
-                       calldesc);
-
-  /* Prepend the arg count.  */
-  calldesc = tree_cons ((tree) 0, build_int_2 (nargs, 0), calldesc);
-
-  /* Output the call description vector and get its address.  */
-  calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc);
-  TREE_TYPE (calldesc) = build_array_type (integer_type_node,
-                                          build_index_type (build_int_2 (nargs * 2, 0)));
-
-  return output_constant_def (calldesc);
-}
-
-
 /* Generate RTL for the start of the function SUBR (a FUNCTION_DECL tree node)
    and initialize static variables for generating RTL for the statements
    of the function.  */
@@ -4913,17 +5425,6 @@ init_function_start (subr, filename, line)
      char *filename;
      int line;
 {
-  if (output_bytecode)
-    {
-      this_function_decl = subr;
-      this_function_calldesc = bc_build_calldesc (subr);
-      local_vars_size = 0;
-      stack_depth = 0;
-      max_stack_depth = 0;
-      stmt_expr_depth = 0;
-      return;
-    }
-
   init_stmt_for_function ();
 
   cse_not_expected = ! optimize;
@@ -4978,6 +5479,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;
@@ -4985,6 +5487,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;
@@ -5017,8 +5520,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.
@@ -5077,99 +5582,14 @@ mark_varargs ()
 void
 expand_main_function ()
 {
-  if (!output_bytecode)
-    {
-      /* The zero below avoids a possible parse error */
-      0;
 #if !defined (HAS_INIT_SECTION)
-      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, NAME__MAIN), 0,
-                        VOIDmode, 0);
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), 0,
+                    VOIDmode, 0);
 #endif /* not HAS_INIT_SECTION */
-    }
 }
 \f
 extern struct obstack permanent_obstack;
 
-/* Expand start of bytecode function. See comment at
-   expand_function_start below for details.  */
-
-void
-bc_expand_function_start (subr, parms_have_cleanups)
-  tree subr;
-  int parms_have_cleanups;
-{
-  char label[20], *name;
-  static int nlab;
-  tree thisarg;
-  int argsz;
-
-  if (TREE_PUBLIC (subr))
-    bc_globalize_label (IDENTIFIER_POINTER (DECL_NAME (subr)));
-
-#ifdef DEBUG_PRINT_CODE
-  fprintf (stderr, "\n<func %s>\n", IDENTIFIER_POINTER (DECL_NAME (subr)));
-#endif
-
-  for (argsz = 0, thisarg = DECL_ARGUMENTS (subr); thisarg; thisarg = TREE_CHAIN (thisarg))
-    {
-      if (DECL_RTL (thisarg))
-       abort ();               /* Should be NULL here I think.  */
-      else if (TREE_CONSTANT (DECL_SIZE (thisarg)))
-       {
-         DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0);
-         argsz += TREE_INT_CST_LOW (DECL_SIZE (thisarg));
-       }
-      else
-       {
-         /* Variable-sized objects are pointers to their storage.  */
-         DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0);
-         argsz += POINTER_SIZE;
-       }
-    }
-
-  bc_begin_function (xstrdup (IDENTIFIER_POINTER (DECL_NAME (subr))));
-
-  ASM_GENERATE_INTERNAL_LABEL (label, "LX", nlab);
-
-  ++nlab;
-  name = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
-  this_function_callinfo = bc_gen_rtx (name, 0, (struct bc_label *) 0);
-  this_function_bytecode
-    = bc_emit_trampoline (BYTECODE_LABEL (this_function_callinfo));
-}
-
-
-/* Expand end of bytecode function. See details the comment of
-   expand_function_end(), below.  */
-
-void
-bc_expand_function_end ()
-{
-  char *ptrconsts;
-
-  expand_null_return ();
-
-  /* Emit any fixup code. This must be done before the call to
-     to BC_END_FUNCTION (), since that will cause the bytecode
-     segment to be finished off and closed.  */
-
-  expand_fixups (NULL_RTX);
-
-  ptrconsts = bc_end_function ();
-
-  bc_align_const (2 /* INT_ALIGN */);
-
-  /* If this changes also make sure to change bc-interp.h!  */
-
-  bc_emit_const_labeldef (BYTECODE_LABEL (this_function_callinfo));
-  bc_emit_const ((char *) &max_stack_depth, sizeof max_stack_depth);
-  bc_emit_const ((char *) &local_vars_size, sizeof local_vars_size);
-  bc_emit_const_labelref (this_function_bytecode, 0);
-  bc_emit_const_labelref (ptrconsts, 0);
-  bc_emit_const_labelref (BYTECODE_LABEL (this_function_calldesc), 0);
-}
-
-
 /* Start the RTL for a new function, and set variables used for
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
@@ -5183,30 +5603,31 @@ expand_function_start (subr, parms_have_cleanups)
 {
   register int i;
   tree tem;
-  rtx last_ptr;
-
-  if (output_bytecode)
-    {
-      bc_expand_function_start (subr, parms_have_cleanups);
-      return;
-    }
+  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)
     {
       last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
 
-#ifdef SMALL_REGISTER_CLASSES
       /* Delay copying static chain if it is not a register to avoid
         conflicts with regs used for parameters.  */
       if (! SMALL_REGISTER_CLASSES
          || GET_CODE (static_chain_incoming_rtx) == REG)
-#endif
         emit_move_insn (last_ptr, static_chain_incoming_rtx);
     }
 
@@ -5223,6 +5644,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;
@@ -5263,7 +5685,7 @@ expand_function_start (subr, parms_have_cleanups)
       if (value_address)
        {
          DECL_RTL (DECL_RESULT (subr))
-           = gen_rtx (MEM, DECL_MODE (DECL_RESULT (subr)), value_address);
+           = 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)));
        }
@@ -5271,7 +5693,7 @@ expand_function_start (subr, parms_have_cleanups)
   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,
@@ -5315,14 +5737,12 @@ expand_function_start (subr, parms_have_cleanups)
 
   assign_parms (subr, 0);
 
-#ifdef SMALL_REGISTER_CLASSES
   /* Copy the static chain now if it wasn't a register.  The delay is to
      avoid conflicts with the parameter passing registers.  */
 
   if (SMALL_REGISTER_CLASSES && current_function_needs_context)
       if (GET_CODE (static_chain_incoming_rtx) != REG)
         emit_move_insn (last_ptr, static_chain_incoming_rtx);
-#endif
 
   /* The following was moved from init_function_start.
      The move is supposed to make sdb output more accurate.  */
@@ -5357,15 +5777,12 @@ expand_function_start (subr, parms_have_cleanups)
         generated above.  */
       if (tem && ! obey_regdecls)
        {
-#ifdef SMALL_REGISTER_CLASSES
          /* If the static chain originally came in a register, put it back
             there, then move it out in the next insn.  The reason for
             this peculiar code is to satisfy function integration.  */
          if (SMALL_REGISTER_CLASSES
              && GET_CODE (static_chain_incoming_rtx) == REG)
            emit_move_insn (static_chain_incoming_rtx, last_ptr);
-#endif
-
          last_ptr = copy_to_reg (static_chain_incoming_rtx);
        }
 
@@ -5383,17 +5800,32 @@ expand_function_start (subr, parms_have_cleanups)
 #ifdef FRAME_GROWS_DOWNWARD
          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 = copy_to_reg (gen_rtx_MEM (Pmode,
+                                              memory_address (Pmode, last_ptr)));
 
          /* If we are not optimizing, ensure that we know that this
             piece of context is live over the entire function.  */
          if (! optimize)
-           save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, last_ptr,
-                                     save_expr_regs);
+           save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, last_ptr,
+                                               save_expr_regs);
        }
     }
 
+  if (current_function_instrument_entry_exit)
+    {
+      rtx fun = DECL_RTL (current_function_decl);
+      if (GET_CODE (fun) == MEM)
+       fun = XEXP (fun, 0);
+      else
+       abort ();
+      emit_library_call (profile_function_entry_libfunc, 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.  */
@@ -5402,7 +5834,8 @@ expand_function_start (subr, parms_have_cleanups)
   /* Evaluate now the sizes of any types declared among the arguments.  */
   for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
     {
-      expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
+      expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode,
+                  EXPAND_MEMORY_USE_BAD);
       /* Flush the queue in case this parameter declaration has
         side-effects.  */
       emit_queue ();
@@ -5431,12 +5864,6 @@ expand_function_end (filename, line, end_bindings)
   static rtx initial_trampoline;
 #endif
 
-  if (output_bytecode)
-    {
-      bc_expand_function_end ();
-      return;
-    }
-
 #ifdef NON_SAVING_SETJMP
   /* Don't put any variables in registers if we call setjmp
      on a machine that fails to restore the registers.  */
@@ -5462,7 +5889,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
@@ -5472,7 +5901,7 @@ expand_function_end (filename, line, end_bindings)
        {
          end_temporary_allocation ();
          initial_trampoline
-           = gen_rtx (MEM, BLKmode, assemble_trampoline_template ());
+           = gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
          resume_temporary_allocation ();
        }
 #endif
@@ -5610,6 +6039,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.  */
@@ -5650,7 +6094,12 @@ expand_function_end (filename, line, end_bindings)
                  GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
       emit_move_insn (real_decl_result,
                      DECL_RTL (DECL_RESULT (current_function_decl)));
-      emit_insn (gen_rtx (USE, VOIDmode, real_decl_result));
+      emit_insn (gen_rtx_USE (VOIDmode, real_decl_result));
+
+      /* The delay slot scheduler assumes that current_function_return_rtx
+        holds the hard register containing the return value, not a temporary
+        pseudo.  */
+      current_function_return_rtx = real_decl_result;
     }
 
   /* If returning a structure, arrange to return the address of the value
@@ -5682,6 +6131,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.  */
@@ -5712,6 +6165,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;
@@ -5762,6 +6216,7 @@ contains (insn, vec)
     }
   return 0;
 }
+#endif /* HAVE_prologue || HAVE_epilogue */
 
 /* Generate the prologue and epilogue RTL if the machine supports it.  Thread
    this into place with notes indicating where the prologue ends and where
@@ -5769,12 +6224,12 @@ contains (insn, vec)
 
 void
 thread_prologue_and_epilogue_insns (f)
-     rtx f;
+     rtx f ATTRIBUTE_UNUSED;
 {
 #ifdef HAVE_prologue
   if (HAVE_prologue)
     {
-      rtx head, seq, insn;
+      rtx head, seq;
 
       /* The first insn (a NOTE_INSN_DELETED) is followed by zero or more
         prologue insns and a NOTE_INSN_PROLOGUE_END.  */
@@ -5870,7 +6325,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.  */
@@ -5901,17 +6356,24 @@ reposition_prologue_and_epilogue_notes (f)
                     move it to just after the last prologue insn.  */
                  if (note == 0)
                    {
-                     for (note = insn; note = NEXT_INSN (note);)
+                     for (note = insn; (note = NEXT_INSN (note));)
                        if (GET_CODE (note) == NOTE
                            && NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
                          break;
                    }
+
                  next = NEXT_INSN (note);
                  prev = PREV_INSN (note);
                  if (prev)
                    NEXT_INSN (prev) = next;
                  if (next)
                    PREV_INSN (next) = prev;
+
+                 /* Whether or not we can depend on basic_block_head, 
+                    attempt to keep it up-to-date.  */
+                 if (basic_block_head[0] == note)
+                   basic_block_head[0] = next;
+
                  add_insn_after (note, insn);
                }
            }
@@ -5939,7 +6401,7 @@ reposition_prologue_and_epilogue_notes (f)
                     move it to just before the first epilogue insn.  */
                  if (note == 0)
                    {
-                     for (note = insn; note = PREV_INSN (note);)
+                     for (note = insn; (note = PREV_INSN (note));)
                        if (GET_CODE (note) == NOTE
                            && NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
                          break;
@@ -5950,7 +6412,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 basic_block_head, 
+                    attempt to keep it up-to-date.  */
+                 if (n_basic_blocks
+                     && basic_block_head[n_basic_blocks-1] == insn)
+                   basic_block_head[n_basic_blocks-1] = note;
+
+                 add_insn_before (note, insn);
                }
            }
        }