OSDN Git Service

* flow.c (clear_log_links): Use free_INSN_LIST_list, not
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 1c3ee31..553ab91 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
    1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 /* This file handles the generation of rtl code from tree structure
    at the level of the function as a whole.
@@ -45,9 +45,8 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "except.h"
 #include "function.h"
-#include "insn-flags.h"
 #include "expr.h"
-#include "insn-codes.h"
+#include "libfuncs.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "insn-config.h"
@@ -59,10 +58,7 @@ Boston, MA 02111-1307, USA.  */
 #include "hash.h"
 #include "ggc.h"
 #include "tm_p.h"
-
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
+#include "integrate.h"
 
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
@@ -72,10 +68,6 @@ Boston, MA 02111-1307, USA.  */
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
 #endif
 
-#if !defined (PREFERRED_STACK_BOUNDARY) && defined (STACK_BOUNDARY)
-#define PREFERRED_STACK_BOUNDARY STACK_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
@@ -126,8 +118,10 @@ int current_function_sp_is_unchanging;
 int current_function_uses_only_leaf_regs;
 
 /* Nonzero once virtual register instantiation has been done.
-   assign_stack_local uses frame_pointer_rtx when this is nonzero.  */
-static int virtuals_instantiated;
+   assign_stack_local uses frame_pointer_rtx when this is nonzero.
+   calls.c:emit_library_call_value_1 uses it to set up
+   post-instantiation libcalls.  */
+int virtuals_instantiated;
 
 /* These variables hold pointers to functions to create and destroy
    target specific, per-function data structures.  */
@@ -151,9 +145,6 @@ tree inline_function_decl;
 /* The currently compiled function.  */
 struct function *cfun = 0;
 
-/* Global list of all compiled functions.  */
-struct function *all_functions = 0;
-
 /* These arrays record the INSN_UIDs of the prologue and epilogue insns.  */
 static varray_type prologue;
 static varray_type epilogue;
@@ -228,7 +219,8 @@ struct fixup_replacement
   struct fixup_replacement *next;
 };
 
-struct insns_for_mem_entry {
+struct insns_for_mem_entry
+{
   /* The KEY in HE will be a MEM.  */
   struct hash_entry he;
   /* These are the INSNS which reference the MEM.  */
@@ -281,8 +273,9 @@ static void pad_below               PARAMS ((struct args_size *, enum machine_mode,
 static rtx round_trampoline_addr PARAMS ((rtx));
 static rtx adjust_trampoline_addr PARAMS ((rtx));
 static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
-static void reorder_blocks_0   PARAMS ((rtx));
+static void reorder_blocks_0   PARAMS ((tree));
 static void reorder_blocks_1   PARAMS ((rtx, tree, varray_type *));
+static void reorder_fix_fragments PARAMS ((tree));
 static tree blocks_nreverse    PARAMS ((tree));
 static int all_blocks          PARAMS ((tree, tree *));
 static tree *get_block_vector   PARAMS ((tree, int *));
@@ -294,7 +287,7 @@ static int contains         PARAMS ((rtx, varray_type));
 static void emit_return_into_block PARAMS ((basic_block, rtx));
 #endif
 static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
-static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
+static bool purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
                                          struct hash_table *));
 static void purge_single_hard_subreg_set PARAMS ((rtx));
 #ifdef HAVE_epilogue
@@ -305,18 +298,17 @@ static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *,
                                                         struct hash_table *,
                                                         hash_table_key));
 static unsigned long insns_for_mem_hash PARAMS ((hash_table_key));
-static boolean insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
+static bool insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
 static int insns_for_mem_walk   PARAMS ((rtx *, void *));
 static void compute_insns_for_mem PARAMS ((rtx, rtx, struct hash_table *));
-static void mark_temp_slot PARAMS ((struct temp_slot *));
 static void mark_function_status PARAMS ((struct function *));
-static void mark_function_chain PARAMS ((void *));
+static void maybe_mark_struct_function PARAMS ((void *));
 static void prepare_function_start PARAMS ((void));
 static void do_clobber_return_reg PARAMS ((rtx, void *));
 static void do_use_return_reg PARAMS ((rtx, void *));
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
-struct function *outer_function_chain;
+static struct function *outer_function_chain;
 
 /* Given a function decl for a containing function,
    return the `struct function' for it.  */
@@ -327,7 +319,7 @@ find_function_data (decl)
 {
   struct function *p;
 
-  for (p = outer_function_chain; p; p = p->next)
+  for (p = outer_function_chain; p; p = p->outer)
     if (p->decl == decl)
       return p;
 
@@ -344,21 +336,24 @@ void
 push_function_context_to (context)
      tree context;
 {
-  struct function *p, *context_data;
+  struct function *p;
 
   if (context)
     {
-      context_data = (context == current_function_decl
-                     ? cfun
-                     : find_function_data (context));
-      context_data->contains_functions = 1;
+      if (context == current_function_decl)
+       cfun->contains_functions = 1;
+      else
+       {
+         struct function *containing = find_function_data (context);
+         containing->contains_functions = 1;
+       }
     }
 
   if (cfun == 0)
     init_dummy_function_start ();
   p = cfun;
 
-  p->next = outer_function_chain;
+  p->outer = outer_function_chain;
   outer_function_chain = p;
   p->fixup_var_refs_queue = 0;
 
@@ -383,28 +378,25 @@ pop_function_context_from (context)
 {
   struct function *p = outer_function_chain;
   struct var_refs_queue *queue;
-  struct var_refs_queue *next;
 
   cfun = p;
-  outer_function_chain = p->next;
+  outer_function_chain = p->outer;
 
   current_function_decl = p->decl;
   reg_renumber = 0;
 
   restore_emit_status (p);
+  restore_varasm_status (p);
 
   if (restore_lang_status)
     (*restore_lang_status) (p);
 
   /* Finish doing put_var_into_stack for any of our variables
      which became addressable during the nested function.  */
-  for (queue = p->fixup_var_refs_queue; queue; queue = next)
-    {
-      next = queue->next;
-      fixup_var_refs (queue->modified, queue->promoted_mode,
-                     queue->unsignedp, 0);
-      free (queue);
-    }
+  for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
+    fixup_var_refs (queue->modified, queue->promoted_mode,
+                   queue->unsignedp, 0);
+
   p->fixup_var_refs_queue = 0;
 
   /* Reset variables that have known state during rtx generation.  */
@@ -445,9 +437,6 @@ void
 free_after_compilation (f)
      struct function *f;
 {
-  struct temp_slot *ts;
-  struct temp_slot *next;
-
   free_eh_status (f);
   free_expr_status (f);
   free_emit_status (f);
@@ -459,13 +448,7 @@ free_after_compilation (f)
   if (f->x_parm_reg_stack_loc)
     free (f->x_parm_reg_stack_loc);
 
-  for (ts = f->x_temp_slots; ts; ts = next)
-    {
-      next = ts->next;
-      free (ts);
-    }
   f->x_temp_slots = NULL;
-
   f->arg_offset_rtx = NULL;
   f->return_rtx = NULL;
   f->internal_arg_pointer = NULL;
@@ -540,7 +523,7 @@ assign_stack_local_1 (mode, size, align, function)
      int align;
      struct function *function;
 {
-  register rtx x, addr;
+  rtx x, addr;
   int bigend_correction = 0;
   int alignment;
 
@@ -704,7 +687,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
 
          if (best_p->size - rounded_size >= alignment)
            {
-             p = (struct temp_slot *) xmalloc (sizeof (struct temp_slot));
+             p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
              p->in_use = p->addr_taken = 0;
              p->size = best_p->size - rounded_size;
              p->base_offset = best_p->base_offset + rounded_size;
@@ -735,7 +718,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
     {
       HOST_WIDE_INT frame_offset_old = frame_offset;
 
-      p = (struct temp_slot *) xmalloc (sizeof (struct temp_slot));
+      p = (struct temp_slot *) ggc_alloc (sizeof (struct temp_slot));
 
       /* We are passing an explicit alignment request to assign_stack_local.
         One side effect of that is assign_stack_local will not round SIZE
@@ -811,12 +794,9 @@ assign_stack_temp_for_type (mode, size, keep, type)
   /* If we know the alias set for the memory that will be used, use
      it.  If there's no TYPE, then we don't know anything about the
      alias set for the memory.  */
-  if (type)
-    MEM_ALIAS_SET (p->slot) = get_alias_set (type);
-  else
-    MEM_ALIAS_SET (p->slot) = 0;
+  set_mem_alias_set (p->slot, type ? get_alias_set (type) : 0);
 
-  /* If a type is specified, set the relevant flags. */
+  /* If a type is specified, set the relevant flags.  */
   if (type != 0)
     {
       RTX_UNCHANGING_P (p->slot) = TYPE_READONLY (type);
@@ -942,10 +922,7 @@ combine_temp_slots ()
              }
            /* Either delete Q or advance past it.  */
            if (delete_q)
-             {
-               prev_q->next = q->next;
-               free (q);
-             }
+             prev_q->next = q->next;
            else
              prev_q = q;
          }
@@ -1217,7 +1194,7 @@ free_temps_for_rtl_expr (t)
        /* If this slot is below the current TEMP_SLOT_LEVEL, then it
           needs to be preserved.  This can happen if a temporary in
           the RTL_EXPR was addressed; preserve_temp_slots will move
-          the temporary into a higher level.   */
+          the temporary into a higher level.  */
        if (temp_slot_level <= p->level)
          p->in_use = 0;
        else
@@ -1326,7 +1303,7 @@ void
 put_var_into_stack (decl)
      tree decl;
 {
-  register rtx reg;
+  rtx reg;
   enum machine_mode promoted_mode, decl_mode;
   struct function *function = 0;
   tree context;
@@ -1338,7 +1315,9 @@ put_var_into_stack (decl)
   context = decl_function_context (decl);
 
   /* Get the current rtl used for this object and its original mode.  */
-  reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl);
+  reg = (TREE_CODE (decl) == SAVE_EXPR 
+        ? SAVE_EXPR_RTL (decl) 
+        : DECL_RTL_IF_SET (decl));
 
   /* No need to do anything if decl has no rtx yet
      since in that case caller is setting TREE_ADDRESSABLE
@@ -1352,10 +1331,13 @@ put_var_into_stack (decl)
   /* Get the mode it's actually stored in.  */
   promoted_mode = GET_MODE (reg);
 
-  /* If this variable comes from an outer function,
-     find that function's saved context.  */
+  /* If this variable comes from an outer function, find that
+     function's saved context.  Don't use find_function_data here,
+     because it might not be in any active function.
+     FIXME: Is that really supposed to happen?
+     It does in ObjC at least.  */
   if (context != current_function_decl && context != inline_function_decl)
-    for (function = outer_function_chain; function; function = function->next)
+    for (function = outer_function_chain; function; function = function->outer)
       if (function->decl == context)
        break;
 
@@ -1425,7 +1407,15 @@ put_var_into_stack (decl)
 
       /* Change the CONCAT into a combined MEM for both parts.  */
       PUT_CODE (reg, MEM);
+      MEM_ATTRS (reg) = 0;
+
+      /* set_mem_attributes uses DECL_RTL to avoid re-generating of
+         already computed alias sets.  Here we want to re-generate.  */
+      if (DECL_P (decl))
+       SET_DECL_RTL (decl, NULL);
       set_mem_attributes (reg, decl, 1);
+      if (DECL_P (decl))
+       SET_DECL_RTL (decl, reg);
 
       /* The two parts are in memory order already.
         Use the lower parts address as ours.  */
@@ -1488,6 +1478,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
   PUT_CODE (reg, MEM);
   PUT_MODE (reg, decl_mode);
   XEXP (reg, 0) = XEXP (new, 0);
+  MEM_ATTRS (reg) = 0;
   /* `volatil' bit means one thing for MEMs, another entirely for REGs.  */
   MEM_VOLATILE_P (reg) = volatile_p;
 
@@ -1500,8 +1491,9 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
     {
       MEM_SET_IN_STRUCT_P (reg,
                           AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new));
-      MEM_ALIAS_SET (reg) = get_alias_set (type);
+      set_mem_alias_set (reg, get_alias_set (type));
     }
+
   if (used_p)
     schedule_fixup_var_refs (function, reg, type, promoted_mode, ht);
 }
@@ -1525,7 +1517,7 @@ schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
       struct var_refs_queue *temp;
 
       temp
-       = (struct var_refs_queue *) xmalloc (sizeof (struct var_refs_queue));
+       = (struct var_refs_queue *) ggc_alloc (sizeof (struct var_refs_queue));
       temp->modified = reg;
       temp->promoted_mode = promoted_mode;
       temp->unsignedp = unsigned_p;
@@ -1584,11 +1576,6 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
          end_sequence ();
        }
     }
-
-  /* Scan the catch clauses for exception handling too.  */
-  push_to_full_sequence (catch_clauses, catch_clauses_last);
-  fixup_var_refs_insns (catch_clauses, var, promoted_mode, unsignedp, 0);
-  end_full_sequence (&catch_clauses, &catch_clauses_last);
 }
 \f
 /* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
@@ -1673,6 +1660,7 @@ fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel)
    N.B. No need for special processing of CALL_PLACEHOLDERs here,
    because the hash table will point straight to the interesting insn
    (inside the CALL_PLACEHOLDER).  */
+
 static void
 fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp)
      struct hash_table *ht;
