OSDN Git Service

* config/alpha/osf5.h (TARGET_LD_BUGGY_LDGP): New.
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 98184ef..cdfe697 100644 (file)
@@ -1,6 +1,6 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -45,9 +45,7 @@ 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 "regs.h"
 #include "hard-reg-set.h"
 #include "insn-config.h"
@@ -60,10 +58,6 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "tm_p.h"
 
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
 #endif
@@ -126,17 +120,19 @@ 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
-   save and restore machine-specific data,
-   in push_function_context and pop_function_context.  */
+/* These variables hold pointers to functions to create and destroy
+   target specific, per-function data structures.  */
 void (*init_machine_status) PARAMS ((struct function *));
-void (*save_machine_status) PARAMS ((struct function *));
-void (*restore_machine_status) PARAMS ((struct function *));
-void (*mark_machine_status) PARAMS ((struct function *));
 void (*free_machine_status) PARAMS ((struct function *));
+/* This variable holds a pointer to a function to register any
+   data items in the target specific, per-function data structure
+   that will need garbage collection.  */
+void (*mark_machine_status) PARAMS ((struct function *));
 
 /* Likewise, but for language-specific data.  */
 void (*init_lang_status) PARAMS ((struct function *));
@@ -193,17 +189,11 @@ struct temp_slot
   int align;
   /* The size, in units, of the slot.  */
   HOST_WIDE_INT size;
-  /* The alias set for the slot.  If the alias set is zero, we don't
-     know anything about the alias set of the slot.  We must only
-     reuse a slot if it is assigned an object of the same alias set.
-     Otherwise, the rest of the compiler may assume that the new use
-     of the slot cannot alias the old use of the slot, which is
-     false.  If the slot has alias set zero, then we can't reuse the
-     slot at all, since we have no idea what alias set may have been
-     imposed on the memory.  For example, if the stack slot is the
-     call frame for an inline functioned, we have no idea what alias
-     sets will be assigned to various pieces of the call frame.  */
-  HOST_WIDE_INT alias_set;
+  /* The type of the object in the slot, or zero if it doesn't correspond
+     to a type.  We use this to determine whether a slot can be reused.
+     It can be reused if objects of the type of the new slot will always
+     conflict with objects of the type of the old slot.  */
+  tree type;
   /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
   tree rtl_expr;
   /* Non-zero if this temporary is currently in use.  */
@@ -259,8 +249,13 @@ static void fixup_var_refs PARAMS ((rtx, enum machine_mode, int,
                                         struct hash_table *));
 static struct fixup_replacement
   *find_fixup_replacement      PARAMS ((struct fixup_replacement **, rtx));
-static void fixup_var_refs_insns PARAMS ((rtx, enum machine_mode, int,
-                                         rtx, int, struct hash_table *));
+static void fixup_var_refs_insns PARAMS ((rtx, rtx, enum machine_mode,
+                                         int, int));
+static void fixup_var_refs_insns_with_hash
+                               PARAMS ((struct hash_table *, rtx,
+                                        enum machine_mode, int));
+static void fixup_var_refs_insn PARAMS ((rtx, rtx, enum machine_mode,
+                                        int, int));
 static void fixup_var_refs_1   PARAMS ((rtx, enum machine_mode, rtx *, rtx,
                                         struct fixup_replacement **));
 static rtx fixup_memory_subreg PARAMS ((rtx, rtx, int));
@@ -270,6 +265,7 @@ static void optimize_bit_field      PARAMS ((rtx, rtx, rtx *));
 static void instantiate_decls  PARAMS ((tree, int));
 static void instantiate_decls_1        PARAMS ((tree, int));
 static void instantiate_decl   PARAMS ((rtx, HOST_WIDE_INT, int));
+static rtx instantiate_new_reg PARAMS ((rtx, HOST_WIDE_INT *));
 static int instantiate_virtual_regs_1 PARAMS ((rtx *, rtx, int));
 static void delete_handlers    PARAMS ((void));
 static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
@@ -279,7 +275,9 @@ static void pad_below               PARAMS ((struct args_size *, enum machine_mode,
                                         tree));
 #endif
 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_1   PARAMS ((rtx, tree, varray_type *));
 static tree blocks_nreverse    PARAMS ((tree));
 static int all_blocks          PARAMS ((tree, tree *));
@@ -292,7 +290,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
@@ -303,7 +301,7 @@ 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 *));
@@ -362,8 +360,6 @@ push_function_context_to (context)
 
   if (save_lang_status)
     (*save_lang_status) (p);
-  if (save_machine_status)
-    (*save_machine_status) (p);
 
   cfun = 0;
 }
@@ -393,8 +389,6 @@ pop_function_context_from (context)
 
   restore_emit_status (p);
 
