OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 54c668e..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-95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -39,12 +39,11 @@ 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"
+#include "except.h"
 #include "function.h"
 #include "insn-flags.h"
 #include "expr.h"
@@ -56,12 +55,16 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "basic-block.h"
 #include "obstack.h"
-#include "bytecode.h"
+#include "toplev.h"
+
+#ifndef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
+#endif
 
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
    give the same symbol without quotes for an alternative entry point.  You
-   must define both, or neither. */
+   must define both, or neither.  */
 #ifndef NAME__MAIN
 #define NAME__MAIN "__main"
 #define SYMBOL__MAIN __main
@@ -124,10 +127,28 @@ 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.  */
+int current_function_is_thunk;
+
 /* Nonzero if function being compiled can call alloca,
    either as a subroutine or builtin.  */
 
@@ -154,7 +175,7 @@ int current_function_args_size;
 int current_function_pretend_args_size;
 
 /* # of bytes of outgoing arguments.  If ACCUMULATE_OUTGOING_ARGS is
-   defined, the needed space is pushed by the prologue. */
+   defined, the needed space is pushed by the prologue.  */
 
 int current_function_outgoing_args_size;
 
@@ -182,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;
 
@@ -199,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;
 
@@ -263,7 +294,7 @@ rtx arg_pointer_save_area;
 /* Offset to end of allocated area of stack frame.
    If stack grows down, this is the address of the last stack slot allocated.
    If stack grows up, this is the address for the next slot.  */
-int frame_offset;
+HOST_WIDE_INT frame_offset;
 
 /* List (chain of TREE_LISTs) of static chains for containing functions.
    Each link has a FUNCTION_DECL in the TREE_PURPOSE and a reg rtx
@@ -291,21 +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 0  /* Turned off because 0 seems to work just as well.  */
-/* Cleanup lists are required for binding levels regardless of whether
-   that binding level has cleanups or not.  This node serves as the
-   cleanup list whenever an empty list is required.  */
-static tree empty_cleanup_list;
-#endif
+   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.  */
@@ -314,8 +339,8 @@ static int virtuals_instantiated;
 /* These variables hold pointers to functions to
    save and restore machine-specific data,
    in push_function_context and pop_function_context.  */
-void (*save_machine_status) ();
-void (*restore_machine_status) ();
+void (*save_machine_status) PROTO((struct function *));
+void (*restore_machine_status) PROTO((struct function *));
 
 /* Nonzero if we need to distinguish between the return value of this function
    and the return value of a function called by this function.  This helps
@@ -323,10 +348,6 @@ void (*restore_machine_status) ();
 
 extern int rtx_equal_function_value_matters;
 extern tree sequence_rtl_expr;
-extern tree bc_runtime_type_code ();
-extern rtx bc_build_calldesc ();
-extern char *bc_emit_trampoline ();
-extern char *bc_end_function ();
 \f
 /* In order to evaluate some expressions, such as function calls returning
    structures in memory, we need to temporarily allocate stack locations.
@@ -350,13 +371,13 @@ struct temp_slot
 {
   /* Points to next temporary slot.  */
   struct temp_slot *next;
-  /* The rtx to used to reference the slot. */
+  /* The rtx to used to reference the slot.  */
   rtx slot;
   /* The rtx used to represent the address if not the address of the
      slot above.  May be an EXPR_LIST if multiple addresses exist.  */
   rtx address;
   /* The 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.  */
@@ -369,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.  */
@@ -382,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;
@@ -422,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));
@@ -443,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;
@@ -463,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 ();
 }
 
@@ -488,6 +506,7 @@ push_function_context_to (context)
   p->pops_args = current_function_pops_args;
   p->returns_struct = current_function_returns_struct;
   p->returns_pcc_struct = current_function_returns_pcc_struct;
+  p->returns_pointer = current_function_returns_pointer;
   p->needs_context = current_function_needs_context;
   p->calls_setjmp = current_function_calls_setjmp;
   p->calls_longjmp = current_function_calls_longjmp;
@@ -495,6 +514,7 @@ push_function_context_to (context)
   p->has_nonlocal_label = current_function_has_nonlocal_label;
   p->has_nonlocal_goto = current_function_has_nonlocal_goto;
   p->contains_functions = current_function_contains_functions;