@@ -1689,7 +1677,7 @@ fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp)
       rtx insn = XEXP (insn_list, 0);
        
       if (INSN_P (insn))
-       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 0);
+       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 1);
 
       insn_list = XEXP (insn_list, 1);
     }
@@ -1701,6 +1689,7 @@ fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp)
    references to, PROMOTED_MODE and UNSIGNEDP describe VAR, and
    TOPLEVEL is nonzero if this is the main insn chain for this
    function.  */
+
 static void
 fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
      rtx insn;
@@ -1734,11 +1723,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
                     find_reg_note (XEXP (note, 0), REG_RETVAL,
                                    NULL_RTX));
 
-      /* In unoptimized compilation, we shouldn't call delete_insn
-        except in jump.c doing warnings.  */
-      PUT_CODE (insn, NOTE);
-      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (insn) = 0;
+      delete_insn (insn);
     }
 
   /* The insn to load VAR from a home in the arglist
@@ -1759,11 +1744,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
                   && 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.  */
-      PUT_CODE (insn, NOTE);
-      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (insn) = 0;
+      delete_insn (insn);
     }
   else
     {
@@ -1898,17 +1879,17 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
 
 static void
 fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
-     register rtx var;
+     rtx var;
      enum machine_mode promoted_mode;
-     register rtx *loc;
+     rtx *loc;
      rtx insn;
      struct fixup_replacement **replacements;
 {
-  register int i;
-  register rtx x = *loc;
+  int i;
+  rtx x = *loc;
   RTX_CODE code = GET_CODE (x);
-  register const char *fmt;
-  register rtx tem, tem1;
+  const char *fmt;
+  rtx tem, tem1;
   struct fixup_replacement *replacement;
 
   switch (code)
@@ -2067,23 +2048,21 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
              enum machine_mode is_mode = GET_MODE (tem);
              HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
 
-#ifdef HAVE_extzv
              if (GET_CODE (x) == ZERO_EXTRACT)
                {
-                 wanted_mode
-                   = insn_data[(int) CODE_FOR_extzv].operand[1].mode;
-                 if (wanted_mode == VOIDmode)
-                   wanted_mode = word_mode;
+                 enum machine_mode new_mode
+                   = mode_for_extraction (EP_extzv, 1);
+                 if (new_mode != MAX_MACHINE_MODE)
+                   wanted_mode = new_mode;
                }
-#endif
-#ifdef HAVE_extv
-             if (GET_CODE (x) == SIGN_EXTRACT)
+             else if (GET_CODE (x) == SIGN_EXTRACT)
                {
-                 wanted_mode = insn_data[(int) CODE_FOR_extv].operand[1].mode;
-                 if (wanted_mode == VOIDmode)
-                   wanted_mode = word_mode;
+                 enum machine_mode new_mode
+                   = mode_for_extraction (EP_extv, 1);
+                 if (new_mode != MAX_MACHINE_MODE)
+                   wanted_mode = new_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))
@@ -2100,9 +2079,7 @@ 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));
-                 MEM_COPY_ATTRIBUTES (newmem, tem);
+                 newmem = adjust_address_nv (tem, wanted_mode, offset);
 
                  /* Make the change and see if the insn remains valid.  */
                  INSN_CODE (insn) = -1;
@@ -2151,7 +2128,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            {
              replacement = find_fixup_replacement (replacements, var);
              if (replacement->new == 0)
-               replacement->new = gen_reg_rtx (GET_MODE (var));
+               replacement->new = gen_reg_rtx (promoted_mode);
              SUBREG_REG (x) = replacement->new;
              return;
            }
@@ -2185,7 +2162,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
        optimize_bit_field (x, insn, 0);
       if (GET_CODE (SET_SRC (x)) == SIGN_EXTRACT
          || GET_CODE (SET_SRC (x)) == ZERO_EXTRACT)
-       optimize_bit_field (x, insn, NULL_PTR);
+       optimize_bit_field (x, insn, 0);
 
       /* For a paradoxical SUBREG inside a ZERO_EXTRACT, load the object
         into a register and then store it back out.  */
@@ -2220,9 +2197,7 @@ 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
@@ -2230,7 +2205,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          dest = XEXP (dest, 0);
 
        if (GET_CODE (src) == SUBREG)
-         src = XEXP (src, 0);
+         src = SUBREG_REG (src);
 
        /* If VAR does not appear at the top level of the SET
           just scan the lower levels of the tree.  */
@@ -2241,8 +2216,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
        /* We will need to rerecognize this insn.  */
        INSN_CODE (insn) = -1;
 
-#ifdef HAVE_insv
-       if (GET_CODE (outerdest) == ZERO_EXTRACT && dest == var)
+       if (GET_CODE (outerdest) == ZERO_EXTRACT && dest == var
+           && mode_for_extraction (EP_insv, -1) != MAX_MACHINE_MODE)
          {
            /* Since this case will return, ensure we fixup all the
               operands here.  */
@@ -2273,9 +2248,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                enum machine_mode is_mode = GET_MODE (tem);
                HOST_WIDE_INT pos = INTVAL (XEXP (outerdest, 2));
 
-               wanted_mode = insn_data[(int) CODE_FOR_insv].operand[0].mode;
-               if (wanted_mode == VOIDmode)
-                 wanted_mode = word_mode;
+               wanted_mode = mode_for_extraction (EP_insv, 0);
 
                /* If we have a narrower mode, we can do something.  */
                if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
@@ -2290,10 +2263,7 @@ 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));
-                   MEM_COPY_ATTRIBUTES (newmem, tem);
+                   newmem = adjust_address_nv (tem, wanted_mode, offset);
 
                    /* Make the change and see if the insn remains valid.  */
                    INSN_CODE (insn) = -1;
@@ -2319,7 +2289,6 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            XEXP (outerdest, 0) = tem1;
            return;
          }