-  if (restore_machine_status)
-    (*restore_machine_status) (p);
   if (restore_lang_status)
     (*restore_lang_status) (p);
 
@@ -483,6 +477,7 @@ free_after_compilation (f)
   f->x_tail_recursion_label = NULL;
   f->x_tail_recursion_reentry = NULL;
   f->x_arg_pointer_save_area = NULL;
+  f->x_clobber_return_insn = NULL;
   f->x_context_display = NULL;
   f->x_trampoline_list = NULL;
   f->x_parm_birth_insn = NULL;
@@ -656,7 +651,6 @@ assign_stack_temp_for_type (mode, size, keep, type)
      tree type;
 {
   int align;
-  HOST_WIDE_INT alias_set;
   struct temp_slot *p, *best_p = 0;
 
   /* If SIZE is -1 it means that somebody tried to allocate a temporary
@@ -664,14 +658,6 @@ assign_stack_temp_for_type (mode, size, keep, type)
   if (size == -1)
     abort ();
 
-  /* 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)
-    alias_set = get_alias_set (type);
-  else
-    alias_set = 0;
-
   if (mode == BLKmode)
     align = BIGGEST_ALIGNMENT;
   else
@@ -689,8 +675,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
   for (p = temp_slots; p; p = p->next)
     if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
        && ! p->in_use
-       && (! flag_strict_aliasing
-           || (alias_set && p->alias_set == alias_set))
+       && objects_must_conflict_p (p->type, type)
        && (best_p == 0 || best_p->size > p->size
            || (best_p->size == p->size && best_p->align > p->align)))
       {
@@ -726,7 +711,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
              p->align = best_p->align;
              p->address = 0;
              p->rtl_expr = 0;
-             p->alias_set = best_p->alias_set;
+             p->type = best_p->type;
              p->next = temp_slots;
              temp_slots = p;
 
@@ -764,7 +749,6 @@ assign_stack_temp_for_type (mode, size, keep, type)
                                    align);
 
       p->align = align;
-      p->alias_set = alias_set;
 
       /* The following slot size computation is necessary because we don't
         know the actual size of the temporary slot until assign_stack_local
@@ -795,6 +779,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
   p->in_use = 1;
   p->addr_taken = 0;
   p->rtl_expr = seq_rtl_expr;
+  p->type = type;
 
   if (keep == 2)
     {
@@ -817,10 +802,23 @@ assign_stack_temp_for_type (mode, size, keep, type)
   RTX_UNCHANGING_P (p->slot) = 0;
   MEM_IN_STRUCT_P (p->slot) = 0;
   MEM_SCALAR_P (p->slot) = 0;
-  MEM_ALIAS_SET (p->slot) = alias_set;
+  MEM_VOLATILE_P (p->slot) = 0;
 
+  /* 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;
+
+  /* If a type is specified, set the relevant flags. */
   if (type != 0)
-    MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type));
+    {
+      RTX_UNCHANGING_P (p->slot) = TYPE_READONLY (type);
+      MEM_VOLATILE_P (p->slot) = TYPE_VOLATILE (type);
+      MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type));
+    }
 
   return p->slot;
 }
@@ -1110,7 +1108,7 @@ preserve_temp_slots (x)
      a temporary slot we know it points to.  To be consistent with
      the code below, we really should preserve all non-kept slots
      if we can't find a match, but that seems to be much too costly.  */
-  if (GET_CODE (x) == REG && REGNO_POINTER_FLAG (REGNO (x)))
+  if (GET_CODE (x) == REG && REG_POINTER (x))
     p = find_temp_slot_from_address (x);
 
   /* If X is not in memory or is at a constant address, it cannot be in
@@ -1336,7 +1334,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
@@ -1507,6 +1507,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
 /* Make sure that all refs to the variable, previously made
    when it was a register, are fixed up to be valid again.
    See function above for meaning of arguments.  */
+
 static void
 schedule_fixup_var_refs (function, reg, type, promoted_mode, ht)
      struct function *function;
@@ -1545,21 +1546,25 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
   rtx first_insn = get_insns ();
   struct sequence_stack *stack = seq_stack;
   tree rtl_exps = rtl_expr_chain;
-  rtx insn;
 
-  /* Must scan all insns for stack-refs that exceed the limit.  */
-  fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn,
-                       stack == 0, ht);
   /* If there's a hash table, it must record all uses of VAR.  */
   if (ht)