+  p->is_thunk = current_function_is_thunk;
   p->args_size = current_function_args_size;
   p->pretend_args_size = current_function_pretend_args_size;
   p->arg_offset_rtx = current_function_arg_offset_rtx;
@@ -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,17 +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);
 }
@@ -555,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;
 
@@ -566,12 +591,14 @@ pop_function_context_from (context)
   current_function_pops_args = p->pops_args;
   current_function_returns_struct = p->returns_struct;
   current_function_returns_pcc_struct = p->returns_pcc_struct;
+  current_function_returns_pointer = p->returns_pointer;
   current_function_needs_context = p->needs_context;
   current_function_calls_setjmp = p->calls_setjmp;
   current_function_calls_longjmp = p->calls_longjmp;
   current_function_calls_alloca = p->calls_alloca;
   current_function_has_nonlocal_label = p->has_nonlocal_label;
   current_function_has_nonlocal_goto = p->has_nonlocal_goto;
+  current_function_is_thunk = p->is_thunk;
   current_function_args_size = p->args_size;
   current_function_pretend_args_size = p->pretend_args_size;
   current_function_arg_offset_rtx = p->arg_offset_rtx;
@@ -580,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;
@@ -603,10 +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);
@@ -618,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);
 
@@ -642,7 +672,7 @@ void pop_function_context ()
    This size counts from zero.  It is not rounded to STACK_BOUNDARY;
    the caller may have to do that.  */
 
-int
+HOST_WIDE_INT
 get_frame_size ()
 {
 #ifdef FRAME_GROWS_DOWNWARD
@@ -665,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;
@@ -720,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;
 }
@@ -731,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;
 {
@@ -782,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 ();
 
@@ -802,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;
@@ -841,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)
            {
@@ -850,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;
@@ -872,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
@@ -889,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;
@@ -911,11 +947,21 @@ 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;
       p->keep = keep;
     }
+
+  /* We may be reusing an old slot, so clear any MEM flags that may have been
+     set from before.  */
+  RTX_UNCHANGING_P (p->slot) = 0;
+  MEM_IN_STRUCT_P (p->slot) = 0;
   return p->slot;
 }
 \f
@@ -938,13 +984,13 @@ 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
         temporaries.  However, sometimes we have a fixed upper limit on
         the size (which is stored in TYPE_ARRAY_MAX_SIZE) and can use that
-        instead.  This is the case for Chill variable-sized strings. */
+        instead.  This is the case for Chill variable-sized strings.  */
       if (size == -1 && TREE_CODE (type) == ARRAY_TYPE
          && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE
          && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type)) == INTEGER_CST)
@@ -974,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)
          {
@@ -1019,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.  */
@@ -1037,8 +1087,14 @@ find_temp_slot_from_address (x)
     {
       if (! p->in_use)
        continue;
+
       else if (XEXP (p->slot, 0) == x
-              || p->address == x)
+              || p->address == x
+              || (GET_CODE (x) == PLUS
+                  && XEXP (x, 0) == virtual_stack_vars_rtx
+                  && GET_CODE (XEXP (x, 1)) == CONST_INT
+                  && INTVAL (XEXP (x, 1)) >= p->base_offset
+                  && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size))
        return p;
 
       else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST)
@@ -1051,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)
@@ -1067,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);
     }
 }
 
@@ -1231,6 +1287,21 @@ free_temps_for_rtl_expr (t)
   combine_temp_slots ();
 }
 
+/* Mark all temporaries ever allocated in this function as not suitable
+   for reuse until the current level is exited.  */
+
+void
+mark_all_temps_used ()
+{
+  struct temp_slot *p;
+
+  for (p = temp_slots; p; p = p->next)
+    {
+      p->in_use = p->keep = 1;
+      p->level = MIN (p->level, temp_slot_level);
+    }
+}
+
 /* Push deeper into the nesting level for stack temporaries.  */
 
 void
@@ -1239,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.  */
 
@@ -1264,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
@@ -1278,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
@@ -1301,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;
@@ -1317,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.
@@ -1331,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.  */
@@ -1352,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);
     }
@@ -1393,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;
 
@@ -1417,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));
 }