-#endif
 
        /* STRICT_LOW_PART is a no-op on memory references
           and it can cause combinations to be unrecognizable,
@@ -2387,9 +2356,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  REG_NOTES (insn) = REG_NOTES (last);
                PATTERN (insn) = PATTERN (last);
 
-               PUT_CODE (last, NOTE);
-               NOTE_LINE_NUMBER (last) = NOTE_INSN_DELETED;
-               NOTE_SOURCE_FILE (last) = 0;
+               delete_insn (last);
              }
            else
              PATTERN (insn) = pat;
@@ -2432,9 +2399,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  REG_NOTES (insn) = REG_NOTES (last);
                PATTERN (insn) = PATTERN (last);
 
-               PUT_CODE (last, NOTE);
-               NOTE_LINE_NUMBER (last) = NOTE_INSN_DELETED;
-               NOTE_SOURCE_FILE (last) = 0;
+               delete_insn (last);
              }
            else
              PATTERN (insn) = pat;
@@ -2493,7 +2458,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
        fixup_var_refs_1 (var, promoted_mode, &XEXP (x, i), insn, replacements);
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            fixup_var_refs_1 (var, promoted_mode, &XVECEXP (x, i, j),
                              insn, replacements);
@@ -2514,7 +2479,7 @@ fixup_memory_subreg (x, insn, uncritical)
      rtx insn;
      int uncritical;
 {
-  int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+  int offset = SUBREG_BYTE (x);
   rtx addr = XEXP (SUBREG_REG (x), 0);
   enum machine_mode mode = GET_MODE (x);
   rtx result;
@@ -2524,15 +2489,13 @@ fixup_memory_subreg (x, insn, uncritical)
       && ! uncritical)
     abort ();
 
-  if (BYTES_BIG_ENDIAN)
-    offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-              - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-  addr = plus_constant (addr, offset);
-  if (!flag_force_addr && memory_address_p (mode, addr))
+  if (!flag_force_addr
+      && memory_address_p (mode, plus_constant (addr, offset)))
     /* Shortcut if no insns need be emitted.  */
-    return change_address (SUBREG_REG (x), mode, addr);
+    return adjust_address (SUBREG_REG (x), mode, offset);
+
   start_sequence ();
-  result = change_address (SUBREG_REG (x), mode, addr);
+  result = adjust_address (SUBREG_REG (x), mode, offset);
   emit_insn_before (gen_sequence (), insn);
   end_sequence ();
   return result;
@@ -2549,13 +2512,13 @@ fixup_memory_subreg (x, insn, uncritical)
 
 static rtx
 walk_fixup_memory_subreg (x, insn, uncritical)
-     register rtx x;
+     rtx x;
      rtx insn;
      int uncritical;
 {
-  register enum rtx_code code;
-  register const char *fmt;
-  register int i;
+  enum rtx_code code;
+  const char *fmt;
+  int i;
 
   if (x == 0)
     return 0;
@@ -2574,7 +2537,7 @@ walk_fixup_memory_subreg (x, insn, uncritical)
        XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn, uncritical);
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            XVECEXP (x, i, j)
              = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn, uncritical);
@@ -2594,13 +2557,13 @@ fixup_stack_1 (x, insn)
      rtx x;
      rtx insn;
 {
-  register int i;
-  register RTX_CODE code = GET_CODE (x);
-  register const char *fmt;
+  int i;
+  RTX_CODE code = GET_CODE (x);
+  const char *fmt;
 
   if (code == MEM)
     {
-      register rtx ad = XEXP (x, 0);
+      rtx ad = XEXP (x, 0);
       /* If we have address of a stack slot but it's not valid
         (displacement is too large), compute the sum in a register.  */
       if (GET_CODE (ad) == PLUS
@@ -2625,7 +2588,7 @@ fixup_stack_1 (x, insn)
          seq = gen_sequence ();
          end_sequence ();
          emit_insn_before (seq, insn);
-         return change_address (x, VOIDmode, temp);
+         return replace_equiv_address (x, temp);
        }
       return x;
     }
@@ -2637,7 +2600,7 @@ fixup_stack_1 (x, insn)
        XEXP (x, i) = fixup_stack_1 (XEXP (x, i), insn);
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (x, i); j++)
            XVECEXP (x, i, j) = fixup_stack_1 (XVECEXP (x, i, j), insn);
        }
@@ -2662,7 +2625,7 @@ optimize_bit_field (body, insn, equiv_mem)
      rtx insn;
      rtx *equiv_mem;
 {
-  register rtx bitfield;
+  rtx bitfield;
   int destflag;
   rtx seq = 0;
   enum machine_mode mode;
@@ -2682,7 +2645,7 @@ optimize_bit_field (body, insn, equiv_mem)
          != BLKmode)
       && INTVAL (XEXP (bitfield, 2)) % INTVAL (XEXP (bitfield, 1)) == 0)
     {
-      register rtx memref = 0;
+      rtx memref = 0;
 
       /* Now check that the containing word is memory, not a register,
         and that it is safe to change the machine mode.  */
@@ -2720,7 +2683,8 @@ optimize_bit_field (body, insn, equiv_mem)
          offset /= BITS_PER_UNIT;
          if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
            {
-             offset += SUBREG_WORD (XEXP (bitfield, 0)) * UNITS_PER_WORD;
+             offset += (SUBREG_BYTE (XEXP (bitfield, 0))
+                        / UNITS_PER_WORD) * UNITS_PER_WORD;
              if (BYTES_BIG_ENDIAN)
                offset -= (MIN (UNITS_PER_WORD,
                                GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
@@ -2729,8 +2693,7 @@ optimize_bit_field (body, insn, equiv_mem)
            }
 
          start_sequence ();
-         memref = change_address (memref, mode,
-                                  plus_constant (XEXP (memref, 0), offset));
+         memref = adjust_address (memref, mode, offset);
          insns = get_insns ();
          end_sequence ();
          emit_insns_before (insns, insn);
@@ -2745,7 +2708,7 @@ optimize_bit_field (body, insn, equiv_mem)
                {
                  rtx src = SET_SRC (body);
                  while (GET_CODE (src) == SUBREG
-                        && SUBREG_WORD (src) == 0)
+                        && SUBREG_BYTE (src) == 0)
                    src = SUBREG_REG (src);
                  if (GET_MODE (src) != GET_MODE (memref))
                    src = gen_lowpart (GET_MODE (memref), SET_SRC (body));
@@ -2766,7 +2729,7 @@ optimize_bit_field (body, insn, equiv_mem)
              rtx dest = SET_DEST (body);
 
              while (GET_CODE (dest) == SUBREG
-                    && SUBREG_WORD (dest) == 0
+                    && SUBREG_BYTE (dest) == 0
                     && (GET_MODE_CLASS (GET_MODE (dest))
                         == GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest))))
                     && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
@@ -2872,32 +2835,44 @@ gen_mem_addressof (reg, decl)
   rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)),
                             REGNO (reg), decl);
 
+  /* Calculate this before we start messing with decl's RTL.  */
+  HOST_WIDE_INT set = decl ? get_alias_set (decl) : 0;
+
   /* If the original REG was a user-variable, then so is the REG whose
      address is being taken.  Likewise for unchanging.  */
   REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
   RTX_UNCHANGING_P (XEXP (r, 0)) = RTX_UNCHANGING_P (reg);
 
   PUT_CODE (reg, MEM);
+  MEM_ATTRS (reg) = 0;
   XEXP (reg, 0) = r;
+
   if (decl)
     {
       tree type = TREE_TYPE (decl);
+      enum machine_mode decl_mode
+       = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl))
+          : DECL_MODE (decl));
+      rtx decl_rtl = decl ? DECL_RTL_IF_SET (decl) : 0;
 
-      PUT_MODE (reg, DECL_MODE (decl));
-      MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
-      MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (type));
-      MEM_ALIAS_SET (reg) = get_alias_set (decl);
+      PUT_MODE (reg, decl_mode);
+
+      /* Clear DECL_RTL momentarily so functions below will work
+        properly, then set it again.  */
+      if (decl_rtl == reg)
+       SET_DECL_RTL (decl, 0);
+
+      set_mem_attributes (reg, decl, 1);
+      set_mem_alias_set (reg, set);
+
+      if (decl_rtl == reg)
+       SET_DECL_RTL (decl, reg);
 
       if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
        fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type), 0);
     }
   else
-    {
-      /* We have no alias information about this newly created MEM.  */
-      MEM_ALIAS_SET (reg) = 0;
-
-      fixup_var_refs (reg, GET_MODE (reg), 0, 0);
-    }
+    fixup_var_refs (reg, GET_MODE (reg), 0, 0);
 
   return reg;
 }
@@ -2969,7 +2944,7 @@ static rtx purge_addressof_replacements;
    the stack.  If the function returns FALSE then the replacement could not
    be made.  */
 
-static boolean
+static bool
 purge_addressof_1 (loc, insn, force, store, ht)
      rtx *loc;
      rtx insn;
@@ -2980,7 +2955,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
   RTX_CODE code;
   int i, j;
   const char *fmt;
-  boolean result = true;
+  bool result = true;
 
   /* Re-start here to avoid recursion in common cases.  */
  restart:
@@ -3000,14 +2975,19 @@ purge_addressof_1 (loc, insn, force, store, ht)
       result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
       return result;
     }
-
-  else if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
+  else if (code == ADDRESSOF)
     {
+      rtx sub, insns;
+
+      if (GET_CODE (XEXP (x, 0)) != MEM)
+       {
+         put_addressof_into_stack (x, ht);
+         return true;
+       }
+         
       /* 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));
-      rtx insns;
-
+      sub = copy_rtx (XEXP (XEXP (x, 0), 0));
       if (validate_change (insn, loc, sub, 0)
          || validate_replace_rtx (x, sub, insn))
        return true;
@@ -3027,14 +3007,9 @@ purge_addressof_1 (loc, insn, force, store, ht)
   else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
     {
       rtx sub = XEXP (XEXP (x, 0), 0);
-      rtx sub2;
 
       if (GET_CODE (sub) == MEM)
-       {
-         sub2 = gen_rtx_MEM (GET_MODE (x), copy_rtx (XEXP (sub, 0)));
-         MEM_COPY_ATTRIBUTES (sub2, sub);
-         sub = sub2;
-       }
+       sub = adjust_address_nv (sub, GET_MODE (x), 0);
       else if (GET_CODE (sub) == REG
               && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
        ;
@@ -3076,7 +3051,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
                       code did.  This is especially true of
                       REG_RETVAL.  */
 
-                   if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0)
+                   if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0)
                      z = SUBREG_REG (z);
 
                    if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
@@ -3219,22 +3194,9 @@ purge_addressof_1 (loc, insn, force, store, ht)
            }
          goto restart;
        }
-    give_up:;
-      /* else give up and put it into the stack */
-    }
-
-  else if (code == ADDRESSOF)
-    {
-      put_addressof_into_stack (x, ht);
-      return true;
-    }
-  else if (code == SET)
-    {
-      result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
-      result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
-      return result;
     }
 