-    return;
+    {
+      if (stack != 0)
+       abort ();
+      fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp);
+      return;
+    }
+
+  fixup_var_refs_insns (first_insn, var, promoted_mode, unsignedp,
+                       stack == 0);
 
   /* Scan all pending sequences too.  */
   for (; stack; stack = stack->next)
     {
-      push_to_sequence (stack->first);
-      fixup_var_refs_insns (var, promoted_mode, unsignedp,
-                           stack->first, stack->next != 0, 0);
+      push_to_full_sequence (stack->first, stack->last);
+      fixup_var_refs_insns (stack->first, var, promoted_mode, unsignedp,
+                           stack->next != 0);
       /* Update remembered end of sequence
         in case we added an insn at the end.  */
       stack->last = get_last_insn ();
@@ -1573,40 +1578,10 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
       if (seq != const0_rtx && seq != 0)
        {
          push_to_sequence (seq);
-         fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0, 0);
+         fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0);
          end_sequence ();
        }
     }
-
-  /* Scan the catch clauses for exception handling too.  */
-  push_to_full_sequence (catch_clauses, catch_clauses_last);
-  fixup_var_refs_insns (var, promoted_mode, unsignedp, catch_clauses, 0, 0);
-  end_full_sequence (&catch_clauses, &catch_clauses_last);
-
-  /* Scan sequences saved in CALL_PLACEHOLDERS too.  */
-  for (insn = first_insn; insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == CALL_INSN
-         && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
-       {
-         int i;
-
-         /* Look at the Normal call, sibling call and tail recursion
-            sequences attached to the CALL_PLACEHOLDER.  */
-         for (i = 0; i < 3; i++)
-           {
-             rtx seq = XEXP (PATTERN (insn), i);
-             if (seq)
-               {
-                 push_to_sequence (seq);
-                 fixup_var_refs_insns (var, promoted_mode, unsignedp,
-                                       seq, 0, 0);
-                 XEXP (PATTERN (insn), i) = get_insns ();
-                 end_sequence ();
-               }
-           }
-       }
-    }
 }
 \f
 /* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
@@ -1641,218 +1616,265 @@ find_fixup_replacement (replacements, x)
    main chain of insns for the current function.  */
 
 static void
-fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
+fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel)
+     rtx insn;
      rtx var;
      enum machine_mode promoted_mode;
      int unsignedp;
-     rtx insn;
      int toplevel;
+{
+  while (insn)
+    {
+      /* fixup_var_refs_insn might modify insn, so save its next
+         pointer now.  */
+      rtx next = NEXT_INSN (insn);
+
+      /* CALL_PLACEHOLDERs are special; we have to switch into each of
+        the three sequences they (potentially) contain, and process
+        them recursively.  The CALL_INSN itself is not interesting.  */
+
+      if (GET_CODE (insn) == CALL_INSN
+         && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+       {
+         int i;
+
+         /* Look at the Normal call, sibling call and tail recursion
+            sequences attached to the CALL_PLACEHOLDER.  */
+         for (i = 0; i < 3; i++)
+           {
+             rtx seq = XEXP (PATTERN (insn), i);
+             if (seq)
+               {
+                 push_to_sequence (seq);
+                 fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0);
+                 XEXP (PATTERN (insn), i) = get_insns ();
+                 end_sequence ();
+               }
+           }
+       }
+
+      else if (INSN_P (insn))
+       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel);
+
+      insn = next;
+    }
+}
+
+/* Look up the insns which reference VAR in HT and fix them up.  Other
+   arguments are the same as fixup_var_refs_insns.
+
+   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;
+     rtx var;
+     enum machine_mode promoted_mode;
+     int unsignedp;
 {
-  rtx call_dest = 0;
-  rtx insn_list = NULL_RTX;
+  struct insns_for_mem_entry *ime = (struct insns_for_mem_entry *)
+    hash_lookup (ht, var, /*create=*/0, /*copy=*/0);
+  rtx insn_list = ime->insns;
 
-  /* If we already know which INSNs reference VAR there's no need
-     to walk the entire instruction chain.  */
-  if (ht)
+  while (insn_list)
     {
-      insn_list = ((struct insns_for_mem_entry *)
-                  hash_lookup (ht, var, /*create=*/0, /*copy=*/0))->insns;
-      insn = insn_list ? XEXP (insn_list, 0) : NULL_RTX;
+      rtx insn = XEXP (insn_list, 0);
+       
+      if (INSN_P (insn))
+       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 1);
+
       insn_list = XEXP (insn_list, 1);
     }
+}
 
-  while (insn)
+
+/* Per-insn processing by fixup_var_refs_insns(_with_hash).  INSN is
+   the insn under examination, VAR is the variable to fix up
+   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;
+     rtx var;
+     enum machine_mode promoted_mode;
+     int unsignedp;
+     int toplevel;
+{
+  rtx call_dest = 0;
+  rtx set, prev, prev_set;
+  rtx note;
+
+  /* Remember the notes in case we delete the insn.  */
+  note = REG_NOTES (insn);
+
+  /* If this is a CLOBBER of VAR, delete it.
+
+     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
+         || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
+             && (XEXP (XEXP (PATTERN (insn), 0), 0) == var
+                 || XEXP (XEXP (PATTERN (insn), 0), 1) == var))))
     {
-      rtx next = NEXT_INSN (insn);
-      rtx set, prev, prev_set;
-      rtx note;
+      if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
+       /* The REG_LIBCALL note will go away since we are going to
+          turn INSN into a NOTE, so just delete the
+          corresponding REG_RETVAL note.  */
+       remove_note (XEXP (note, 0),
+                    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;
+    }
 