@@ -1463,7 +1626,7 @@ fixup_var_refs (var, promoted_mode, unsignedp)
 \f
 /* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
    some part of an insn.  Return a struct fixup_replacement whose OLD
-   value is equal to X.  Allocate a new structure if no such entry exists. */
+   value is equal to X.  Allocate a new structure if no such entry exists.  */
 
 static struct fixup_replacement *
 find_fixup_replacement (replacements, x)
@@ -1505,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.
@@ -1513,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
@@ -1531,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.  */
@@ -1553,42 +1729,43 @@ 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 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.  */
-
-             if (call_dest != 0 && GET_CODE (insn) == INSN
-                 && reg_mentioned_p (var, PATTERN (insn))
-                 && reg_mentioned_p (call_dest, PATTERN (insn)))
+             if (SMALL_REGISTER_CLASSES)
                {
-                 rtx temp = gen_reg_rtx (GET_MODE (call_dest));
+                 /* 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.
+
+                    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 (call_dest != 0 && GET_CODE (insn) == INSN
+                     && reg_mentioned_p (var, PATTERN (insn))
+                     && reg_mentioned_p (call_dest, PATTERN (insn)))
+                   {
+                     rtx temp = gen_reg_rtx (GET_MODE (call_dest));
 
-                 emit_insn_before (gen_move_insn (temp, call_dest), insn);
+                     emit_insn_before (gen_move_insn (temp, call_dest), insn);
 
-                 PATTERN (insn) = replace_rtx (PATTERN (insn),
-                                               call_dest, temp);
-               }
+                     PATTERN (insn) = replace_rtx (PATTERN (insn),
+                                                   call_dest, temp);
+                   }
              
-             if (GET_CODE (insn) == CALL_INSN
-                 && GET_CODE (PATTERN (insn)) == SET)
-               call_dest = SET_DEST (PATTERN (insn));
-             else if (GET_CODE (insn) == CALL_INSN
-                      && GET_CODE (PATTERN (insn)) == PARALLEL
-                      && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
-               call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
-             else
-               call_dest = 0;
-#endif
+                 if (GET_CODE (insn) == CALL_INSN
+                     && GET_CODE (PATTERN (insn)) == SET)
+                   call_dest = SET_DEST (PATTERN (insn));
+                 else if (GET_CODE (insn) == CALL_INSN
+                          && GET_CODE (PATTERN (insn)) == PARALLEL
+                          && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
+                   call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+                 else
+                   call_dest = 0;
+               }
 
              /* 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
@@ -1691,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)
        {
@@ -1758,8 +1956,20 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
          tem = XEXP (x, 0);
          if (GET_CODE (tem) == SUBREG)
-           tem = fixup_memory_subreg (tem, insn, 1);
-         tem = fixup_stack_1 (tem, insn);
+           {
+             if (GET_MODE_BITSIZE (GET_MODE (tem))
+                 > GET_MODE_BITSIZE (GET_MODE (var)))
+               {
+                 replacement = find_fixup_replacement (replacements, var);
+                 if (replacement->new == 0)
+                   replacement->new = gen_reg_rtx (GET_MODE (var));
+                 SUBREG_REG (tem) = replacement->new;
+               }
+             else
+               tem = fixup_memory_subreg (tem, insn, 0);
+           }
+         else
+           tem = fixup_stack_1 (tem, insn);
 
          /* Unless we want to load from memory, get TEM into the proper mode
             for an extract from memory.  This can only be done if the
@@ -1772,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;
 
@@ -1799,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);
@@ -1888,8 +2105,24 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          || GET_CODE (SET_SRC (x)) == ZERO_EXTRACT)
        optimize_bit_field (x, insn, NULL_PTR);
 
+      /* For a paradoxical SUBREG inside a ZERO_EXTRACT, load the object
+        into a register and then store it back out.  */
+      if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
+         && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG
+         && SUBREG_REG (XEXP (SET_DEST (x), 0)) == var
+         && (GET_MODE_SIZE (GET_MODE (XEXP (SET_DEST (x), 0)))
+             > GET_MODE_SIZE (GET_MODE (var))))
+       {
+         replacement = find_fixup_replacement (replacements, var);
+         if (replacement->new == 0)
+           replacement->new = gen_reg_rtx (GET_MODE (var));
+
+         SUBREG_REG (XEXP (SET_DEST (x), 0)) = replacement->new;
+         emit_insn_after (gen_move_insn (var, replacement->new), insn);
+       }
+
       /* If SET_DEST is now a paradoxical SUBREG, put the result of this
-        insn into a pseudo and store the low part of the pseudo into VAR. */
+        insn into a pseudo and store the low part of the pseudo into VAR.  */
       if (GET_CODE (SET_DEST (x)) == SUBREG
          && SUBREG_REG (SET_DEST (x)) == var
          && (GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
@@ -1905,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
@@ -1943,7 +2178,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
               This was legitimate when the MEM was a REG.  */
            if (GET_CODE (tem) == SUBREG
                && SUBREG_REG (tem) == var)
-             tem = fixup_memory_subreg (tem, insn, 1);
+             tem = fixup_memory_subreg (tem, insn, 0);
            else
              tem = fixup_stack_1 (tem, insn);
 
@@ -1952,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;
 
@@ -1971,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);
@@ -2137,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.  */
@@ -2161,7 +2401,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
    If any insns must be emitted to compute NEWADDR, put them before INSN.
 
    UNCRITICAL nonzero means accept paradoxical subregs.
-   This is used for subregs found inside of ZERO_EXTRACTs and in REG_NOTES. */
+   This is used for subregs found inside REG_NOTES.  */
 
 static rtx
 fixup_memory_subreg (x, insn, uncritical)
@@ -2172,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)))
@@ -2262,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)
        {
@@ -2357,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.  */
@@ -2464,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.  */
@@ -2502,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.  */
 
@@ -2511,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
@@ -2537,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);
@@ -2569,13 +3096,18 @@ instantiate_decls (fndecl, valid_only)
   /* Process all parameters of the function.  */
   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
     {
-      instantiate_decl (DECL_RTL (decl), int_size_in_bytes (TREE_TYPE (decl)),
-                       valid_only);    
-      instantiate_decl (DECL_INCOMING_RTL (decl),
-                       int_size_in_bytes (TREE_TYPE (decl)), valid_only);
+      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
+        larger than the declared type size.  We must use the larger of
+        the two sizes.  */
+      size = MAX (GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl))), size);
+      instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
     }
 
