OSDN Git Service

alphabatize irix___restrict
[pf3gnuchains/gcc-fork.git] / gcc / integrate.c
index cfab58a..576d824 100644 (file)
@@ -1,27 +1,29 @@
-/* Procedure integration for GNU CC.
-   Copyright (C) 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+/* Procedure integration for GCC.
+   Copyright (C) 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
-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.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "rtl.h"
 #include "tree.h"
@@ -42,12 +44,8 @@ Boston, MA 02111-1307, USA.  */
 #include "loop.h"
 #include "params.h"
 #include "ggc.h"
-
-#include "obstack.h"
-#define        obstack_chunk_alloc     xmalloc
-#define        obstack_chunk_free      free
-
-extern struct obstack *function_maybepermanent_obstack;
+#include "target.h"
+#include "langhooks.h"
 
 /* Similar, but round to the next highest integer that meets the
    alignment.  */
@@ -63,23 +61,17 @@ extern struct obstack *function_maybepermanent_obstack;
    ? (1 + (3 * list_length (DECL_ARGUMENTS (DECL))) / 2) \
    : (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))))
 #endif
-
-/* Decide whether a function with a target specific attribute
-   attached can be inlined.  By default we disallow this.  */
-#ifndef FUNCTION_ATTRIBUTE_INLINABLE_P
-#define FUNCTION_ATTRIBUTE_INLINABLE_P(FNDECL) 0
-#endif
 \f
 
-/* Private type used by {get/has}_func_hard_reg_initial_val. */
-typedef struct initial_value_pair {
+/* Private type used by {get/has}_func_hard_reg_initial_val.  */
+typedef struct initial_value_pair GTY(()) {
   rtx hard_reg;
   rtx pseudo;
 } initial_value_pair;
-typedef struct initial_value_struct {
+typedef struct initial_value_struct GTY(()) {
   int num_entries;
   int max_entries;
-  initial_value_pair *entries;
+  initial_value_pair * GTY ((length ("%h.num_entries"))) entries;
 } initial_value_struct;
 
 static void setup_initial_hard_reg_value_integration PARAMS ((struct function *, struct inline_remap *));
@@ -130,6 +122,30 @@ get_label_from_map (map, i)
   return x;
 }
 
+/* Return false if the function FNDECL cannot be inlined on account of its
+   attributes, true otherwise.  */
+bool
+function_attribute_inlinable_p (fndecl)
+     tree fndecl;
+{
+  if (targetm.attribute_table)
+    {
+      tree a;
+
+      for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a))
+       {
+         tree name = TREE_PURPOSE (a);
+         int i;
+
+         for (i = 0; targetm.attribute_table[i].name != NULL; i++)
+           if (is_attribute_p (targetm.attribute_table[i].name, name))
+             return (*targetm.function_attribute_inlinable_p) (fndecl);
+       }
+    }
+
+  return true;
+}
+
 /* Zero if the current function (whose FUNCTION_DECL is FNDECL)
    is safe and reasonable to integrate into other functions.
    Nonzero means value is a warning msgid with a single %s
@@ -137,9 +153,9 @@ get_label_from_map (map, i)
 
 const char *
 function_cannot_inline_p (fndecl)
-     register tree fndecl;
+     tree fndecl;
 {
-  register rtx insn;
+  rtx insn;
   tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
 
   /* For functions marked as inline increase the maximum size to
@@ -151,15 +167,14 @@ function_cannot_inline_p (fndecl)
                      + 8 * list_length (DECL_ARGUMENTS (fndecl)))
                   : INTEGRATE_THRESHOLD (fndecl);
 
-  register int ninsns = 0;
-  register tree parms;
+  int ninsns = 0;
+  tree parms;
 
   if (DECL_UNINLINABLE (fndecl))
     return N_("function cannot be inline");
 
   /* No inlines with varargs.  */
-  if ((last && TREE_VALUE (last) != void_type_node)
-      || current_function_varargs)
+  if (last && TREE_VALUE (last) != void_type_node)
     return N_("varargs function cannot be inline");
 
   if (current_function_calls_alloca)
@@ -232,7 +247,7 @@ function_cannot_inline_p (fndecl)
 
   /* We will not inline a function which uses computed goto.  The addresses of
      its local labels, which may be tucked into global storage, are of course
-     not constant across instantiations, which causes unexpected behaviour.  */
+     not constant across instantiations, which causes unexpected behavior.  */
   if (current_function_has_computed_jump)
     return N_("function with computed jump cannot inline");
 
@@ -249,10 +264,9 @@ function_cannot_inline_p (fndecl)
     }
 
   /* If the function has a target specific attribute attached to it,
-     then we assume that we should not inline it.  This can be overriden
-     by the target if it defines FUNCTION_ATTRIBUTE_INLINABLE_P.  */
-  if (DECL_MACHINE_ATTRIBUTES (fndecl)
-      && ! FUNCTION_ATTRIBUTE_INLINABLE_P (fndecl))
+     then we assume that we should not inline it.  This can be overridden
+     by the target if it defines TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P.  */
+  if (!function_attribute_inlinable_p (fndecl))
     return N_("function with target specific attribute(s) cannot be inlined");
 
   return NULL;