-      if (INSN_P (insn))
+  /* The insn to load VAR from a home in the arglist
+     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
+          && (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 (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.  */
+      PUT_CODE (insn, NOTE);
+      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+      NOTE_SOURCE_FILE (insn) = 0;
+    }
+  else
+    {
+      struct fixup_replacement *replacements = 0;
+      rtx next_insn = NEXT_INSN (insn);
+
+      if (SMALL_REGISTER_CLASSES)
        {
-         /* Remember the notes in case we delete the insn.  */
-         note = REG_NOTES (insn);
-
-         /* If this is a CLOBBER of VAR, delete it.
-
-            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
-                 || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
-                     && (XEXP (XEXP (PATTERN (insn), 0), 0) == var
-                         || XEXP (XEXP (PATTERN (insn), 0), 1) == var))))
+         /* 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 ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
-               /* The REG_LIBCALL note will go away since we are going to
-                  turn INSN into a NOTE, so just delete the
-                  corresponding REG_RETVAL note.  */
-               remove_note (XEXP (note, 0),
-                            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;
-           }
+             rtx temp = gen_reg_rtx (GET_MODE (call_dest));
 
-         /* The insn to load VAR from a home in the arglist
-            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
-                  && (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 (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.  */
-             PUT_CODE (insn, NOTE);
-             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (insn) = 0;
-             if (insn == last_parm_insn)
-               last_parm_insn = PREV_INSN (next);
+             emit_insn_before (gen_move_insn (temp, call_dest), insn);
+
+             PATTERN (insn) = replace_rtx (PATTERN (insn),
+                                           call_dest, temp);
            }
-         else
-           {
-             struct fixup_replacement *replacements = 0;
-             rtx next_insn = NEXT_INSN (insn);
 
-             if (SMALL_REGISTER_CLASSES)
-               {
-                 /* If the insn that copies the results of a CALL_INSN
-                    into a pseudo now references VAR, we have to use an
-                    intermediate pseudo since we want the life of the
-                    return value register to be only a single insn.
-
-                    If we don't use an intermediate pseudo, such things as
-                    address computations to make the address of VAR valid
-                    if it is not can be placed between the CALL_INSN and INSN.
-
-                    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));
+         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;
+       }
 
-                     emit_insn_before (gen_move_insn (temp, call_dest), insn);
+      /* 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
+        pseudo for the entire insn in case there is a MATCH_DUP
+        between two operands.  We pass a pointer to the head of
+        a list of struct fixup_replacements.  If fixup_var_refs_1
+        needs to allocate pseudos or replacement MEMs (for SUBREGs),
+        it will record them in this list.
 
-                     PATTERN (insn) = replace_rtx (PATTERN (insn),
-                                                   call_dest, temp);
-                   }
+        If it allocated a pseudo for any replacement, we copy into
+        it here.  */
 
-                 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;
-               }
+      fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,
+                       &replacements);
 
-             /* 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
-                pseudo for the entire insn in case there is a MATCH_DUP
-                between two operands.  We pass a pointer to the head of
-                a list of struct fixup_replacements.  If fixup_var_refs_1
-                needs to allocate pseudos or replacement MEMs (for SUBREGs),
-                it will record them in this list.
+      /* If this is last_parm_insn, and any instructions were output
+        after it to fix it up, then we must set last_parm_insn to
+        the last such instruction emitted.  */
+      if (insn == last_parm_insn)
+       last_parm_insn = PREV_INSN (next_insn);
 
-                If it allocated a pseudo for any replacement, we copy into
-                it here.  */
+      while (replacements)
+       {
+         struct fixup_replacement *next;
 
-             fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,
-                               &replacements);
+         if (GET_CODE (replacements->new) == REG)
+           {
+             rtx insert_before;
+             rtx seq;
 
-             /* If this is last_parm_insn, and any instructions were output
-                after it to fix it up, then we must set last_parm_insn to
-                the last such instruction emitted.  */
-             if (insn == last_parm_insn)
-               last_parm_insn = PREV_INSN (next_insn);
+             /* OLD might be a (subreg (mem)).  */
+             if (GET_CODE (replacements->old) == SUBREG)
+               replacements->old
+                 = fixup_memory_subreg (replacements->old, insn, 0);
+             else
+               replacements->old
+                 = fixup_stack_1 (replacements->old, insn);
 
-             while (replacements)
-               {
-                 struct fixup_replacement *next;
+             insert_before = insn;
 
-                 if (GET_CODE (replacements->new) == REG)
-                   {
-                     rtx insert_before;
-                     rtx seq;
-
-                     /* OLD might be a (subreg (mem)).  */
-                     if (GET_CODE (replacements->old) == SUBREG)
-                       replacements->old
-                         = fixup_memory_subreg (replacements->old, insn, 0);
-                     else
-                       replacements->old
-                         = fixup_stack_1 (replacements->old, insn);
-
-                     insert_before = insn;
-
-                     /* If we are changing the mode, do a conversion.
-                        This might be wasteful, but combine.c will
-                        eliminate much of the waste.  */
-
-                     if (GET_MODE (replacements->new)
-                         != GET_MODE (replacements->old))
-                       {
-                         start_sequence ();
-                         convert_move (replacements->new,
-                                       replacements->old, unsignedp);
-                         seq = gen_sequence ();
-                         end_sequence ();
-                       }
-                     else
-                       seq = gen_move_insn (replacements->new,
-                                            replacements->old);
-
-                     emit_insn_before (seq, insert_before);
-                   }
+             /* If we are changing the mode, do a conversion.
+                This might be wasteful, but combine.c will
+                eliminate much of the waste.  */
 
-                 next = replacements->next;
-                 free (replacements);
-                 replacements = next;
+             if (GET_MODE (replacements->new)
+                 != GET_MODE (replacements->old))
+               {
+                 start_sequence ();
+                 convert_move (replacements->new,
+                               replacements->old, unsignedp);
+                 seq = gen_sequence ();
+                 end_sequence ();
                }
-           }
+             else
+               seq = gen_move_insn (replacements->new,
+                                    replacements->old);
 
-         /* Also fix up any invalid exprs in the REG_NOTES of this insn.
-            But don't touch other insns referred to by reg-notes;
-            we will get them elsewhere.  */
-         while (note)
-           {
-             if (GET_CODE (note) != INSN_LIST)
-               XEXP (note, 0)
-                 = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
-             note = XEXP (note, 1);
+             emit_insn_before (seq, insert_before);
            }
-       }
 
-      if (!ht)
-       insn = next;
-      else if (insn_list)
-       {
-         insn = XEXP (insn_list, 0);
-         insn_list = XEXP (insn_list, 1);
+         next = replacements->next;
+         free (replacements);
+         replacements = next;
        }
-      else
-       insn = NULL_RTX;
+    }
+
+  /* Also fix up any invalid exprs in the REG_NOTES of this insn.
+     But don't touch other insns referred to by reg-notes;
+     we will get them elsewhere.  */
+  while (note)
+    {
+      if (GET_CODE (note) != INSN_LIST)
+       XEXP (note, 0)
+         = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);
+      note = XEXP (note, 1);
     }
 }
 \f