-  /* Now process all variables defined in the function or its subblocks. */
+  /* Now process all variables defined in the function or its subblocks.  */
   instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
 
   if (DECL_INLINE (fndecl) || DECL_DEFER_OUTPUT (fndecl))
@@ -2630,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)))
@@ -2645,28 +3178,28 @@ instantiate_decl (x, size, valid_only)
 
   instantiate_virtual_regs_1 (&addr, NULL_RTX, 0);
 
-  if (! valid_only)
-    return;
-
-  /* Now verify that the resulting address is valid for every integer or
-     floating-point mode up to and including SIZE bytes long.  We do this
-     since the object might be accessed in any mode and frame addresses
-     are shared.  */
-
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-       mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
-       mode = GET_MODE_WIDER_MODE (mode))
-    if (! memory_address_p (mode, addr))
-      return;
+  if (valid_only)
+    {
+      /* Now verify that the resulting address is valid for every integer or
+        floating-point mode up to and including SIZE bytes long.  We do this
+        since the object might be accessed in any mode and frame addresses
+        are shared.  */
+
+      for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+          mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
+          mode = GET_MODE_WIDER_MODE (mode))
+       if (! memory_address_p (mode, addr))
+         return;
 
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
-       mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
-       mode = GET_MODE_WIDER_MODE (mode))
-    if (! memory_address_p (mode, addr))
-      return;
+      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+          mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
+          mode = GET_MODE_WIDER_MODE (mode))
+       if (! memory_address_p (mode, addr))
+         return;
+    }
 
-  /* Otherwise, put back the address, now that we have updated it and we
-     know it is valid.  */
+  /* Put back the address now that we have updated it and we either know
+     it is valid or we don't care whether it is valid.  */
 
   XEXP (x, 0) = addr;
 }