@@ -332,18 +346,41 @@ copy_decl_for_inlining (decl, from_fn, to_fn)
   /* Copy the declaration.  */
   if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL)
     {
+      tree type;
+      int invisiref = 0;
+
+      /* See if the frontend wants to pass this by invisible reference.  */
+      if (TREE_CODE (decl) == PARM_DECL
+         && DECL_ARG_TYPE (decl) != TREE_TYPE (decl)
+         && POINTER_TYPE_P (DECL_ARG_TYPE (decl))
+         && TREE_TYPE (DECL_ARG_TYPE (decl)) == TREE_TYPE (decl))
+       {
+         invisiref = 1;
+         type = DECL_ARG_TYPE (decl);
+       }
+      else
+       type = TREE_TYPE (decl);
+
       /* For a parameter, we must make an equivalent VAR_DECL, not a
         new PARM_DECL.  */
-      copy = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
-      TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
-      TREE_READONLY (copy) = TREE_READONLY (decl);
-      TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
+      copy = build_decl (VAR_DECL, DECL_NAME (decl), type);
+      if (!invisiref)
+       {
+         TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
+         TREE_READONLY (copy) = TREE_READONLY (decl);
+         TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
+       }
+      else
+       {
+         TREE_ADDRESSABLE (copy) = 0;
+         TREE_READONLY (copy) = 1;
+         TREE_THIS_VOLATILE (copy) = 0;
+       }
     }
   else
     {
       copy = copy_node (decl);
-      if (DECL_LANG_SPECIFIC (copy))
-       copy_lang_decl (copy);
+      (*lang_hooks.dup_lang_specific_decl) (copy);
 
       /* TREE_ADDRESSABLE isn't used to indicate that a label's
         address has been taken; it's for internal bookkeeping in
@@ -357,7 +394,8 @@ copy_decl_for_inlining (decl, from_fn, to_fn)
   DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (decl);
 
   /* The new variable/label has no RTL, yet.  */
-  SET_DECL_RTL (copy, NULL_RTX);
+  if (!TREE_STATIC (copy) && !DECL_EXTERNAL (copy))
+    SET_DECL_RTL (copy, NULL_RTX);
 
   /* These args would always appear unused, if not for this.  */
   TREE_USED (copy) = 1;
@@ -368,10 +406,10 @@ copy_decl_for_inlining (decl, from_fn, to_fn)
     ;
   else if (DECL_CONTEXT (decl) != from_fn)
     /* Things that weren't in the scope of the function we're inlining
-       from aren't in the scope we're inlining too, either.  */
+       from aren't in the scope we're inlining to, either.  */
     ;
   else if (TREE_STATIC (decl))
-    /* Function-scoped static variables should say in the original
+    /* Function-scoped static variables should stay in the original
        function.  */
     ;
   else
@@ -414,8 +452,8 @@ save_for_inline (fndecl)
      Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values
      for the parms, prior to elimination of virtual registers.
      These values are needed for substituting parms properly.  */
-
-  parmdecl_map = (tree *) xmalloc (max_parm_reg * sizeof (tree));
+  if (! flag_no_inline)
+    parmdecl_map = (tree *) xmalloc (max_parm_reg * sizeof (tree));
 
   /* Make and emit a return-label if we have not already done so.  */
 
@@ -425,14 +463,17 @@ save_for_inline (fndecl)
       emit_label (return_label);
     }
 
-  argvec = initialize_for_inline (fndecl);
+  if (! flag_no_inline)
+    argvec = initialize_for_inline (fndecl);
+  else
+    argvec = NULL;
 
   /* Delete basic block notes created by early run of find_basic_block.
      The notes would be later used by find_basic_blocks to reuse the memory
      for basic_block structures on already freed obstack.  */
   for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK)
-      delete_insn (insn);
+      delete_related_insns (insn);
 
   /* If there are insns that copy parms from the stack into pseudo registers,
      those insns are not copied.  `expand_inline_function' must
@@ -442,27 +483,31 @@ save_for_inline (fndecl)
   if (GET_CODE (insn) != NOTE)
     abort ();
 
-  /* Get the insn which signals the end of parameter setup code.  */
-  first_nonparm_insn = get_first_nonparm_insn ();
-
-  /* Now just scan the chain of insns to see what happens to our
-     PARM_DECLs.  If a PARM_DECL is used but never modified, we
-     can substitute its rtl directly when expanding inline (and
-     perform constant folding when its incoming value is constant).
-     Otherwise, we have to copy its value into a new register and track
-     the new register's life.  */
-  in_nonparm_insns = 0;
-  save_parm_insns (insn, first_nonparm_insn);
-
-  cfun->inl_max_label_num = max_label_num ();
-  cfun->inl_last_parm_insn = cfun->x_last_parm_insn;
-  cfun->original_arg_vector = argvec;
+  if (! flag_no_inline)
+    {
+      /* Get the insn which signals the end of parameter setup code.  */
+      first_nonparm_insn = get_first_nonparm_insn ();
+
+      /* Now just scan the chain of insns to see what happens to our
+        PARM_DECLs.  If a PARM_DECL is used but never modified, we
+        can substitute its rtl directly when expanding inline (and
+        perform constant folding when its incoming value is
+        constant).  Otherwise, we have to copy its value into a new
+        register and track the new register's life.  */
+      in_nonparm_insns = 0;
+      save_parm_insns (insn, first_nonparm_insn);
+
+      cfun->inl_max_label_num = max_label_num ();
+      cfun->inl_last_parm_insn = cfun->x_last_parm_insn;
+      cfun->original_arg_vector = argvec;
+    }
   cfun->original_decl_initial = DECL_INITIAL (fndecl);
   cfun->no_debugging_symbols = (write_symbols == NO_DEBUG);
   DECL_SAVED_INSNS (fndecl) = cfun;
 
   /* Clean up.  */