@@ -1864,7 +1886,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht)
    to modify this insn by replacing a memory reference with a pseudo or by
    making a new MEM to implement a SUBREG, we consult that list to see if
    we have already chosen a replacement. If none has already been allocated,
-   we allocate it and update the list.  fixup_var_refs_insns will copy VAR
+   we allocate it and update the list.  fixup_var_refs_insn will copy VAR
    or the SUBREG, as appropriate, to the pseudo.  */
 
 static void
@@ -1916,7 +1938,9 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  /* That failed.  Fall back on force_operand and hope.  */
 
                  start_sequence ();
-                 force_operand (sub, y);
+                 sub = force_operand (sub, y);
+                 if (sub != y)
+                   emit_insn (gen_move_insn (y, sub));
                  seq = gen_sequence ();
                  end_sequence ();
                }
@@ -2120,7 +2144,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;
            }
@@ -2154,7 +2178,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.  */
@@ -2199,7 +2223,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.  */
@@ -2483,7 +2507,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;
@@ -2493,9 +2517,6 @@ 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))
     /* Shortcut if no insns need be emitted.  */
@@ -2689,7 +2710,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))))
@@ -2714,7 +2736,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));
@@ -2735,7 +2757,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)))
@@ -2938,7 +2960,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;
@@ -2949,7 +2971,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:
@@ -2969,14 +2991,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;
@@ -3045,7 +3072,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
@@ -3188,22 +3215,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++)
@@ -3249,7 +3263,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;
@@ -3421,17 +3435,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;
     }
 }
@@ -3512,6 +3531,10 @@ instantiate_virtual_regs (fndecl, insns)
       {
        instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1);
        instantiate_virtual_regs_1 (&REG_NOTES (insn), NULL_RTX, 0);