+ give_up:
   /* Scan all subexpressions.  */
   fmt = GET_RTX_FORMAT (code);
   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
@@ -3280,7 +3242,7 @@ insns_for_mem_hash (k)
 
 /* Return non-zero if K1 and K2 (two REGs) are the same.  */
 
-static boolean
+static bool
 insns_for_mem_comp (k1, k2)
      hash_table_key k1;
      hash_table_key k2;
@@ -3288,7 +3250,8 @@ insns_for_mem_comp (k1, k2)
   return k1 == k2;
 }
 
-struct insns_for_mem_walk_info {
+struct insns_for_mem_walk_info
+{
   /* The hash table that we are using to record which INSNs use which
      MEMs.  */
   struct hash_table *ht;
@@ -3361,6 +3324,7 @@ compute_insns_for_mem (insns, last_insn, ht)
 
 /* Helper function for purge_addressof called through for_each_rtx.
    Returns true iff the rtl is an ADDRESSOF.  */
+
 static int
 is_addressof (rtl, data)
      rtx *rtl;
@@ -3452,17 +3416,22 @@ purge_single_hard_subreg_set (pattern)
 {
   rtx reg = SET_DEST (pattern);
   enum machine_mode mode = GET_MODE (SET_DEST (pattern));
-  int word = 0;
-                 
-  while (GET_CODE (reg) == SUBREG)
+  int offset = 0;
+
+  if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG
+      && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
     {
-      word += SUBREG_WORD (reg);
+      offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
+                                   GET_MODE (SUBREG_REG (reg)),
+                                   SUBREG_BYTE (reg),
+                                   GET_MODE (reg));
       reg = SUBREG_REG (reg);
     }
-             
-  if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
+
+                 
+  if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER)
     {
-      reg = gen_rtx_REG (mode, REGNO (reg) + word);
+      reg = gen_rtx_REG (mode, REGNO (reg) + offset);
       SET_DEST (pattern) = reg;
     }
 }
@@ -3581,13 +3550,15 @@ instantiate_decls (fndecl, valid_only)
   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
     {
       HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+      HOST_WIDE_INT size_rtl;
 
       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);
+      size_rtl = GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl)));
+      size = MAX (size_rtl, size);
       instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
     }
 
@@ -3606,8 +3577,10 @@ instantiate_decls_1 (let, valid_only)
   tree t;
 
   for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
-    instantiate_decl (DECL_RTL (t), int_size_in_bytes (TREE_TYPE (t)),
-                     valid_only);
+    if (DECL_RTL_SET_P (t))
+      instantiate_decl (DECL_RTL (t), 
+                       int_size_in_bytes (TREE_TYPE (t)),
+                       valid_only);
 
   /* Process all subblocks.  */
   for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
@@ -4150,7 +4123,7 @@ delete_handlers ()
              || (nonlocal_goto_stack_level != 0
                  && reg_mentioned_p (nonlocal_goto_stack_level,
                                      PATTERN (insn))))
-           delete_insn (insn);
+           delete_related_insns (insn);
        }
     }
 }
@@ -4177,8 +4150,8 @@ get_first_nonparm_insn ()
 rtx
 get_first_block_beg ()
 {
-  register rtx searcher;
-  register rtx insn = get_first_nonparm_insn ();
+  rtx searcher;
+  rtx insn = get_first_nonparm_insn ();
 
   for (searcher = insn; searcher; searcher = NEXT_INSN (searcher))
     if (GET_CODE (searcher) == NOTE
@@ -4238,9 +4211,9 @@ void
 assign_parms (fndecl)
      tree fndecl;
 {
-  register tree parm;
-  register rtx entry_parm = 0;
-  register rtx stack_parm = 0;
+  tree parm;
+  rtx entry_parm = 0;
+  rtx stack_parm = 0;
   CUMULATIVE_ARGS args_so_far;
   enum machine_mode promoted_mode, passed_mode;
   enum machine_mode nominal_mode, promoted_nominal_mode;
@@ -4353,8 +4326,8 @@ assign_parms (fndecl)
          || TREE_CODE (parm) != PARM_DECL
          || passed_type == NULL)
        {
-         DECL_INCOMING_RTL (parm) = DECL_RTL (parm)
-           = gen_rtx_MEM (BLKmode, const0_rtx);
+         SET_DECL_RTL (parm, gen_rtx_MEM (BLKmode, const0_rtx));
+         DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
          TREE_USED (parm) = 1;
          continue;
        }
@@ -4373,7 +4346,8 @@ assign_parms (fndecl)
         and avoid the usual things like emit_move_insn that could crash.  */
       if (nominal_mode == VOIDmode)
        {
-         DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = const0_rtx;
+         SET_DECL_RTL (parm, const0_rtx);
+         DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
          continue;
        }
 
@@ -4669,7 +4643,7 @@ assign_parms (fndecl)
                                     size_stored / UNITS_PER_WORD,
                                     int_size_in_bytes (TREE_TYPE (parm)));
            }
-         DECL_RTL (parm) = stack_parm;
+         SET_DECL_RTL (parm, stack_parm);
        }
       else if (! ((! optimize
                   && ! DECL_REGISTER (parm)
@@ -4686,7 +4660,7 @@ assign_parms (fndecl)
          /* Store the parm in a pseudoregister during the function, but we
             may need to do it in a wider mode.  */
 
-         register rtx parmreg;
+         rtx parmreg;
          unsigned int regno, regnoi = 0, regnor = 0;
 
          unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
@@ -4701,13 +4675,14 @@ assign_parms (fndecl)
             appropriately.  */
          if (passed_pointer)
            {
-             DECL_RTL (parm)
-               = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
-             set_mem_attributes (DECL_RTL (parm), parm, 1);
+             rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)),
+                                  parmreg);
+             set_mem_attributes (x, parm, 1);
+             SET_DECL_RTL (parm, x);
            }
          else
            {
-             DECL_RTL (parm) = parmreg;
+             SET_DECL_RTL (parm, parmreg);
              maybe_set_unchanging (DECL_RTL (parm), parm);
            }
              
@@ -4742,6 +4717,20 @@ assign_parms (fndecl)
              push_to_sequence (conversion_insns);
              tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
 
+             if (GET_CODE (tempreg) == SUBREG
+                 && GET_MODE (tempreg) == nominal_mode
+                 && GET_CODE (SUBREG_REG (tempreg)) == REG
+                 && nominal_mode == passed_mode
+                 && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm)
+                 && GET_MODE_SIZE (GET_MODE (tempreg))
+                    < GET_MODE_SIZE (GET_MODE (entry_parm)))
+               {
+                 /* The argument is already sign/zero extended, so note it
+                    into the subreg.  */
+                 SUBREG_PROMOTED_VAR_P (tempreg) = 1;
+                 SUBREG_PROMOTED_UNSIGNED_P (tempreg) = unsignedp;
+               }
+
              /* TREE_USED gets set erroneously during expand_assignment.  */
              save_tree_used = TREE_USED (parm);
              expand_assignment (parm,
@@ -4773,12 +4762,13 @@ assign_parms (fndecl)
              if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm)))
                {
                  rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm)));
-
+                 int unsigned_p = TREE_UNSIGNED (TREE_TYPE (parm));
                  push_to_sequence (conversion_insns);
                  emit_move_insn (tempreg, DECL_RTL (parm));
-                 DECL_RTL (parm)
-                   = convert_to_mode (GET_MODE (parmreg), tempreg,
-                                      TREE_UNSIGNED (TREE_TYPE (parm)));
+                 SET_DECL_RTL (parm,
+                               convert_to_mode (GET_MODE (parmreg), 
+                                                tempreg,
+                                                unsigned_p));
                  emit_move_insn (parmreg, DECL_RTL (parm));
                  conversion_insns = get_insns();
                  did_conversion = 1;
@@ -4786,7 +4776,7 @@ assign_parms (fndecl)
                }
              else
                emit_move_insn (parmreg, DECL_RTL (parm));
-             DECL_RTL (parm) = parmreg;
+             SET_DECL_RTL (parm, parmreg);
              /* STACK_PARM is the pointer, not the parm, and PARMREG is
                 now the parm.  */
              stack_parm = 0;
@@ -4966,7 +4956,7 @@ assign_parms (fndecl)
 
          if (promoted_mode != nominal_mode)
            {
-             /* Conversion is required.   */
+             /* Conversion is required.  */
              rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
 
              emit_move_insn (tempreg, validize_mem (entry_parm));
@@ -4975,11 +4965,9 @@ assign_parms (fndecl)
              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);
-               }
+               /* ??? This may need a big-endian conversion on sparc64.  */
+               stack_parm = adjust_address (stack_parm, nominal_mode, 0);
+
              conversion_insns = get_insns ();
              did_conversion = 1;
              end_sequence ();
@@ -5021,7 +5009,7 @@ assign_parms (fndecl)
              conversion_insns = get_insns ();
              end_sequence ();
            }
-         DECL_RTL (parm) = stack_parm;
+         SET_DECL_RTL (parm, stack_parm);
        }
 
       /* If this "parameter" was the place where we are receiving the
@@ -5029,12 +5017,20 @@ assign_parms (fndecl)
       if (parm == function_result_decl)
        {
          tree result = DECL_RESULT (fndecl);
+         rtx x = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
 
-         DECL_RTL (result)
-           = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
+         set_mem_attributes (x, result, 1);
+         SET_DECL_RTL (result, x);
+       }
 
-         set_mem_attributes (DECL_RTL (result), result, 1);
+      if (GET_CODE (DECL_RTL (parm)) == REG)
+       REGNO_DECL (REGNO (DECL_RTL (parm))) = parm;
+      else if (GET_CODE (DECL_RTL (parm)) == CONCAT)
+       {
+         REGNO_DECL (REGNO (XEXP (DECL_RTL (parm), 0))) = parm;
+         REGNO_DECL (REGNO (XEXP (DECL_RTL (parm), 1))) = parm;
        }
+
     }
 
   /* Output all parameter conversion instructions (possibly including calls)
@@ -5055,13 +5051,11 @@ assign_parms (fndecl)
 #endif
 #endif
 
-#ifdef STACK_BOUNDARY
 #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
 
   current_function_args_size
     = ((current_function_args_size + STACK_BYTES - 1)
        / STACK_BYTES) * STACK_BYTES;
-#endif
 
 #ifdef ARGS_GROW_DOWNWARD
   current_function_arg_offset_rtx
@@ -5090,7 +5084,9 @@ assign_parms (fndecl)
      to include tree.h.  Do this here so it gets done when an inlined
      function gets output.  */
 