-  free (parmdecl_map);
+  if (! flag_no_inline)
+    free (parmdecl_map);
 }
 
 /* Scan the chain of insns to see what happens to our PARM_DECLs.  If a
@@ -562,7 +607,8 @@ process_reg_param (map, loc, copy)
 }
 
 /* Compare two BLOCKs for qsort.  The key we sort on is the
-   BLOCK_ABSTRACT_ORIGIN of the blocks.  */
+   BLOCK_ABSTRACT_ORIGIN of the blocks.  We cannot just subtract the
+   two pointers, because it may overflow sizeof(int).  */
 
 static int
 compare_blocks (v1, v2)
@@ -571,9 +617,12 @@ compare_blocks (v1, v2)
 {
   tree b1 = *((const tree *) v1);
   tree b2 = *((const tree *) v2);
+  char *p1 = (char *) BLOCK_ABSTRACT_ORIGIN (b1);
+  char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2);
 
-  return ((char *) BLOCK_ABSTRACT_ORIGIN (b1)
-         - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
+  if (p1 == p2)
+    return 0;
+  return p1 < p2 ? -1 : 1;
 }
 
 /* Compare two BLOCKs for bsearch.  The first pointer corresponds to
@@ -586,8 +635,12 @@ find_block (v1, v2)
 {
   const union tree_node *b1 = (const union tree_node *) v1;
   tree b2 = *((const tree *) v2);
+  char *p1 = (char *) b1;
+  char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2);
 
-  return ((const char *) b1 - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
+  if (p1 == p2)
+    return 0;
+  return p1 < p2 ? -1 : 1;
 }
 
 /* Integrate the procedure defined by FNDECL.  Note that this function
@@ -622,7 +675,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   tree *arg_trees;
   rtx *arg_vals;
   int max_regno;
-  register int i;
+  int i;
   int min_labelno = inl_f->emit->x_first_label_num;
   int max_labelno = inl_f->inl_max_label_num;
   int nargs;
@@ -630,10 +683,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   rtx stack_save = 0;
   rtx temp;
   struct inline_remap *map = 0;
-#ifdef HAVE_cc0
-  rtx cc0_insn = 0;
-#endif
-  rtvec arg_vector = (rtvec) inl_f->original_arg_vector;
+  rtvec arg_vector = inl_f->original_arg_vector;
   rtx static_chain_value = 0;
   int inl_max_uid;
   int eh_region_offset;
@@ -668,7 +718,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
       enum machine_mode mode;
 
       if (actual == 0)
-       return (rtx) (HOST_WIDE_INT) -1;
+       return (rtx) (size_t) -1;
 
       arg = TREE_VALUE (actual);
       mode = TYPE_MODE (DECL_ARG_TYPE (formal));
@@ -681,7 +731,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          || (mode == BLKmode
              && (TYPE_MAIN_VARIANT (TREE_TYPE (arg))
                  != TYPE_MAIN_VARIANT (TREE_TYPE (formal)))))
-       return (rtx) (HOST_WIDE_INT) -1;
+       return (rtx) (size_t) -1;
     }
 
   /* Extra arguments are valid, but will be ignored below, so we must
@@ -814,7 +864,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 
      ??? These numbers are quite arbitrary and were obtained by
      experimentation.  At some point, we should try to allocate the
-     table after all the parameters are set up so we an more accurately
+     table after all the parameters are set up so we can more accurately
      estimate the number of pseudos we will need.  */
 
   VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray,
@@ -849,6 +899,11 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   if (inl_f->needs_context)
     static_chain_value = lookup_static_chain (fndecl);
 