+       /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE.  */
+       if (GET_CODE (insn) == CALL_INSN)
+         instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn),
+                                     NULL_RTX, 0);
       }
 
   /* Instantiate the stack slots for the parm registers, for later use in
@@ -3571,8 +3594,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))
@@ -3646,6 +3671,35 @@ instantiate_decl (x, size, valid_only)
   XEXP (x, 0) = addr;
 }
 \f
+/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
+   is a virtual register, return the requivalent hard register and set the
+   offset indirectly through the pointer.  Otherwise, return 0.  */
+
+static rtx
+instantiate_new_reg (x, poffset)
+     rtx x;
+     HOST_WIDE_INT *poffset;
+{
+  rtx new;
+  HOST_WIDE_INT offset;
+
+  if (x == virtual_incoming_args_rtx)
+    new = arg_pointer_rtx, offset = in_arg_offset;
+  else if (x == virtual_stack_vars_rtx)
+    new = frame_pointer_rtx, offset = var_offset;
+  else if (x == virtual_stack_dynamic_rtx)
+    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;
+  else
+    return 0;
+
+  *poffset = offset;
+  return new;
+}
+\f
 /* Given a pointer to a piece of rtx and an optional pointer to the
    containing object, instantiate any virtual registers present in it.
 
@@ -3705,21 +3759,14 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
         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)
-       new = arg_pointer_rtx, offset = -in_arg_offset;
-      else if (SET_DEST (x) == virtual_stack_vars_rtx)
-       new = frame_pointer_rtx, offset = -var_offset;
-      else if (SET_DEST (x) == virtual_stack_dynamic_rtx)
-       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)
+      if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0)
        {
          rtx src = SET_SRC (x);
 
+         /* We are setting the register, not using it, so the relevant
+            offset is the negative of the offset to use were we using
+            the register.  */
+         offset = - offset;
          instantiate_virtual_regs_1 (&src, NULL_RTX, 0);
 
          /* The only valid sources here are PLUS or REG.  Just do
@@ -3759,40 +3806,37 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
          /* Check for (plus (plus VIRT foo) (const_int)) first.  */
          if (GET_CODE (XEXP (x, 0)) == PLUS)
            {
-             rtx inner = XEXP (XEXP (x, 0), 0);
-
-             if (inner == virtual_incoming_args_rtx)
-               new = arg_pointer_rtx, offset = in_arg_offset;
-             else if (inner == virtual_stack_vars_rtx)
-               new = frame_pointer_rtx, offset = var_offset;
-             else if (inner == virtual_stack_dynamic_rtx)
-               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;
+             if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset)))
+               {
+                 instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
+                                             extra_insns);
+                 new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
+               }
              else
                {
                  loc = &XEXP (x, 0);
                  goto restart;
                }
-
-             instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
-                                         extra_insns);
-             new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
            }
 
-         else if (XEXP (x, 0) == virtual_incoming_args_rtx)
-           new = arg_pointer_rtx, offset = in_arg_offset;
-         else if (XEXP (x, 0) == virtual_stack_vars_rtx)
-           new = frame_pointer_rtx, offset = var_offset;
-         else if (XEXP (x, 0) == virtual_stack_dynamic_rtx)
-           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
+#ifdef POINTERS_EXTEND_UNSIGNED
+         /* If we have (plus (subreg (virtual-reg)) (const_int)), we know
+            we can commute the PLUS and SUBREG because pointers into the
+            frame are well-behaved.  */
+         else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode
+                  && GET_CODE (XEXP (x, 1)) == CONST_INT
+                  && 0 != (new
+                           = instantiate_new_reg (SUBREG_REG (XEXP (x, 0)),
+                                                  &offset))
+                  && validate_change (object, loc,
+                                      plus_constant (gen_lowpart (ptr_mode,
+                                                                  new),
+                                                     offset
+                                                     + INTVAL (XEXP (x, 1))),
+                                      0))
+               return 1;
+#endif
+         else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0)
            {
              /* We know the second operand is a constant.  Unless the
                 first operand is a REG (which has been already checked),
@@ -3991,18 +4035,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
     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.  */
-      if (x == virtual_incoming_args_rtx)
-       new = arg_pointer_rtx, offset = in_arg_offset;
-      else if (x == virtual_stack_vars_rtx)
-       new = frame_pointer_rtx, offset = var_offset;
-      else if (x == virtual_stack_dynamic_rtx)
-       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)
+      if ((new = instantiate_new_reg (x, &offset)) != 0)
        {
          temp = plus_constant (new, offset);
          if (!validate_change (object, loc, temp, 0))
@@ -4310,8 +4343,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;
        }
@@ -4330,7 +4363,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;
        }
 
@@ -4548,6 +4582,27 @@ assign_parms (fndecl)
          && nominal_mode != BLKmode && nominal_mode != passed_mode)
        stack_parm = 0;
 