-  current_function_return_rtx = DECL_RTL (DECL_RESULT (fndecl));
+  current_function_return_rtx
+    = (DECL_RTL_SET_P (DECL_RESULT (fndecl))
+       ? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX);
 }
 \f
 /* Indicate whether REGNO is an incoming argument to the current function
@@ -5367,7 +5363,7 @@ void
 uninitialized_vars_warning (block)
      tree block;
 {
-  register tree decl, sub;
+  tree decl, sub;
   for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
     {
       if (warn_uninitialized
@@ -5408,7 +5404,7 @@ uninitialized_vars_warning (block)
 void
 setjmp_args_warning ()
 {
-  register tree decl;
+  tree decl;
   for (decl = DECL_ARGUMENTS (current_function_decl);
        decl; decl = TREE_CHAIN (decl))
     if (DECL_RTL (decl) != 0
@@ -5425,7 +5421,7 @@ void
 setjmp_protect (block)
      tree block;
 {
-  register tree decl, sub;
+  tree decl, sub;
   for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
     if ((TREE_CODE (decl) == VAR_DECL
         || TREE_CODE (decl) == PARM_DECL)
@@ -5457,7 +5453,7 @@ setjmp_protect (block)
 void
 setjmp_protect_args ()
 {
-  register tree decl;
+  tree decl;
   for (decl = DECL_ARGUMENTS (current_function_decl);
        decl; decl = TREE_CHAIN (decl))
     if ((TREE_CODE (decl) == VAR_DECL
@@ -5524,12 +5520,7 @@ fix_lexical_addr (addr, var)
   if (context == current_function_decl || context == inline_function_decl)
     return addr;
 
-  for (fp = outer_function_chain; fp; fp = fp->next)
-    if (fp->decl == context)
-      break;
-
-  if (fp == 0)
-    abort ();
+  fp = find_function_data (context);
 
   if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM)
     addr = XEXP (XEXP (addr, 0), 0);
@@ -5558,15 +5549,12 @@ fix_lexical_addr (addr, var)
 #ifdef NEED_SEPARATE_AP
       rtx addr;
 
-      if (fp->x_arg_pointer_save_area == 0)
-       fp->x_arg_pointer_save_area
-         = assign_stack_local_1 (Pmode, GET_MODE_SIZE (Pmode), 0, fp);
-
-      addr = fix_lexical_addr (XEXP (fp->x_arg_pointer_save_area, 0), var);
+      addr = get_arg_pointer_save_area (fp);
+      addr = fix_lexical_addr (XEXP (addr, 0), var);
       addr = memory_address (Pmode, addr);
 
       base = gen_rtx_MEM (Pmode, addr);
-      MEM_ALIAS_SET (base) = get_frame_alias_set ();
+      set_mem_alias_set (base, get_frame_alias_set ());
       base = copy_to_reg (base);
 #else
       displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET);
@@ -5616,7 +5604,7 @@ trampoline_address (function)
       return
        adjust_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
 
-  for (fp = outer_function_chain; fp; fp = fp->next)
+  for (fp = outer_function_chain; fp; fp = fp->outer)
     for (link = fp->x_trampoline_list; link; link = TREE_CHAIN (link))
       if (TREE_PURPOSE (link) == function)
        {
@@ -5632,9 +5620,7 @@ trampoline_address (function)
   fn_context = decl_function_context (function);
   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;
+    fp = find_function_data (fn_context);
 
   /* Allocate run-time space for this trampoline
      (usually in the defining function's stack frame).  */
@@ -5686,19 +5672,20 @@ round_trampoline_addr (tramp)
 #ifdef TRAMPOLINE_ALIGNMENT
   /* Round address up to desired boundary.  */
   rtx temp = gen_reg_rtx (Pmode);
-  temp = expand_binop (Pmode, add_optab, tramp,
-                      GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1),
-                      temp, 0, OPTAB_LIB_WIDEN);
-  tramp = expand_binop (Pmode, and_optab, temp,
-                       GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT),
-                       temp, 0, OPTAB_LIB_WIDEN);
+  rtx addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1);
+  rtx mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
+
+  temp  = expand_simple_binop (Pmode, PLUS, tramp, addend,
+                              temp, 0, OPTAB_LIB_WIDEN);
+  tramp = expand_simple_binop (Pmode, AND, temp, mask,
+                              temp, 0, OPTAB_LIB_WIDEN);
 #endif
   return tramp;
 }
 
 /* Given a trampoline address, round it then apply any
    platform-specific adjustments so that the result can be used for a
-   function call . */
+   function call .  */
 
 static rtx
 adjust_trampoline_addr (tramp)
@@ -5815,8 +5802,11 @@ identify_blocks_1 (insns, block_vector, end_block_vector, orig_block_stack)
   return block_vector;
 }
 
-/* Identify BLOCKs referenced by more than one
-   NOTE_INSN_BLOCK_{BEG,END}, and create duplicate blocks.  */
+/* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END},
+   and create duplicate blocks.  */
+/* ??? Need an option to either create block fragments or to create
+   abstract origin duplicates of a source block.  It really depends
+   on what optimization has been performed.  */
 
 void
 reorder_blocks ()
@@ -5829,47 +5819,34 @@ reorder_blocks ()
 
   VARRAY_TREE_INIT (block_stack, 10, "block_stack");
 
+  /* Reset the TREE_ASM_WRITTEN bit for all blocks.  */
+  reorder_blocks_0 (block);
+
   /* Prune the old trees away, so that they don't get in the way.  */
   BLOCK_SUBBLOCKS (block) = NULL_TREE;
   BLOCK_CHAIN (block) = NULL_TREE;
 
-  reorder_blocks_0 (get_insns ());
+  /* Recreate the block tree from the note nesting.  */
   reorder_blocks_1 (get_insns (), block, &block_stack);
-
   BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block));
 
+  /* Remove deleted blocks from the block fragment chains.  */
+  reorder_fix_fragments (block);
+
   VARRAY_FREE (block_stack);
 }
 
-/* Helper function for reorder_blocks.  Process the insn chain beginning
-   at INSNS.  Recurse for CALL_PLACEHOLDER insns.  */
+/* Helper function for reorder_blocks.  Reset TREE_ASM_WRITTEN.  */
 
 static void
-reorder_blocks_0 (insns)
-     rtx insns;
+reorder_blocks_0 (block)
+     tree block;
 {
-  rtx insn;
-
-  for (insn = insns; insn; insn = NEXT_INSN (insn))
+  while (block)
     {
-      if (GET_CODE (insn) == NOTE)
-       {
-         if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
-           {
-             tree block = NOTE_BLOCK (insn);
-             TREE_ASM_WRITTEN (block) = 0;
-           }
-       }
-      else if (GET_CODE (insn) == CALL_INSN
-              && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
-       {
-         rtx cp = PATTERN (insn);
-         reorder_blocks_0 (XEXP (cp, 0));
-         if (XEXP (cp, 1))
-           reorder_blocks_0 (XEXP (cp, 1));
-         if (XEXP (cp, 2))
-           reorder_blocks_0 (XEXP (cp, 2));
-       }
+      TREE_ASM_WRITTEN (block) = 0;
+      reorder_blocks_0 (BLOCK_SUBBLOCKS (block));
+      block = BLOCK_CHAIN (block);
     }
 }
 
@@ -5888,12 +5865,26 @@ reorder_blocks_1 (insns, current_block, p_block_stack)
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
            {
              tree block = NOTE_BLOCK (insn);
-             /* If we have seen this block before, copy it.  */
+
+             /* If we have seen this block before, that means it now
+                spans multiple address regions.  Create a new fragment.  */
              if (TREE_ASM_WRITTEN (block))
                {
-                 block = copy_node (block);
-                 NOTE_BLOCK (insn) = block;
+                 tree new_block = copy_node (block);
+                 tree origin;
+
+                 origin = (BLOCK_FRAGMENT_ORIGIN (block)
+                           ? BLOCK_FRAGMENT_ORIGIN (block)
+                           : block);
+                 BLOCK_FRAGMENT_ORIGIN (new_block) = origin;
+                 BLOCK_FRAGMENT_CHAIN (new_block)
+                   = BLOCK_FRAGMENT_CHAIN (origin);
+                 BLOCK_FRAGMENT_CHAIN (origin) = new_block;
+
+                 NOTE_BLOCK (insn) = new_block;
+                 block = new_block;
                }
+
              BLOCK_SUBBLOCKS (block) = 0;
              TREE_ASM_WRITTEN (block) = 1;
              BLOCK_SUPERCONTEXT (block) = current_block;
@@ -5924,6 +5915,62 @@ reorder_blocks_1 (insns, current_block, p_block_stack)
     }
 }
 