@@ -2694,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;
@@ -2727,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)
@@ -2738,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)
        {
@@ -2759,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 ();
 
@@ -2789,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);
@@ -2797,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)
@@ -2808,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
@@ -2834,7 +3373,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
             in the case of old offset equals new just changing the register
             will yield a valid insn.  In the interests of a little efficiency,
             however, we only call validate change once (we don't queue up the
-            changes and then call apply_change_group). */
+            changes and then call apply_change_group).  */
 
          old = XEXP (x, 0);
          if (offset == 0
@@ -2860,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);
@@ -2898,7 +3437,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
 
     case MEM:
       /* Most cases of MEM that convert to valid addresses have already been
-        handled by our scan of regno_reg_rtx.  The only special handling we
+        handled by our scan of decls.  The only special handling we
         need here is to make a copy of the rtx to ensure it isn't being
         shared if we have to change it to a pseudo. 
 
@@ -2956,7 +3495,9 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
             ??? Also note that this can still lose if OBJECT is an insn that
             has less restrictions on an address that some other insn.
             In that case, we will modify the shared address.  This case
-            doesn't seem very likely, though.  */
+            doesn't seem very likely, though.  One case where this could
+            happen is in the case of a USE or CLOBBER reference, but we
+            take care of that below.  */
 
          if (instantiate_virtual_regs_1 (&XEXP (x, 0),
                                          object ? object : x, 0))
@@ -2969,8 +3510,6 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        }
 
       /* Fall through to generic unary operation case.  */
-    case USE:
-    case CLOBBER:
     case SUBREG:
     case STRICT_LOW_PART:
     case NEG:          case NOT:
@@ -2987,6 +3526,23 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
       loc = &XEXP (x, 0);
       goto restart;
 
+    case USE:
+    case CLOBBER:
+      /* If the operand is a MEM, see if the change is a valid MEM.  If not,
+        go ahead and make the invalid one, but do it to a copy.  For a REG,
+        just make the recursive call, since there's no chance of a problem. */
+
+      if ((GET_CODE (XEXP (x, 0)) == MEM
+          && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
+                                         0))
+         || (GET_CODE (XEXP (x, 0)) == REG
+             && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
+       return 1;
+
+      XEXP (x, 0) = copy_rtx (XEXP (x, 0));
+      loc = &XEXP (x, 0);
+      goto restart;
+
     case REG:
       /* Try to replace with a PLUS.  If that doesn't work, compute the sum
         in front of this insn and substitute the temporary.  */
@@ -2998,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)
        {
@@ -3020,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.  */
@@ -3093,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;
 }
@@ -3108,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
@@ -3127,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
@@ -3190,11 +3765,21 @@ aggregate_value_p (exp)
 
   if (RETURN_IN_MEMORY (type))
     return 1;
+  /* Types that are TREE_ADDRESSABLE must be constructed in memory,
+     and thus can't be returned in registers.  */
+  if (TREE_ADDRESSABLE (type))
+    return 1;
   if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
     return 1;
   /* Make sure we have suitable call-clobbered regs to return
      the value in; if not, we must return it in memory.  */
   reg = hard_function_value (type, 0);
+
+  /* If we have something other than a REG (e.g. a PARALLEL), then assume
+     it is OK.  */
+  if (GET_CODE (reg) != REG)
+    return 0;
+
   regno = REGNO (reg);
   nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
   for (i = 0; i < nregs; i++)
@@ -3236,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;
 
@@ -3253,7 +3837,7 @@ assign_parms (fndecl, second_time)
 
   /* Nonzero if function takes extra anonymous args.
      This means the last named arg must be on the stack
-     right before the anonymous ones. */
+     right before the anonymous ones.  */
   int stdarg
     = (TYPE_ARG_TYPES (fntype) != 0
        && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
@@ -3294,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);
@@ -3318,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
@@ -3329,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;
        }
@@ -3370,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
          )
        {
@@ -3383,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
 
@@ -3390,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)
@@ -3439,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);
@@ -3454,15 +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.  */
+            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,
@@ -3482,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)
            {
@@ -3492,9 +4086,19 @@ assign_parms (fndecl, second_time)
                   * (PARM_BOUNDARY / BITS_PER_UNIT));
 
              if (! second_time)
-               move_block_from_reg (REGNO (entry_parm),
-                                    validize_mem (stack_parm), nregs,
-                                    int_size_in_bytes (TREE_TYPE (parm)));
+               {
+                 /* Handle calls that pass values in multiple non-contiguous
+                    locations.  The Irix 6 ABI has examples of this.  */
+                 if (GET_CODE (entry_parm) == PARALLEL)
+                   emit_group_store (validize_mem (stack_parm), entry_parm,
+                                     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,
+                                        int_size_in_bytes (TREE_TYPE (parm)));
+               }
              entry_parm = stack_parm;
            }
        }