+      /* When an argument is passed in multiple locations, we can't
+        make use of this information, but we can save some copying if
+        the whole argument is passed in a single register.  */
+      if (GET_CODE (entry_parm) == PARALLEL
+         && nominal_mode != BLKmode && passed_mode != BLKmode)
+       {
+         int i, len = XVECLEN (entry_parm, 0);
+
+         for (i = 0; i < len; i++)
+           if (XEXP (XVECEXP (entry_parm, 0, i), 0) != NULL_RTX
+               && GET_CODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) == REG
+               && (GET_MODE (XEXP (XVECEXP (entry_parm, 0, i), 0))
+                   == passed_mode)
+               && INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0)
+             {
+               entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0);
+               DECL_INCOMING_RTL (parm) = entry_parm;
+               break;
+             }
+       }
+
       /* ENTRY_PARM is an RTX for the parameter as it arrives,
         in the mode in which it arrives.
         STACK_PARM is an RTX for a stack slot where the parameter can live
@@ -4605,13 +4660,11 @@ 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)
                   && ! DECL_INLINE (fndecl))
-                 /* layout_decl may set this.  */
-                 || TREE_ADDRESSABLE (parm)
                  || TREE_SIDE_EFFECTS (parm)
                  /* If -ffloat-store specified, don't put explicit
                     float variables into registers.  */
@@ -4639,13 +4692,17 @@ assign_parms (fndecl)
             appropriately.  */
          if (passed_pointer)
            {
-             DECL_RTL (parm)
-               = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
+             SET_DECL_RTL (parm,
+                           gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), 
+                                        parmreg));
              set_mem_attributes (DECL_RTL (parm), parm, 1);
            }
          else
-           DECL_RTL (parm) = parmreg;
-
+           {
+             SET_DECL_RTL (parm, parmreg);
+             maybe_set_unchanging (DECL_RTL (parm), parm);
+           }
+             
          /* Copy the value into the register.  */
          if (nominal_mode != passed_mode
              || promoted_nominal_mode != promoted_mode)
@@ -4677,6 +4734,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,
@@ -4695,8 +4766,6 @@ assign_parms (fndecl)
              && ! ((! optimize
                     && ! DECL_REGISTER (parm)
                     && ! DECL_INLINE (fndecl))
-                   /* layout_decl may set this.  */
-                   || TREE_ADDRESSABLE (parm)
                    || TREE_SIDE_EFFECTS (parm)
                    /* If -ffloat-store specified, don't put explicit
                       float variables into registers.  */
@@ -4707,8 +4776,24 @@ assign_parms (fndecl)
                 Pmode above.  We must use the actual mode of the parm.  */
              parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
              mark_user_reg (parmreg);
-             emit_move_insn (parmreg, DECL_RTL (parm));
-             DECL_RTL (parm) = parmreg;
+             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));
+                 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;
+                 end_sequence ();
+               }
+             else
+               emit_move_insn (parmreg, DECL_RTL (parm));
+             SET_DECL_RTL (parm, parmreg);
              /* STACK_PARM is the pointer, not the parm, and PARMREG is
                 now the parm.  */
              stack_parm = 0;
@@ -4865,6 +4950,21 @@ assign_parms (fndecl)
            mark_reg_pointer (parmreg,
                              TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
 
+         /* If something wants our address, try to use ADDRESSOF.  */
+         if (TREE_ADDRESSABLE (parm))
+           {
+             /* If we end up putting something into the stack,
+                fixup_var_refs_insns will need to make a pass over
+                all the instructions.  It looks throughs the pending
+                sequences -- but it can't see the ones in the
+                CONVERSION_INSNS, if they're not on the sequence
+                stack.  So, we go back to that sequence, just so that
+                the fixups will happen.  */
+             push_to_sequence (conversion_insns);
+             put_var_into_stack (parm);
+             conversion_insns = get_insns ();
+             end_sequence ();
+           }
        }
       else
        {
@@ -4928,7 +5028,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
@@ -4937,8 +5037,8 @@ assign_parms (fndecl)
        {
          tree result = DECL_RESULT (fndecl);
 
-         DECL_RTL (result)
-           = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
+         SET_DECL_RTL (result,
+                       gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm)));
 
          set_mem_attributes (DECL_RTL (result), result, 1);
        }
@@ -4997,7 +5097,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
@@ -5521,7 +5623,7 @@ trampoline_address (function)
   for (link = trampoline_list; link; link = TREE_CHAIN (link))
     if (TREE_PURPOSE (link) == function)
       return
-       round_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
+       adjust_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
 
   for (fp = outer_function_chain; fp; fp = fp->next)
     for (link = fp->x_trampoline_list; link; link = TREE_CHAIN (link))
@@ -5529,7 +5631,7 @@ trampoline_address (function)
        {
          tramp = fix_lexical_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0),
                                    function);
-         return round_trampoline_addr (tramp);
+         return adjust_trampoline_addr (tramp);
        }
 
   /* None exists; we must make one.  */