+/* Rationalize BLOCK_FRAGMENT_ORIGIN.  If an origin block no longer
+   appears in the block tree, select one of the fragments to become
+   the new origin block.  */
+
+static void
+reorder_fix_fragments (block)
+    tree block;
+{
+  while (block)
+    {
+      tree dup_origin = BLOCK_FRAGMENT_ORIGIN (block);
+      tree new_origin = NULL_TREE;
+
+      if (dup_origin)
+       {
+         if (! TREE_ASM_WRITTEN (dup_origin))
+           {
+             new_origin = BLOCK_FRAGMENT_CHAIN (dup_origin);
+             
+             /* Find the first of the remaining fragments.  There must
+                be at least one -- the current block.  */
+             while (! TREE_ASM_WRITTEN (new_origin))
+               new_origin = BLOCK_FRAGMENT_CHAIN (new_origin);
+             BLOCK_FRAGMENT_ORIGIN (new_origin) = NULL_TREE;
+           }
+       }
+      else if (! dup_origin)
+       new_origin = block;
+
+      /* Re-root the rest of the fragments to the new origin.  In the
+        case that DUP_ORIGIN was null, that means BLOCK was the origin
+        of a chain of fragments and we want to remove those fragments
+        that didn't make it to the output.  */
+      if (new_origin)
+       {
+         tree *pp = &BLOCK_FRAGMENT_CHAIN (new_origin);
+         tree chain = *pp;
+
+         while (chain)
+           {
+             if (TREE_ASM_WRITTEN (chain))
+               {
+                 BLOCK_FRAGMENT_ORIGIN (chain) = new_origin;
+                 *pp = chain;
+                 pp = &BLOCK_FRAGMENT_CHAIN (chain);
+               }
+             chain = BLOCK_FRAGMENT_CHAIN (chain);
+           }
+         *pp = NULL_TREE;
+       }
+
+      reorder_fix_fragments (BLOCK_SUBBLOCKS (block));
+      block = BLOCK_CHAIN (block);
+    }
+}
+
 /* Reverse the order of elements in the chain T of blocks,
    and return the new head of the chain (old last element).  */
 
@@ -5931,7 +5978,7 @@ static tree
 blocks_nreverse (t)
      tree t;
 {
-  register tree prev = 0, decl, next;
+  tree prev = 0, decl, next;
   for (decl = t; decl; decl = next)
     {
       next = BLOCK_CHAIN (decl);
@@ -6024,10 +6071,11 @@ number_blocks (fn)
 }
 \f
 /* Allocate a function structure and reset its contents to the defaults.  */
+
 static void
 prepare_function_start ()
 {
-  cfun = (struct function *) xcalloc (1, sizeof (struct function));
+  cfun = (struct function *) ggc_alloc_cleared (sizeof (struct function));
 
   init_stmt_for_function ();
   init_eh_for_function ();
@@ -6075,13 +6123,8 @@ prepare_function_start ()
   cfun->original_decl_initial = 0;
   cfun->original_arg_vector = 0;
 
-#ifdef STACK_BOUNDARY
   cfun->stack_alignment_needed = STACK_BOUNDARY;
   cfun->preferred_stack_boundary = STACK_BOUNDARY;
-#else
-  cfun->stack_alignment_needed = 0;
-  cfun->preferred_stack_boundary = 0;
-#endif
 
   /* Set if a call to setjmp is seen.  */
   current_function_calls_setjmp = 0;
@@ -6175,10 +6218,6 @@ init_function_start (subr, filename, line)
 {
   prepare_function_start ();
 
-  /* Remember this function for later.  */
-  cfun->next_global = all_functions;
-  all_functions = cfun;
-
   current_function_name = (*decl_printable_name) (subr, 2);
   cfun->decl = subr;
 
@@ -6200,7 +6239,7 @@ init_function_start (subr, 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.
      Also, final expects a note to appear there.  */
-  emit_note (NULL_PTR, NOTE_INSN_DELETED);
+  emit_note (NULL, NOTE_INSN_DELETED);
 
   /* Set flags used by final.c.  */
   if (aggregate_value_p (DECL_RESULT (subr)))
@@ -6253,14 +6292,62 @@ mark_varargs ()
 void
 expand_main_function ()
 {
-#if !defined (HAS_INIT_SECTION)
+#ifdef FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
+  if (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN)
+    {
+      int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+      rtx tmp;
+
+      /* Forcibly align the stack.  */
+#ifdef STACK_GROWS_DOWNWARD
+      tmp = expand_simple_binop (Pmode, AND, stack_pointer_rtx, GEN_INT(-align),
+                                stack_pointer_rtx, 1, OPTAB_WIDEN);
+#else
+      tmp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx,
+                                GEN_INT (align - 1), NULL_RTX, 1, OPTAB_WIDEN);
+      tmp = expand_simple_binop (Pmode, AND, tmp, GEN_INT (-align),
+                                stack_pointer_rtx, 1, OPTAB_WIDEN);
+#endif
+      if (tmp != stack_pointer_rtx)
+       emit_move_insn (stack_pointer_rtx, tmp);
+      
+      /* Enlist allocate_dynamic_stack_space to pick up the pieces.  */
+      tmp = force_reg (Pmode, const0_rtx);
+      allocate_dynamic_stack_space (tmp, NULL_RTX, BIGGEST_ALIGNMENT);
+    }
+#endif
+
+#ifndef HAS_INIT_SECTION
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), 0,
                     VOIDmode, 0);
-#endif /* not HAS_INIT_SECTION */
+#endif
 }
 \f
 extern struct obstack permanent_obstack;
 
+/* The PENDING_SIZES represent the sizes of variable-sized types.
+   Create RTL for the various sizes now (using temporary variables),
+   so that we can refer to the sizes from the RTL we are generating
+   for the current function.  The PENDING_SIZES are a TREE_LIST.  The
+   TREE_VALUE of each node is a SAVE_EXPR.  */
+
+void
+expand_pending_sizes (pending_sizes)
+     tree pending_sizes;
+{
+  tree tem;
+
+  /* Evaluate now the sizes of any types declared among the arguments.  */
+  for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem))
+    {
+      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 ();
+    }
+}
+
 /* Start the RTL for a new function, and set variables used for
    emitting RTL.
    SUBR is the FUNCTION_DECL node.
@@ -6312,20 +6399,10 @@ expand_function_start (subr, parms_have_cleanups)
   else
     cleanup_label = 0;
 
-  /* Make the label for return statements to jump to, if this machine
-     does not have a one-instruction return and uses an epilogue,
-     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;
-  else
-    return_label = gen_label_rtx ();
-#else
+  /* Make the label for return statements to jump to.  Do not special
+     case machines with special return instructions -- they will be
+     handled later during jump, ifcvt, or epilogue creation.  */
   return_label = gen_label_rtx ();
-#endif
 
   /* Initialize rtx used to return the value.  */
   /* Do this before assign_parms so that we copy the struct value address
@@ -6335,7 +6412,7 @@ expand_function_start (subr, parms_have_cleanups)
   if (aggregate_value_p (DECL_RESULT (subr)))
     {
       /* Returning something that won't go in a register.  */
-      register rtx value_address = 0;
+      rtx value_address = 0;
 
 #ifdef PCC_STATIC_STRUCT_RETURN
       if (current_function_returns_pcc_struct)
@@ -6357,43 +6434,35 @@ 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);
-         set_mem_attributes (DECL_RTL (DECL_RESULT (subr)),
-                             DECL_RESULT (subr), 1);
+         rtx x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
+         set_mem_attributes (x, DECL_RESULT (subr), 1);
+         SET_DECL_RTL (DECL_RESULT (subr), x);
        }
     }
   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 || current_function_instrument_entry_exit)
-    {
-      /* If function will end with cleanup code for parms,
-        compute the return values into a pseudo reg,
-        which we will copy into the true return register
-        after the cleanups are done.  */
-
-      enum machine_mode mode = DECL_MODE (DECL_RESULT (subr));
-
-#ifdef PROMOTE_FUNCTION_RETURN
-      tree type = TREE_TYPE (DECL_RESULT (subr));
-      int unsignedp = TREE_UNSIGNED (type);
-
-      mode = promote_mode (type, mode, &unsignedp, 1);
-#endif
-
-      DECL_RTL (DECL_RESULT (subr)) = gen_reg_rtx (mode);
-    }
+    SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
   else
-    /* Scalar, returned in a register.  */
     {
-      DECL_RTL (DECL_RESULT (subr))
-       = hard_function_value (TREE_TYPE (DECL_RESULT (subr)), subr, 1);
-
-      /* Mark this reg as the function's return value.  */
-      if (GET_CODE (DECL_RTL (DECL_RESULT (subr))) == REG)
+      /* Compute the return values into a pseudo reg, which we will copy
+        into the true return register after the cleanups are done.  */
+
+      /* In order to figure out what mode to use for the pseudo, we
+        figure out what the mode of the eventual return register will
+        actually be, and use that.  */
+      rtx hard_reg
+       = hard_function_value (TREE_TYPE (DECL_RESULT (subr)),
+                              subr, 1);
+
+      /* Structures that are returned in registers are not aggregate_value_p,
+        so we may see a PARALLEL.  Don't play pseudo games with this.  */
+      if (! REG_P (hard_reg))
+       SET_DECL_RTL (DECL_RESULT (subr), hard_reg);
+      else
        {
-         REG_FUNCTION_VALUE_P (DECL_RTL (DECL_RESULT (subr))) = 1;
+         /* Create the pseudo.  */
+         SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+
          /* Needed because we may need to move this to memory
             in case it's a named return value whose address is taken.  */
          DECL_REGISTER (DECL_RESULT (subr)) = 1;
@@ -6416,10 +6485,10 @@ expand_function_start (subr, parms_have_cleanups)
      The move is supposed to make sdb output more accurate.  */
   /* Indicate the beginning of the function body,
      as opposed to parm setup.  */
-  emit_note (NULL_PTR, NOTE_INSN_FUNCTION_BEG);
+  emit_note (NULL, NOTE_INSN_FUNCTION_BEG);
 
   if (GET_CODE (get_last_insn ()) != NOTE)
-    emit_note (NULL_PTR, NOTE_INSN_DELETED);
+    emit_note (NULL, NOTE_INSN_DELETED);
   parm_birth_insn = get_last_insn ();
 
   context_display = 0;
@@ -6457,7 +6526,7 @@ expand_function_start (subr, parms_have_cleanups)
                                    -(HOST_WIDE_INT) GET_MODE_SIZE (Pmode));
 #endif
          last_ptr = gen_rtx_MEM (Pmode, memory_address (Pmode, last_ptr));
-         MEM_ALIAS_SET (last_ptr) = get_frame_alias_set ();
+         set_mem_alias_set (last_ptr, get_frame_alias_set ());
          last_ptr = copy_to_reg (last_ptr);
 
          /* If we are not optimizing, ensure that we know that this
@@ -6491,17 +6560,10 @@ expand_function_start (subr, parms_have_cleanups)
   /* 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.  */
-  tail_recursion_reentry = emit_note (NULL_PTR, NOTE_INSN_DELETED);
+  tail_recursion_reentry = emit_note (NULL, NOTE_INSN_DELETED);
 
   /* 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,
-                  EXPAND_MEMORY_USE_BAD);
-      /* Flush the queue in case this parameter declaration has
-        side-effects.  */
-      emit_queue ();
-    }
+  expand_pending_sizes (nreverse (get_pending_sizes ()));
 
   /* Make sure there is a line number after the function entry setup code.  */
   force_next_line_note ();