+  /* If the inlined function calls __builtin_constant_p, then we'll
+     need to call purge_builtin_constant_p on this function.  */
+  if (inl_f->calls_constant_p)
+    current_function_calls_constant_p = 1;
+
   if (GET_CODE (parm_insns) == NOTE
       && NOTE_LINE_NUMBER (parm_insns) > 0)
     {
@@ -1044,7 +1099,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
       /* The function returns an object in a register and we use the return
         value.  Set up our target for remapping.  */
 
-      /* Machine mode function was declared to return.   */
+      /* Machine mode function was declared to return.  */
       enum machine_mode departing_mode = TYPE_MODE (type);
       /* (Possibly wider) machine mode it actually computes
         (for the sake of callers that fail to declare it right).
@@ -1210,7 +1265,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
        this block to the list of blocks at this binding level.  We
        can't do it the way it's done for function-at-a-time mode the
        superblocks have not been created yet.  */
-    insert_block (block);
+    (*lang_hooks.decls.insert_block) (block);
   else
     {
       BLOCK_CHAIN (block)
@@ -1256,7 +1311,6 @@ expand_inline_function (fndecl, parms, target, ignore, type,
     free (real_label_map);
   VARRAY_FREE (map->const_equiv_varray);
   free (map->reg_map);
-  VARRAY_FREE (map->block_map);
   free (map->insn_map);
   free (map);
   free (arg_vals);
@@ -1273,7 +1327,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 
    Copying is done in two passes, first the insns and then their REG_NOTES.
 
-   If static_chain_value is non-zero, it represents the context-pointer
+   If static_chain_value is nonzero, it represents the context-pointer
    register for the function.  */
 
 static void
@@ -1282,12 +1336,13 @@ copy_insn_list (insns, map, static_chain_value)
      struct inline_remap *map;
      rtx static_chain_value;
 {
-  register int i;
+  int i;
   rtx insn;
   rtx temp;
 #ifdef HAVE_cc0
   rtx cc0_insn = 0;
 #endif
+  rtx static_chain_mem = 0;
 
   /* Copy the insns one by one.  Do this in two passes, first the insns and
      then their REG_NOTES.  */
@@ -1351,25 +1406,62 @@ copy_insn_list (insns, map, static_chain_value)
                   && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
            break;
 
-         /* If this is setting the static chain rtx, omit it.  */
+         /* Look for the address of the static chain slot. The
+             rtx_equal_p comparisons against the
+             static_chain_incoming_rtx below may fail if the static
+             chain is in memory and the address specified is not
+             "legitimate".  This happens on Xtensa where the static
+             chain is at a negative offset from argp and where only
+             positive offsets are legitimate.  When the RTL is
+             generated, the address is "legitimized" by copying it
+             into a register, causing the rtx_equal_p comparisons to
+             fail.  This workaround looks for code that sets a
+             register to the address of the static chain.  Subsequent
+             memory references via that register can then be
+             identified as static chain references.  We assume that
+             the register is only assigned once, and that the static
+             chain address is only live in one register at a time.  */
+
          else if (static_chain_value != 0
                   && set != 0
+                  && GET_CODE (static_chain_incoming_rtx) == MEM
                   && GET_CODE (SET_DEST (set)) == REG
-                  && rtx_equal_p (SET_DEST (set),
-                                  static_chain_incoming_rtx))
+                  && rtx_equal_p (SET_SRC (set),
+                                  XEXP (static_chain_incoming_rtx, 0)))
+           {
+             static_chain_mem =
+                 gen_rtx_MEM (GET_MODE (static_chain_incoming_rtx),
+                              SET_DEST (set));
+
+             /* emit the instruction in case it is used for something
+                other than setting the static chain; if it's not used,
+                it can always be removed as dead code */
+             copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0));
+           }
+
+         /* If this is setting the static chain rtx, omit it.  */
+         else if (static_chain_value != 0
+                  && set != 0
+                  && (rtx_equal_p (SET_DEST (set),
+                                   static_chain_incoming_rtx)
+                      || (static_chain_mem
+                          && rtx_equal_p (SET_DEST (set), static_chain_mem))))
            break;
 
          /* If this is setting the static chain pseudo, set it from
             the value we want to give it instead.  */
          else if (static_chain_value != 0
                   && set != 0
-                  && rtx_equal_p (SET_SRC (set),
-                                  static_chain_incoming_rtx))
+                  && (rtx_equal_p (SET_SRC (set),
+                                   static_chain_incoming_rtx)
+                      || (static_chain_mem
+                          && rtx_equal_p (SET_SRC (set), static_chain_mem))))
            {
              rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map, 1);
 
              copy = emit_move_insn (newdest, static_chain_value);
-             static_chain_value = 0;
+             if (GET_CODE (static_chain_incoming_rtx) != MEM)
+               static_chain_value = 0;
            }
 
          /* If this is setting the virtual stack vars register, this must
@@ -1436,6 +1528,7 @@ copy_insn_list (insns, map, static_chain_value)
 #else
          try_constants (copy, map);
 #endif
+         INSN_SCOPE (copy) = INSN_SCOPE (insn);
          break;
 
        case JUMP_INSN:
@@ -1456,6 +1549,7 @@ copy_insn_list (insns, map, static_chain_value)
          cc0_insn = 0;
 #endif
          try_constants (copy, map);
+         INSN_SCOPE (copy) = INSN_SCOPE (insn);
 
          /* If this used to be a conditional jump insn but whose branch
             direction is now know, we must do something special.  */
@@ -1463,14 +1557,14 @@ copy_insn_list (insns, map, static_chain_value)
            {
 #ifdef HAVE_cc0
              /* If the previous insn set cc0 for us, delete it.  */
-             if (sets_cc0_p (PREV_INSN (copy)))
-               delete_insn (PREV_INSN (copy));
+             if (only_sets_cc0_p (PREV_INSN (copy)))
+               delete_related_insns (PREV_INSN (copy));
 #endif
 
              /* If this is now a no-op, delete it.  */
              if (map->last_pc_value == pc_rtx)
                {
-                 delete_insn (copy);
+                 delete_related_insns (copy);
                  copy = 0;
                }
              else
@@ -1522,7 +1616,8 @@ copy_insn_list (insns, map, static_chain_value)
          copy = emit_call_insn (pattern);
 
          SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn);