@@ -5580,7 +5682,7 @@ trampoline_address (function)
     }
 
   tramp = fix_lexical_addr (XEXP (tramp, 0), function);
-  return round_trampoline_addr (tramp);
+  return adjust_trampoline_addr (tramp);
 }
 
 /* Given a trampoline address,
@@ -5602,6 +5704,21 @@ round_trampoline_addr (tramp)
 #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 . */
+
+static rtx
+adjust_trampoline_addr (tramp)
+     rtx tramp;
+{
+  tramp = round_trampoline_addr (tramp);
+#ifdef TRAMPOLINE_ADJUST_ADDRESS
+  TRAMPOLINE_ADJUST_ADDRESS (tramp);
+#endif
+  return tramp;
+}
 \f
 /* Put all this function's BLOCK nodes including those that are chained
    onto the first block into a vector, and return it.
@@ -5725,6 +5842,7 @@ reorder_blocks ()
   BLOCK_SUBBLOCKS (block) = NULL_TREE;
   BLOCK_CHAIN (block) = NULL_TREE;
 
+  reorder_blocks_0 (get_insns ());
   reorder_blocks_1 (get_insns (), block, &block_stack);
 
   BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block));
@@ -5736,6 +5854,35 @@ reorder_blocks ()
    at INSNS.  Recurse for CALL_PLACEHOLDER insns.  */
 
 static void
+reorder_blocks_0 (insns)
+     rtx insns;
+{
+  rtx insn;
+
+  for (insn = insns; insn; insn = NEXT_INSN (insn))
+    {
+      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));
+       }
+    }
+}
+
+static void
 reorder_blocks_1 (insns, current_block, p_block_stack)
      rtx insns;
      tree current_block;
@@ -6062,7 +6209,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)))
@@ -6123,6 +6270,29 @@ expand_main_function ()
 \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.
@@ -6174,20 +6344,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
@@ -6219,43 +6379,37 @@ 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_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);
        }
     }
   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;
@@ -6278,10 +6432,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;
@@ -6345,20 +6499,18 @@ expand_function_start (subr, parms_have_cleanups)
                         Pmode);
     }
 
+#ifdef PROFILE_HOOK
+  if (profile_flag)
+    PROFILE_HOOK (profile_label_no);
+#endif
+
   /* 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 ();
@@ -6390,37 +6542,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)
@@ -6449,6 +6574,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
@@ -6478,6 +6614,7 @@ expand_function_end (filename, line, end_bindings)
      int end_bindings;
 {
   tree link;
+  rtx clobber_after;
 
 #ifdef TRAMPOLINE_TEMPLATE
   static rtx initial_trampoline;
@@ -6606,7 +6743,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
@@ -6614,63 +6751,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);
@@ -6686,6 +6794,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.  */
@@ -6703,7 +6816,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);
@@ -6744,6 +6857,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);
 
@@ -6763,8 +6880,8 @@ expand_function_end (filename, line, end_bindings)
   if (current_function_returns_struct
       || current_function_returns_pcc_struct)
     {
-      rtx value_address =
-       XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+      rtx value_address
+       XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
 #ifdef FUNCTION_OUTGOING_VALUE
       rtx outgoing
@@ -6772,27 +6889,52 @@ expand_function_end (filename, line, end_bindings)
                                   current_function_decl);
 #else
       rtx outgoing
-       = FUNCTION_VALUE (build_pointer_type (type),
-                         current_function_decl);
+       = FUNCTION_VALUE (build_pointer_type (type), current_function_decl);
 #endif
 
       /* Mark this as a function return value so integrate will delete the
         assignment and USE below when inlining this function.  */
       REG_FUNCTION_VALUE_P (outgoing) = 1;
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+      /* The address may be ptr_mode and OUTGOING may be Pmode.  */
+      if (GET_MODE (outgoing) != GET_MODE (value_address))
+       value_address = convert_memory_address (GET_MODE (outgoing),
+                                               value_address);
+#endif
+
       emit_move_insn (outgoing, value_address);
+
+      /* Show return register used to hold result (in this case the address
+        of the result.  */
+      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.  */
@@ -6934,7 +7076,8 @@ keep_stack_depressed (seq)
 
   /* If the epilogue is just a single instruction, it's OK as is */
 
-  if (GET_CODE (seq) != SEQUENCE) return;
+  if (GET_CODE (seq) != SEQUENCE)
+    return;
 
   /* Scan all insns in SEQ looking for ones that modified the stack
      pointer.  Record if it modified the stack pointer by copying it
@@ -7230,7 +7373,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)
        {
@@ -7248,7 +7397,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;
@@ -7333,6 +7482,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);
            }
        }
@@ -7389,6 +7541,7 @@ mark_temp_slot (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;
     }