@@ -3539,9 +4143,9 @@ 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 this is our second time through, we are done with this parm.  */
       if (second_time)
        continue;
 
@@ -3581,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.  */
@@ -3601,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,
@@ -3618,10 +4223,13 @@ assign_parms (fndecl, second_time)
 
         Set DECL_RTL to that place.  */
 
-      if (nominal_mode == BLKmode)
+      if (nominal_mode == BLKmode || GET_CODE (entry_parm) == PARALLEL)
        {
-         /* If a BLKmode arrives in registers, copy it to a stack slot.  */
-         if (GET_CODE (entry_parm) == REG)
+         /* If a BLKmode arrives in registers, copy it to a stack slot.
+            Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+         if (GET_CODE (entry_parm) == REG
+             || GET_CODE (entry_parm) == PARALLEL)
            {
              int size_stored
                = CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
@@ -3652,10 +4260,18 @@ assign_parms (fndecl, second_time)
              if (TREE_READONLY (parm))
                RTX_UNCHANGING_P (stack_parm) = 1;
 
-             move_block_from_reg (REGNO (entry_parm),
-                                  validize_mem (stack_parm),
-                                  size_stored / UNITS_PER_WORD,
-                                  int_size_in_bytes (TREE_TYPE (parm)));
+             /* Handle calls that pass values in multiple non-contiguous
+                locations.  The Irix 6 ABI has examples of this.  */
+             if (GET_CODE (entry_parm) == PARALLEL)
+               emit_group_store (validize_mem (stack_parm), entry_parm,
+                                 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),
+                                    size_stored / UNITS_PER_WORD,
+                                    int_size_in_bytes (TREE_TYPE (parm)));
            }
          DECL_RTL (parm) = stack_parm;
        }
@@ -3676,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));
 
@@ -3684,14 +4300,14 @@ assign_parms (fndecl, second_time)
            = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
 
          parmreg = gen_reg_rtx (promoted_nominal_mode);
-         REG_USERVAR_P (parmreg) = 1;
+         mark_user_reg (parmreg);
 
          /* If this was an item that we received a pointer to, set DECL_RTL
             appropriately.  */
          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
@@ -3704,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
@@ -3752,7 +4368,7 @@ assign_parms (fndecl, second_time)
              /* We can't use nominal_mode, because it will have been set to
                 Pmode above.  We must use the actual mode of the parm.  */
              parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
-             REG_USERVAR_P (parmreg) = 1;
+             mark_user_reg (parmreg);
              emit_move_insn (parmreg, DECL_RTL (parm));
              DECL_RTL (parm) = parmreg;
              /* STACK_PARM is the pointer, not the parm, and PARMREG is
@@ -3772,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;
@@ -3786,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 ();
@@ -3814,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;
            }
 
@@ -3859,40 +4486,45 @@ assign_parms (fndecl, second_time)
             as we make here would screw up life analysis for it.  */
          if (nominal_mode == passed_mode
              && ! did_conversion
-             && GET_CODE (entry_parm) == MEM
-             && entry_parm == stack_parm
+             && stack_parm != 0
+             && GET_CODE (stack_parm) == MEM
              && stack_offset.var == 0
              && reg_mentioned_p (virtual_incoming_args_rtx,
-                                 XEXP (entry_parm, 0)))
+                                 XEXP (stack_parm, 0)))
            {
              rtx linsn = get_last_insn ();
+             rtx sinsn, set;
 
              /* Mark complex types separately.  */
              if (GET_CODE (parmreg) == CONCAT)
-               {
-                 REG_NOTES (linsn)
-                     = gen_rtx (EXPR_LIST, REG_EQUIV,
-                                parm_reg_stack_loc[regnoi], REG_NOTES (linsn));
-
-                 /* Now search backward for where we set the real part.  */
-                 for (; linsn != 0
-                      && ! reg_referenced_p (parm_reg_stack_loc[regnor],
-                                             PATTERN (linsn));
-                      linsn = prev_nonnote_insn (linsn))
-                   ;
-
-                 REG_NOTES (linsn)
-                     = gen_rtx (EXPR_LIST, REG_EQUIV,
-                                parm_reg_stack_loc[regnor], REG_NOTES (linsn));
-               }
-             else
+               /* Scan backwards for the set of the real and
+                  imaginary parts.  */
+               for (sinsn = linsn; sinsn != 0;
+                    sinsn = prev_nonnote_insn (sinsn))
+                 {
+                   set = single_set (sinsn);
+                   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));
+                   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));
+                 }
+             else if ((set = single_set (linsn)) != 0
+                      && SET_DEST (set) == parmreg)
                REG_NOTES (linsn)