-         CONST_CALL_P (copy) = CONST_CALL_P (insn);
+         CONST_OR_PURE_CALL_P (copy) = CONST_OR_PURE_CALL_P (insn);
+         INSN_SCOPE (copy) = INSN_SCOPE (insn);
 
          /* Because the USAGE information potentially contains objects other
             than hard registers, we need to copy it.  */
@@ -1555,6 +1650,15 @@ copy_insn_list (insns, map, static_chain_value)
          break;
 
        case NOTE:
+         if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)
+           {
+             copy = emit_label (get_label_from_map (map,
+                                                   CODE_LABEL_NUMBER (insn)));
+             LABEL_NAME (copy) = NOTE_SOURCE_FILE (insn);
+             map->const_age++;
+             break;
+           }
+
          /* NOTE_INSN_FUNCTION_END and NOTE_INSN_FUNCTION_BEG are
             discarded because it is important to have only one of
             each in the current function.
@@ -1646,7 +1750,8 @@ copy_insn_notes (insns, map, eh_region_offset)
              next = XEXP (note, 1);
              if (REG_NOTE_KIND (note) == REG_LABEL)
                remove_note (new_insn, note);
-             else if (REG_NOTE_KIND (note) == REG_EH_REGION)
+             else if (REG_NOTE_KIND (note) == REG_EH_REGION
+                      && INTVAL (XEXP (note, 0)) > 0)
                XEXP (note, 0) = GEN_INT (INTVAL (XEXP (note, 0))
                                          + eh_region_offset);
            }
@@ -1675,8 +1780,8 @@ integrate_parm_decls (args, map, arg_vector)
      struct inline_remap *map;
      rtvec arg_vector;
 {
-  register tree tail;
-  register int i;
+  tree tail;
+  int i;
 
   for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
     {
@@ -1737,6 +1842,7 @@ integrate_decl_tree (let, map)
          r = DECL_RTL (d);
          subst_constants (&r, NULL_RTX, map, 1);
          SET_DECL_RTL (d, r);
+
          apply_change_group ();
        }
 
@@ -1777,15 +1883,15 @@ integrate_decl_tree (let, map)
 
 rtx
 copy_rtx_and_substitute (orig, map, for_lhs)
-     register rtx orig;
+     rtx orig;
      struct inline_remap *map;
      int for_lhs;
 {
-  register rtx copy, temp;
-  register int i, j;
-  register RTX_CODE code;
-  register enum machine_mode mode;
-  register const char *format_ptr;
+  rtx copy, temp;
+  int i, j;
+  RTX_CODE code;
+  enum machine_mode mode;
+  const char *format_ptr;
   int regno;
 
   if (orig == 0)
@@ -1853,7 +1959,7 @@ copy_rtx_and_substitute (orig, map, for_lhs)
 
              SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
 
-             seq = gen_sequence ();
+             seq = get_insns ();
              end_sequence ();
              emit_insn_after (seq, map->insns_at_start);
              return temp;
@@ -1886,7 +1992,7 @@ copy_rtx_and_substitute (orig, map, for_lhs)
 
              SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
 
-             seq = gen_sequence ();
+             seq = get_insns ();
              end_sequence ();
              emit_insn_after (seq, map->insns_at_start);
              return temp;
@@ -1973,7 +2079,17 @@ copy_rtx_and_substitute (orig, map, for_lhs)
          RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (temp);
          /* A reg with REG_FUNCTION_VALUE_P true will never reach here.  */
 
-         if (REG_POINTER (map->x_regno_reg_rtx[regno]))
+         /* Objects may initially be represented as registers, but
+            but turned into a MEM if their address is taken by
+            put_var_into_stack.  Therefore, the register table may have
+            entries which are MEMs.
+
+            We briefly tried to clear such entries, but that ended up
+            cascading into many changes due to the optimizers not being
+            prepared for empty entries in the register table.  So we've
+            decided to allow the MEMs in the register table for now.  */
+         if (REG_P (map->x_regno_reg_rtx[regno])
+             && REG_POINTER (map->x_regno_reg_rtx[regno]))
            mark_reg_pointer (map->reg_map[regno],
                              map->regno_pointer_align[regno]);
          regno = REGNO (map->reg_map[regno]);
@@ -1992,18 +2108,18 @@ copy_rtx_and_substitute (orig, map, for_lhs)
        copy = SUBREG_REG (copy);
       return gen_rtx_fmt_e (code, VOIDmode, copy);
 