@@ -6520,7 +6582,6 @@ expand_dummy_function_end ()
 
   free_after_parsing (cfun);
   free_after_compilation (cfun);
-  free (cfun);
   cfun = 0;
 }
 
@@ -6533,37 +6594,10 @@ diddle_return_value (doit, arg)
      void *arg;
 {
   rtx outgoing = current_function_return_rtx;
-  int pcc;
 
   if (! outgoing)
     return;
 
-  pcc = (current_function_returns_struct
-        || current_function_returns_pcc_struct);
-
-  if ((GET_CODE (outgoing) == REG
-       && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
-      || pcc)
-    {
-      tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
-
-      /* A PCC-style return returns a pointer to the memory in which
-        the structure is stored.  */
-      if (pcc)
-       type = build_pointer_type (type);
-
-#ifdef FUNCTION_OUTGOING_VALUE
-      outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
-#else
-      outgoing = FUNCTION_VALUE (type, current_function_decl);
-#endif
-      /* If this is a BLKmode structure being returned in registers, then use
-        the mode computed in expand_return.  */
-      if (GET_MODE (outgoing) == BLKmode)
-       PUT_MODE (outgoing, GET_MODE (current_function_return_rtx));
-      REG_FUNCTION_VALUE_P (outgoing) = 1;
-    }
-
   if (GET_CODE (outgoing) == REG)
     (*doit) (outgoing, arg);
   else if (GET_CODE (outgoing) == PARALLEL)
@@ -6592,6 +6626,17 @@ void
 clobber_return_register ()
 {
   diddle_return_value (do_clobber_return_reg, NULL);
+
+  /* In case we do use pseudo to return value, clobber it too.  */
+  if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
+    {
+      tree decl_result = DECL_RESULT (current_function_decl);
+      rtx decl_rtl = DECL_RTL (decl_result);
+      if (REG_P (decl_rtl) && REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER)
+       {
+         do_clobber_return_reg (decl_rtl, NULL);
+       }
+    }
 }
 
 static void
@@ -6621,6 +6666,7 @@ expand_function_end (filename, line, end_bindings)
      int end_bindings;
 {
   tree link;
+  rtx clobber_after;
 
 #ifdef TRAMPOLINE_TEMPLATE
   static rtx initial_trampoline;
@@ -6628,6 +6674,11 @@ expand_function_end (filename, line, end_bindings)
 
   finish_expr_for_function ();
 
+  /* If arg_pointer_save_area was referenced only from a nested
+     function, we will not have initialized it yet.  Do that now.  */
+  if (arg_pointer_save_area && ! cfun->arg_pointer_save_area_init)
+    get_arg_pointer_save_area (cfun);
+
 #ifdef NON_SAVING_SETJMP
   /* Don't put any variables in registers if we call setjmp
      on a machine that fails to restore the registers.  */
@@ -6640,20 +6691,6 @@ expand_function_end (filename, line, end_bindings)
     }
 #endif
 
-  /* Save the argument pointer if a save area was made for it.  */
-  if (arg_pointer_save_area)
-    {
-      /* arg_pointer_save_area may not be a valid memory address, so we
-        have to check it and fix it if necessary.  */
-      rtx seq;
-      start_sequence ();
-      emit_move_insn (validize_mem (arg_pointer_save_area),
-                     virtual_incoming_args_rtx);
-      seq = gen_sequence ();
-      end_sequence ();
-      emit_insn_before (seq, tail_recursion_reentry);
-    }
-
   /* Initialize any trampolines required by this function.  */
   for (link = trampoline_list; link; link = TREE_CHAIN (link))
     {
@@ -6749,7 +6786,7 @@ expand_function_end (filename, line, end_bindings)
   /* Mark the end of the function body.
      If control reaches this insn, the function can drop through
      without returning a value.  */
-  emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
+  emit_note (NULL, 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
@@ -6757,63 +6794,34 @@ expand_function_end (filename, line, end_bindings)
      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_INSN_REPEATED_LINE_NUMBER);
+    emit_note (NULL, NOTE_INSN_REPEATED_LINE_NUMBER);
 
   /* Output a linenumber for the end of the function.
      SDB depends on this.  */
   emit_line_note_force (filename, line);
 
+  /* Before the return label (if any), clobber the return
+     registers so that they are not propogated live to the rest of
+     the function.  This can only happen with functions that drop
+     through; if there had been a return statement, there would
+     have either been a return rtx, or a jump to the return label.
+
+     We delay actual code generation after the current_function_value_rtx
+     is computed.  */
+  clobber_after = get_last_insn ();
+
   /* Output the label for the actual return from the function,
      if one is expected.  This happens either because a function epilogue
      is used instead of a return instruction, or because a return was done
      with a goto in order to run local cleanups, or because of pcc-style
      structure returning.  */
-
   if (return_label)
-    {
-      rtx before, after;
-
-      /* Before the return label, clobber the return registers so that
-         they are not propogated live to the rest of the function.  This
-        can only happen with functions that drop through; if there had
-        been a return statement, there would have either been a return
-        rtx, or a jump to the return label.  */
-
-      before = get_last_insn ();
-      clobber_return_register ();
-      after = get_last_insn ();
-
-      if (before != after)
-       cfun->x_clobber_return_insn = after;
-
-      emit_label (return_label);
-    }
+    emit_label (return_label);
 
   /* C++ uses this.  */
   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 there are any catch_clauses remaining, output them now.  */
-    emit_insns (catch_clauses);
-    catch_clauses = catch_clauses_last = NULL_RTX;
-    /* 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);
@@ -6829,6 +6837,11 @@ expand_function_end (filename, line, end_bindings)
                         Pmode);
     }
 
+  /* Let except.c know where it should emit the call to unregister
+     the function context for sjlj exceptions.  */
+  if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
+    sjlj_emit_function_exit_after (get_last_insn ());
+
   /* 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.  */
@@ -6846,7 +6859,7 @@ expand_function_end (filename, line, end_bindings)
   /* If scalar return value was computed in a pseudo-reg, or was a named
      return value that got dumped to the stack, copy that to the hard
      return register.  */
-  if (DECL_RTL (DECL_RESULT (current_function_decl)) != 0)
+  if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
     {
       tree decl_result = DECL_RESULT (current_function_decl);
       rtx decl_rtl = DECL_RTL (decl_result);
@@ -6887,6 +6900,10 @@ expand_function_end (filename, line, end_bindings)
 
              convert_move (real_decl_rtl, decl_rtl, unsignedp);
            }
+         else if (GET_CODE (real_decl_rtl) == PARALLEL)
+           emit_group_load (real_decl_rtl, decl_rtl,
+                            int_size_in_bytes (TREE_TYPE (decl_result)),
+                            TYPE_ALIGN (TREE_TYPE (decl_result)));
          else
            emit_move_insn (real_decl_rtl, decl_rtl);
 
@@ -6936,28 +6953,31 @@ expand_function_end (filename, line, end_bindings)
       current_function_return_rtx = outgoing;
     }
 
+  /* If this is an implementation of throw, do what's necessary to
+     communicate between __builtin_eh_return and the epilogue.  */
+  expand_eh_return ();
+
+  /* Emit the actual code to clobber return register.  */
+  {
+    rtx seq, after;
+    
+    start_sequence ();
+    clobber_return_register ();
+    seq = gen_sequence ();
+    end_sequence ();
+
+    after = emit_insn_after (seq, clobber_after);
+    
+    if (clobber_after != after)
+      cfun->x_clobber_return_insn = after;
+  }
+
   /* ??? This should no longer be necessary since stupid is no longer with
      us, but there are some parts of the compiler (eg reload_combine, and
      sh mach_dep_reorg) that still try and compute their own lifetime info
      instead of using the general framework.  */
   use_return_register ();
 
-  /* 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.  */
-
-#ifdef HAVE_return
-  if (HAVE_return)
-    {
-      emit_jump_insn (gen_return ());
-      emit_barrier ();
-    }
-#endif
-
   /* Fix up any gotos that jumped out to the outermost
      binding level of the function.
      Must follow emitting RETURN_LABEL.  */
@@ -6967,6 +6987,38 @@ expand_function_end (filename, line, end_bindings)
      then you will lose.  */
   expand_fixups (get_insns ());
 }
+
+rtx
+get_arg_pointer_save_area (f)
+     struct function *f;
+{
+  rtx ret = f->x_arg_pointer_save_area;
+
+  if (! ret)
+    {
+      ret = assign_stack_local_1 (Pmode, GET_MODE_SIZE (Pmode), 0, f);
+      f->x_arg_pointer_save_area = ret;
+    }
+
+  if (f == cfun && ! f->arg_pointer_save_area_init)
+    {
+      rtx seq;
+
+      /* Save the arg pointer at the beginning of the function.  The 
+        generated stack slot may not be a valid memory address, so we
+        have to check it and fix it if necessary.  */
+      start_sequence ();
+      emit_move_insn (validize_mem (ret), virtual_incoming_args_rtx);
+      seq = gen_sequence ();
+      end_sequence ();
+
+      push_topmost_sequence ();
+      emit_insn_after (seq, get_insns ());
+      pop_topmost_sequence ();
+    }
+
+  return ret;
+}
 \f
 /* Extend a vector that records the INSN_UIDs of INSNS (either a
    sequence or a single insn).  */
@@ -7003,7 +7055,7 @@ contains (insn, vec)
      rtx insn;
      varray_type vec;
 {
-  register int i, j;
+  int i, j;
 
   if (GET_CODE (insn) == INSN
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
@@ -7059,16 +7111,7 @@ emit_return_into_block (bb, line_note)
   end = emit_jump_insn_after (gen_return (), bb->end);
   if (line_note)
     emit_line_note_after (NOTE_SOURCE_FILE (line_note),
-                         NOTE_LINE_NUMBER (line_note), bb->end);
-
-  while (1)
-    {
-      set_block_for_insn (p, bb);
-      if (p == bb->end)
-       break;
-      p = PREV_INSN (p);
-    }
-  bb->end = end;
+                         NOTE_LINE_NUMBER (line_note), PREV_INSN (bb->end));
 }
 #endif /* HAVE_return */
 
@@ -7117,7 +7160,8 @@ keep_stack_depressed (seq)
          else
            sp_modified_unknown = 1;
 
-         /* Don't allow the SP modification to happen.  */
+         /* Don't allow the SP modification to happen.  We don't call
+            delete_insn here since INSN isn't in any chain.  */
          PUT_CODE (insn, NOTE);
          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
          NOTE_SOURCE_FILE (insn) = 0;
@@ -7145,7 +7189,9 @@ thread_prologue_and_epilogue_insns (f)
 {
   int inserted = 0;
   edge e;
+#if defined (HAVE_sibcall_epilogue) || defined (HAVE_epilogue) || defined (HAVE_return) || defined (HAVE_prologue)
   rtx seq;
+#endif
 #ifdef HAVE_prologue
   rtx prologue_end = NULL_RTX;
 #endif
@@ -7169,19 +7215,14 @@ thread_prologue_and_epilogue_insns (f)
       seq = gen_sequence ();
       end_sequence ();
 
-      /* If optimization is off, and perhaps in an empty function,
-        the entry block will have no successors.  */
-      if (ENTRY_BLOCK_PTR->succ)
-       {
-         /* Can't deal with multiple successsors of the entry block.  */
-         if (ENTRY_BLOCK_PTR->succ->succ_next)
-           abort ();
+      /* Can't deal with multiple successsors of the entry block
+         at the moment.  Function should always have at least one
+         entry point.  */
+      if (!ENTRY_BLOCK_PTR->succ || ENTRY_BLOCK_PTR->succ->succ_next)
+       abort ();
 
-         insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
-         inserted = 1;
-       }
-      else
-       emit_insn_after (seq, f);
+      insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
+      inserted = 1;
     }
 #endif
 
@@ -7255,7 +7296,7 @@ thread_prologue_and_epilogue_insns (f)
              if (simplejump_p (jump))
                {
                  emit_return_into_block (bb, epilogue_line_note);
-                 flow_delete_insn (jump);
+                 delete_insn (jump);
                }
 
              /* If we have a conditional jump, we can try to replace
@@ -7295,6 +7336,7 @@ thread_prologue_and_epilogue_insns (f)
          emit_barrier_after (last->end);
          emit_return_into_block (last, epilogue_line_note);
          epilogue_end = last->end;
+         last->succ->flags &= ~EDGE_FALLTHRU;
          goto epilogue_done;
        }
     }
@@ -7363,10 +7405,6 @@ epilogue_done:
       i = PREV_INSN (insn);
       newinsn = emit_insn_before (seq, insn);
 
-      /* Update the UID to basic block map.  */
-      for (i = NEXT_INSN (i); i != insn; i = NEXT_INSN (i))
-       set_block_for_insn (i, bb);
-
       /* Retain a map of the epilogue insns.  Used in life analysis to
         avoid getting rid of sibcall epilogue insns.  */
       record_insns (GET_CODE (seq) == SEQUENCE
@@ -7384,7 +7422,13 @@ epilogue_done:
         there are line number notes before where we inserted the
         prologue we should move them, and (2) we should generate a
         note before the end of the first basic block, if there isn't
-        one already there.  */
+        one already there.
+
+        ??? This behaviour is completely broken when dealing with
+        multiple entry functions.  We simply place the note always
+        into first basic block and let alternate entry points
+        to be missed.
+       */
 
       for (insn = prologue_end; insn; insn = prev)
        {
@@ -7402,7 +7446,7 @@ epilogue_done:
 
       /* Find the last line number note in the first block.  */
       for (insn = BASIC_BLOCK (0)->end;
-          insn != prologue_end;
+          insn != prologue_end && insn;
           insn = PREV_INSN (insn))
        if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
          break;
@@ -7454,7 +7498,7 @@ reposition_prologue_and_epilogue_notes (f)
 
   if ((len = VARRAY_SIZE (prologue)) > 0)
     {
-      register rtx insn, note = 0;
+      rtx insn, note = 0;
 
       /* Scan from the beginning until we reach the last prologue insn.
         We apparently can't depend on basic_block_{head,end} after
@@ -7487,6 +7531,9 @@ reposition_prologue_and_epilogue_notes (f)
                BLOCK_HEAD (0) = next;
 
              remove_insn (note);
+             /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note.  */
+             if (GET_CODE (insn) == CODE_LABEL)
+               insn = NEXT_INSN (insn);
              add_insn_after (note, insn);
            }
        }
@@ -7494,7 +7541,7 @@ reposition_prologue_and_epilogue_notes (f)
 
   if ((len = VARRAY_SIZE (epilogue)) > 0)
     {
-      register rtx insn, note = 0;
+      rtx insn, note = 0;
 
       /* Scan from the end until we reach the first epilogue insn.
         We apparently can't depend on basic_block_{head,end} after
@@ -7532,29 +7579,14 @@ reposition_prologue_and_epilogue_notes (f)
 #endif /* HAVE_prologue or HAVE_epilogue */
 }
 
-/* Mark T for GC.  */
-
-static void
-mark_temp_slot (t)
-     struct temp_slot *t;
-{
-  while (t)
-    {
-      ggc_mark_rtx (t->slot);
-      ggc_mark_rtx (t->address);
-      ggc_mark_tree (t->rtl_expr);
-      ggc_mark_tree (t->type);
-
-      t = t->next;
-    }
-}
-
 /* Mark P for GC.  */
 
 static void
 mark_function_status (p)
      struct function *p;
 {
+  struct var_refs_queue *q;
+  struct temp_slot *t;
   int i;
   rtx *r;
 
@@ -7585,53 +7617,72 @@ mark_function_status (p)
   ggc_mark_rtx (p->epilogue_delay_list);
   ggc_mark_rtx (p->x_clobber_return_insn);
 
-  mark_temp_slot (p->x_temp_slots);
+  for (t = p->x_temp_slots; t != 0; t = t->next)
+    {
+      ggc_mark (t);
+      ggc_mark_rtx (t->slot);
+      ggc_mark_rtx (t->address);
+      ggc_mark_tree (t->rtl_expr);
+      ggc_mark_tree (t->type);
+    }
 
-  {
-    struct var_refs_queue *q = p->fixup_var_refs_queue;
-    while (q)
-      {
-       ggc_mark_rtx (q->modified);
-       q = q->next;
+  for (q = p->fixup_var_refs_queue; q != 0; q = q->next)
+    {
+      ggc_mark (q);
+      ggc_mark_rtx (q->modified);
       }
-  }
 
   ggc_mark_rtx (p->x_nonlocal_goto_handler_slots);
   ggc_mark_rtx (p->x_nonlocal_goto_handler_labels);
   ggc_mark_rtx (p->x_nonlocal_goto_stack_level);
   ggc_mark_tree (p->x_nonlocal_labels);
+
+  mark_hard_reg_initial_vals (p);
 }
 
-/* Mark the function chain ARG (which is really a struct function **)
-   for GC.  */
+/* Mark the struct function pointed to by *ARG for GC, if it is not
+   NULL.  This is used to mark the current function and the outer
+   function chain.  */
 
 static void
-mark_function_chain (arg)
+maybe_mark_struct_function (arg)
      void *arg;
 {
   struct function *f = *(struct function **) arg;
 
-  for (; f; f = f->next_global)
-    {
-      ggc_mark_tree (f->decl);
-
-      mark_function_status (f);
-      mark_eh_status (f->eh);
-      mark_stmt_status (f->stmt);
-      mark_expr_status (f->expr);
-      mark_emit_status (f->emit);
-      mark_varasm_status (f->varasm);
-
-      if (mark_machine_status)
-       (*mark_machine_status) (f);
-      if (mark_lang_status)
-       (*mark_lang_status) (f);
-
-      if (f->original_arg_vector)
-       ggc_mark_rtvec ((rtvec) f->original_arg_vector);
-      if (f->original_decl_initial)
-       ggc_mark_tree (f->original_decl_initial);
-    }
+  if (f == 0)
+    return;
+
+  ggc_mark_struct_function (f);
+}
+
+/* Mark a struct function * for GC.  This is called from ggc-common.c.  */
+
+void
+ggc_mark_struct_function (f)
+     struct function *f;
+{
+  ggc_mark (f);
+  ggc_mark_tree (f->decl);
+
+  mark_function_status (f);
+  mark_eh_status (f->eh);
+  mark_stmt_status (f->stmt);
+  mark_expr_status (f->expr);
+  mark_emit_status (f->emit);
+  mark_varasm_status (f->varasm);
+
+  if (mark_machine_status)
+    (*mark_machine_status) (f);
+  if (mark_lang_status)
+    (*mark_lang_status) (f);
+
+  if (f->original_arg_vector)
+    ggc_mark_rtvec ((rtvec) f->original_arg_vector);
+  if (f->original_decl_initial)
+    ggc_mark_tree (f->original_decl_initial);
+  if (f->outer)
+    ggc_mark_struct_function (f->outer);
 }
 
 /* Called once, at initialization, to initialize function.c.  */
@@ -7639,8 +7690,9 @@ mark_function_chain (arg)
 void
 init_function_once ()
 {
-  ggc_add_root (&all_functions, 1, sizeof all_functions,
-               mark_function_chain);
+  ggc_add_root (&cfun, 1, sizeof cfun, maybe_mark_struct_function);
+  ggc_add_root (&outer_function_chain, 1, sizeof outer_function_chain,
+               maybe_mark_struct_function);
 
   VARRAY_INT_INIT (prologue, 0, "prologue");
   VARRAY_INT_INIT (epilogue, 0, "epilogue");