-                = gen_rtx (EXPR_LIST, REG_EQUIV,
-                           entry_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));
@@ -3912,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 ();
@@ -3941,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;
        }
       
@@ -3953,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);
        }
@@ -3968,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;
@@ -3996,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
@@ -4105,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
@@ -4165,8 +4815,8 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     }
   else
     {
-      arg_size_ptr->constant = (- initial_offset_ptr->constant -
-                               offset_ptr->constant); 
+      arg_size_ptr->constant = (- initial_offset_ptr->constant
+                               offset_ptr->constant); 
     }
 #else /* !ARGS_GROW_DOWNWARD */
   pad_to_arg_alignment (initial_offset_ptr, boundary);
@@ -4228,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;
@@ -4255,7 +4906,9 @@ pad_below (offset_ptr, passed_mode, sizetree)
        }
     }
 }
+#endif
 
+#ifdef ARGS_GROW_DOWNWARD
 static tree
 round_down (value, divisor)
      tree value;
@@ -4265,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.
@@ -4286,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");
@@ -4327,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.  */
@@ -4352,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.  */
@@ -4408,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;
@@ -4424,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;
@@ -4455,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);
@@ -4518,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;
@@ -4634,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];
          }
       }
 
@@ -4745,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.  */
@@ -4799,19 +5425,6 @@ init_function_start (subr, filename, line)
      char *filename;
      int line;
 {
-  char *junk;
-
-  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;
@@ -4848,7 +5461,7 @@ init_function_start (subr, filename, line)
 
   init_const_rtx_hash_table ();
 
-  current_function_name = (*decl_printable_name) (subr, &junk);
+  current_function_name = (*decl_printable_name) (subr, 2);
 
   /* Nonzero if this is a nested function that uses a static chain.  */
 
@@ -4866,12 +5479,15 @@ 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;
   current_function_returns_struct = 0;
   current_function_epilogue_delay_list = 0;
   current_function_uses_const_pool = 0;
   current_function_uses_pic_offset_table = 0;
+  current_function_cannot_inline = 0;
 
   /* We have not yet needed to make a label to jump to for tail-recursion.  */
   tail_recursion_label = 0;
@@ -4904,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.
@@ -4964,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.
@@ -5070,29 +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 (GET_CODE (static_chain_incoming_rtx) == REG)
-#endif
+      if (! SMALL_REGISTER_CLASSES
+         || GET_CODE (static_chain_incoming_rtx) == REG)
         emit_move_insn (last_ptr, static_chain_incoming_rtx);
     }
 
@@ -5109,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;
@@ -5149,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)));
        }
@@ -5157,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,
@@ -5201,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 (current_function_needs_context)
+  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.  */
@@ -5243,14 +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 (GET_CODE (static_chain_incoming_rtx) == REG)
+         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);
        }
 
@@ -5268,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.  */
@@ -5286,7 +5833,13 @@ 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 ();
+    }
 
   /* Make sure there is a line number after the function entry setup code.  */
   force_next_line_note ();
@@ -5307,13 +5860,9 @@ expand_function_end (filename, line, end_bindings)
   register int i;
   tree link;
 
+#ifdef TRAMPOLINE_TEMPLATE
   static rtx initial_trampoline;
-
-  if (output_bytecode)
-    {
-      bc_expand_function_end ();
-      return;
-    }
+#endif
 
 #ifdef NON_SAVING_SETJMP
   /* Don't put any variables in registers if we call setjmp
@@ -5340,26 +5889,33 @@ 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
       /* First make sure this compilation has a template for
         initializing trampolines.  */
       if (initial_trampoline == 0)
        {
          end_temporary_allocation ();
          initial_trampoline
-           = gen_rtx (MEM, BLKmode, assemble_trampoline_template ());
+           = gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
          resume_temporary_allocation ();
        }