+    /* We need to handle "deleted" labels that appear in the DECL_RTL
+       of a LABEL_DECL.  */
+    case NOTE:
+      if (NOTE_LINE_NUMBER (orig) != NOTE_INSN_DELETED_LABEL)
+       break;
+
+      /* ... FALLTHRU ...  */
     case CODE_LABEL:
       LABEL_PRESERVE_P (get_label_from_map (map, CODE_LABEL_NUMBER (orig)))
        = LABEL_PRESERVE_P (orig);
       return get_label_from_map (map, CODE_LABEL_NUMBER (orig));
 
-    /* We need to handle "deleted" labels that appear in the DECL_RTL
-       of a LABEL_DECL.  */
-    case NOTE:
-      if (NOTE_LINE_NUMBER (orig) == NOTE_INSN_DELETED_LABEL)
-       return map->insn_map[INSN_UID (orig)];
-      break;
-
     case LABEL_REF:
       copy
        = gen_rtx_LABEL_REF
@@ -2033,6 +2149,7 @@ copy_rtx_and_substitute (orig, map, for_lhs)
     case PC:
     case CC0:
     case CONST_INT:
+    case CONST_VECTOR:
       return orig;
 
     case SYMBOL_REF:
@@ -2113,7 +2230,7 @@ copy_rtx_and_substitute (orig, map, for_lhs)
       if (map->orig_asm_operands_vector == ASM_OPERANDS_INPUT_VEC (orig))
        {
          copy = rtx_alloc (ASM_OPERANDS);
-         copy->volatil = orig->volatil;
+         RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil);
          PUT_MODE (copy, GET_MODE (orig));
          ASM_OPERANDS_TEMPLATE (copy) = ASM_OPERANDS_TEMPLATE (orig);
          ASM_OPERANDS_OUTPUT_CONSTRAINT (copy)
@@ -2136,13 +2253,18 @@ copy_rtx_and_substitute (orig, map, for_lhs)
 #ifndef NO_FUNCTION_CSE
       if (! (optimize && ! flag_no_function_cse))
 #endif
-       return
-         gen_rtx_CALL
-           (GET_MODE (orig),
-            gen_rtx_MEM (GET_MODE (XEXP (orig, 0)),
-                         copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0),
-                                                  map, 0)),
-            copy_rtx_and_substitute (XEXP (orig, 1), map, 0));
+       {
+         rtx copy
+           = gen_rtx_MEM (GET_MODE (XEXP (orig, 0)),
+                          copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0),
+                                                   map, 0));
+
+         MEM_COPY_ATTRIBUTES (copy, XEXP (orig, 0));
+
+         return
+           gen_rtx_CALL (GET_MODE (orig), copy, 
+                         copy_rtx_and_substitute (XEXP (orig, 1), map, 0));
+       }
       break;
 
 #if 0
@@ -2209,10 +2331,23 @@ copy_rtx_and_substitute (orig, map, for_lhs)
          return validize_mem (force_const_mem (const_mode, constant));
        }
 
-      copy = rtx_alloc (MEM);
-      PUT_MODE (copy, mode);
-      XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map, 0);
+      copy = gen_rtx_MEM (mode, copy_rtx_and_substitute (XEXP (orig, 0),
+                                                        map, 0));
       MEM_COPY_ATTRIBUTES (copy, orig);
+
+      /* If inlining and this is not for the LHS, turn off RTX_UNCHANGING_P
+        since this may be an indirect reference to a parameter and the
+        actual may not be readonly.  */
+      if (inlining && !for_lhs)
+       RTX_UNCHANGING_P (copy) = 0;
+
+      /* If inlining, squish aliasing data that references the subroutine's
+        parameter list, since that's no longer applicable.  */
+      if (inlining && MEM_EXPR (copy)
+         && TREE_CODE (MEM_EXPR (copy)) == INDIRECT_REF
+         && TREE_CODE (TREE_OPERAND (MEM_EXPR (copy), 0)) == PARM_DECL)
+       set_mem_expr (copy, NULL_TREE);
+
       return copy;
 
     default:
@@ -2221,9 +2356,9 @@ copy_rtx_and_substitute (orig, map, for_lhs)
 
   copy = rtx_alloc (code);
   PUT_MODE (copy, mode);
-  copy->in_struct = orig->in_struct;
-  copy->volatil = orig->volatil;
-  copy->unchanging = orig->unchanging;
+  RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct);
+  RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil);
+  RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging);
 
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
@@ -2367,9 +2502,9 @@ subst_constants (loc, insn, map, memonly)
      int memonly;
 {
   rtx x = *loc;
-  register int i, j;
-  register enum rtx_code code;
-  register const char *format_ptr;
+  int i, j;
+  enum rtx_code code;
+  const char *format_ptr;
   int num_changes = num_validated_changes ();
   rtx new = 0;
   enum machine_mode op0_mode = MAX_MACHINE_MODE;
@@ -2381,6 +2516,7 @@ subst_constants (loc, insn, map, memonly)
     case PC:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case CONST:
     case LABEL_REF:
@@ -2475,10 +2611,7 @@ subst_constants (loc, insn, map, memonly)
          {
            src = SET_SRC (x);
            if (GET_MODE_CLASS (GET_MODE (src)) == MODE_CC
-#ifdef HAVE_cc0
-               || dest == cc0_rtx
-#endif
-               )
+               || CC0_P (dest))
              {
                compare_mode = GET_MODE (XEXP (src, 0));
                if (compare_mode == VOIDmode)
@@ -2530,9 +2663,7 @@ subst_constants (loc, insn, map, memonly)
                        || REGNO (XEXP (src, 0)) == VIRTUAL_STACK_VARS_REGNUM)
                    && CONSTANT_P (XEXP (src, 1)))
                || GET_CODE (src) == COMPARE