+#endif
 
       /* Generate insns to initialize the trampoline.  */
       start_sequence ();
-      tramp = change_address (initial_trampoline, BLKmode,
-                             round_trampoline_addr (XEXP (tramp, 0)));
-      emit_block_move (tramp, initial_trampoline, GEN_INT (TRAMPOLINE_SIZE),
-                      FUNCTION_BOUNDARY / BITS_PER_UNIT);
-      INITIALIZE_TRAMPOLINE (XEXP (tramp, 0),
-                            XEXP (DECL_RTL (function), 0), context);
+      tramp = round_trampoline_addr (XEXP (tramp, 0));
+#ifdef TRAMPOLINE_TEMPLATE
+      blktramp = change_address (initial_trampoline, BLKmode, tramp);
+      emit_block_move (blktramp, initial_trampoline,
+                      GEN_INT (TRAMPOLINE_SIZE),
+                      TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
+#endif
+      INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
       seq = get_insns ();
       end_sequence ();
 
@@ -5367,6 +5923,26 @@ expand_function_end (filename, line, end_bindings)
       emit_insns_before (seq, tail_recursion_reentry);
     }
 
+  /* If we are doing stack checking and this function makes calls,
+     do a stack probe at the start of the function to ensure we have enough
+     space for another stack frame.  */
+  if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+    {
+      rtx insn, seq;
+
+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+       if (GET_CODE (insn) == CALL_INSN)
+         {
+           start_sequence ();
+           probe_stack_range (STACK_CHECK_PROTECT,
+                              GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
+           seq = get_insns ();
+           end_sequence ();
+           emit_insns_before (seq, tail_recursion_reentry);
+           break;
+         }
+    }
+
   /* Warn about unused parms if extra warnings were specified.  */
   if (warn_unused && extra_warnings)
     {
@@ -5420,6 +5996,14 @@ expand_function_end (filename, line, end_bindings)
      without returning a value.  */
   emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
 
+  /* Must mark the last line number note in the function, so that the test
+     coverage code can avoid counting the last line twice.  This just tells
+     the code to ignore the immediately following line note, since there
+     already exists a copy of this note somewhere above.  This line number
+     note is still needed for debugging though, so we can't delete it.  */
+  if (flag_test_coverage)
+    emit_note (NULL_PTR, NOTE_REPEATED_LINE_NUMBER);
+
   /* Output a linenumber for the end of the function.
      SDB depends on this.  */
   emit_line_note_force (filename, line);
@@ -5437,6 +6021,39 @@ expand_function_end (filename, line, end_bindings)
   if (end_bindings)
     expand_end_bindings (0, 0, 0);
 
+  /* Now handle any leftover exception regions that may have been
+     created for the parameters.  */
+  {
+    rtx last = get_last_insn ();
+    rtx label;
+
+    expand_leftover_cleanups ();
+
+    /* If the above emitted any code, may sure we jump around it.  */
+    if (last != get_last_insn ())
+      {
+       label = gen_label_rtx ();
+       last = emit_jump_insn_after (gen_jump (label), last);
+       last = emit_barrier_after (last);
+       emit_label (label);
+      }
+  }
+
+  if (current_function_instrument_entry_exit)
+    {
+      rtx fun = DECL_RTL (current_function_decl);
+      if (GET_CODE (fun) == MEM)
+       fun = XEXP (fun, 0);
+      else
+       abort ();
+      emit_library_call (profile_function_exit_libfunc, 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.  */
@@ -5470,9 +6087,19 @@ expand_function_end (filename, line, end_bindings)
                          current_function_decl);
 #endif
       REG_FUNCTION_VALUE_P (real_decl_result) = 1;
+      /* If this is a BLKmode structure being returned in registers, then use
+        the mode computed in expand_return.  */
+      if (GET_MODE (real_decl_result) == BLKmode)
+       PUT_MODE (real_decl_result,
+                 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
@@ -5504,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.  */
@@ -5534,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;
@@ -5584,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
@@ -5591,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.  */
@@ -5692,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.  */
@@ -5723,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);
                }
            }
@@ -5761,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;
@@ -5772,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);
                }
            }
        }