-#ifdef HAVE_cc0
-               || dest == cc0_rtx
-#endif
+               || CC0_P (dest)
                || (dest == pc_rtx
                    && (src == pc_rtx || GET_CODE (src) == RETURN
                        || GET_CODE (src) == LABEL_REF))))
@@ -2546,10 +2677,7 @@ subst_constants (loc, insn, map, memonly)
            if (compare_mode != VOIDmode
                && GET_CODE (src) == COMPARE
                && (GET_MODE_CLASS (GET_MODE (src)) == MODE_CC
-#ifdef HAVE_cc0
-                   || dest == cc0_rtx
-#endif
-                   )
+                   || CC0_P (dest))
                && GET_MODE (XEXP (src, 0)) == VOIDmode
                && GET_MODE (XEXP (src, 1)) == VOIDmode)
              {
@@ -2588,6 +2716,7 @@ subst_constants (loc, insn, map, memonly)
        case 'w':
        case 'n':
        case 't':
+       case 'B':
          break;
 
        case 'E':
@@ -2640,7 +2769,10 @@ subst_constants (loc, insn, map, memonly)
                new = CONST0_RTX (mode);
              else
                {
-                 REAL_VALUE_TYPE val = FLOAT_STORE_FLAG_VALUE (mode);
+                 REAL_VALUE_TYPE val;
+
+                 /* Avoid automatic aggregate initialization.  */
+                 val = FLOAT_STORE_FLAG_VALUE (mode);
                  new = CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
                }
            }
@@ -2751,14 +2883,14 @@ mark_stores (dest, x, data)
 
 static void
 set_block_origin_self (stmt)
-     register tree stmt;
+     tree stmt;
 {
   if (BLOCK_ABSTRACT_ORIGIN (stmt) == NULL_TREE)
     {
       BLOCK_ABSTRACT_ORIGIN (stmt) = stmt;
 
       {
-       register tree local_decl;
+       tree local_decl;
 
        for (local_decl = BLOCK_VARS (stmt);
             local_decl != NULL_TREE;
@@ -2767,7 +2899,7 @@ set_block_origin_self (stmt)
       }
 
       {
-       register tree subblock;
+       tree subblock;
 
        for (subblock = BLOCK_SUBBLOCKS (stmt);
             subblock != NULL_TREE;
@@ -2790,14 +2922,14 @@ set_block_origin_self (stmt)
 
 void
 set_decl_origin_self (decl)
-     register tree decl;
+     tree decl;
 {
   if (DECL_ABSTRACT_ORIGIN (decl) == NULL_TREE)
     {
       DECL_ABSTRACT_ORIGIN (decl) = decl;
       if (TREE_CODE (decl) == FUNCTION_DECL)
        {
-         register tree arg;
+         tree arg;
 
          for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
            DECL_ABSTRACT_ORIGIN (arg) = arg;
@@ -2815,11 +2947,11 @@ set_decl_origin_self (decl)
 
 static void
 set_block_abstract_flags (stmt, setting)
-     register tree stmt;
-     register int setting;
+     tree stmt;
+     int setting;
 {
-  register tree local_decl;
-  register tree subblock;
+  tree local_decl;
+  tree subblock;
 
   BLOCK_ABSTRACT (stmt) = setting;
 
@@ -2842,13 +2974,13 @@ set_block_abstract_flags (stmt, setting)
 
 void
 set_decl_abstract_flags (decl, setting)
-     register tree decl;
-     register int setting;
+     tree decl;
+     int setting;
 {
   DECL_ABSTRACT (decl) = setting;
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
-      register tree arg;
+      tree arg;
 
       for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
        DECL_ABSTRACT (arg) = setting;
@@ -2862,18 +2994,19 @@ set_decl_abstract_flags (decl, setting)
    from its DECL_SAVED_INSNS.  Used for inline functions that are output
    at end of compilation instead of where they came in the source.  */
 
+static GTY(()) struct function *old_cfun;
+
 void
 output_inline_function (fndecl)
      tree fndecl;
 {
-  struct function *old_cfun = cfun;
   enum debug_info_type old_write_symbols = write_symbols;
-  struct gcc_debug_hooks *old_debug_hooks = debug_hooks;
+  const struct gcc_debug_hooks *const old_debug_hooks = debug_hooks;
   struct function *f = DECL_SAVED_INSNS (fndecl);
 
+  old_cfun = cfun;
   cfun = f;
   current_function_decl = fndecl;
-  clear_emit_caches ();
 
   set_new_last_label_num (f->inl_max_label_num);
 
@@ -2887,15 +3020,15 @@ output_inline_function (fndecl)
       debug_hooks = &do_nothing_debug_hooks;
     }
 
-  /* Do any preparation, such as emitting abstract debug info for the inline
-     before it gets mangled by optimization.  */
-  (*debug_hooks->outlining_inline_function) (fndecl);
+  /* Make sure warnings emitted by the optimizers (e.g. control reaches
+     end of non-void function) is not wildly incorrect.  */
+  input_filename = DECL_SOURCE_FILE (fndecl);
+  lineno = DECL_SOURCE_LINE (fndecl);
 
-  /* Compile this function all the way down to assembly code.  */
+  /* Compile this function all the way down to assembly code.  As a
+     side effect this destroys the saved RTL representation, but
+     that's okay, because we don't need to inline this anymore.  */
   rest_of_compilation (fndecl);
-
-  /* We can't inline this anymore.  */
-  f->inlinable = 0;
   DECL_INLINE (fndecl) = 0;
 
   cfun = old_cfun;
@@ -2909,6 +3042,24 @@ output_inline_function (fndecl)
    the function.  */
 
 rtx
+get_hard_reg_initial_reg (fun, reg)
+     struct function *fun;
+     rtx reg;
+{
+  struct initial_value_struct *ivs = fun->hard_reg_initial_vals;
+  int i;
+
+  if (ivs == 0)
+    return NULL_RTX;
+
+  for (i = 0; i < ivs->num_entries; i++)
+    if (rtx_equal_p (ivs->entries[i].pseudo, reg))
+      return ivs->entries[i].hard_reg;
+
+  return NULL_RTX;
+}
+
+rtx
 has_func_hard_reg_initial_val (fun, reg)
      struct function *fun;
      rtx reg;
@@ -2939,20 +3090,20 @@ get_func_hard_reg_initial_val (fun, reg)
 
   if (ivs == 0)
     {
-      fun->hard_reg_initial_vals = (void *) xmalloc (sizeof (initial_value_struct));
+      fun->hard_reg_initial_vals = (void *) ggc_alloc (sizeof (initial_value_struct));
       ivs = fun->hard_reg_initial_vals;
       ivs->num_entries = 0;
       ivs->max_entries = 5;
-      ivs->entries = (initial_value_pair *) xmalloc (5 * sizeof (initial_value_pair));
+      ivs->entries = (initial_value_pair *) ggc_alloc (5 * sizeof (initial_value_pair));
     }
 
   if (ivs->num_entries >= ivs->max_entries)
     {
       ivs->max_entries += 5;
       ivs->entries = 
-       (initial_value_pair *) xrealloc (ivs->entries,
-                                        ivs->max_entries
-                                        * sizeof (initial_value_pair));
+       (initial_value_pair *) ggc_realloc (ivs->entries,
+                                           ivs->max_entries
+                                           * sizeof (initial_value_pair));
     }
 
   ivs->entries[ivs->num_entries].hard_reg = reg;
@@ -2977,23 +3128,6 @@ has_hard_reg_initial_val (mode, regno)
   return has_func_hard_reg_initial_val (cfun, gen_rtx_REG (mode, regno));
 }
 
-void
-mark_hard_reg_initial_vals (fun)
-     struct function *fun;
-{
-  struct initial_value_struct *ivs = fun->hard_reg_initial_vals;
-  int i;
-
-  if (ivs == 0)
-    return;
-
-  for (i = 0; i < ivs->num_entries; i ++)
-    {
-      ggc_mark_rtx (ivs->entries[i].hard_reg);
-      ggc_mark_rtx (ivs->entries[i].pseudo);
-    }
-}
-
 static void
 setup_initial_hard_reg_value_integration (inl_f, remap)
      struct function *inl_f;
@@ -3027,5 +3161,41 @@ emit_initial_value_sets ()
   seq = get_insns ();
   end_sequence ();
 
-  emit_insns_after (seq, get_insns ());
+  emit_insn_after (seq, get_insns ());
 }
+
+/* If the backend knows where to allocate pseudos for hard
+   register initial values, register these allocations now.  */
+void
+allocate_initial_values (reg_equiv_memory_loc)
+     rtx *reg_equiv_memory_loc ATTRIBUTE_UNUSED;
+{
+#ifdef ALLOCATE_INITIAL_VALUE
+  struct initial_value_struct *ivs = cfun->hard_reg_initial_vals;
+  int i;
+
+  if (ivs == 0)
+    return;
+
+  for (i = 0; i < ivs->num_entries; i++)
+    {
+      int regno = REGNO (ivs->entries[i].pseudo);
+      rtx x = ALLOCATE_INITIAL_VALUE (ivs->entries[i].hard_reg);
+
+      if (x == NULL_RTX || REG_N_SETS (REGNO (ivs->entries[i].pseudo)) > 1)
+       ; /* Do nothing.  */
+      else if (GET_CODE (x) == MEM)
+       reg_equiv_memory_loc[regno] = x;
+      else if (GET_CODE (x) == REG)
+       {
+         reg_renumber[regno] = REGNO (x);
+         /* Poke the regno right into regno_reg_rtx
+            so that even fixed regs are accepted.  */
+         REGNO (ivs->entries[i].pseudo) = REGNO (x);
+       }
+      else abort ();
+    }
+#endif
+}
+
+#include "gt-integrate.h"