OSDN Git Service

2005-10-31 Andrew Pinski <pinskia@physics.uc.edu>
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 61fe66d..b17a597 100644 (file)
@@ -1,5 +1,5 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
 This file is part of GCC.
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 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.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -32,23 +32,58 @@ Boston, MA 02111-1307, USA.  */
 #include "params.h"
 #include "input.h"
 #include "insn-config.h"
-#include "integrate.h"
 #include "varray.h"
 #include "hashtab.h"
-#include "pointer-set.h"
 #include "splay-tree.h"
 #include "langhooks.h"
+#include "basic-block.h"
+#include "tree-iterator.h"
 #include "cgraph.h"
 #include "intl.h"
 #include "tree-mudflap.h"
+#include "tree-flow.h"
 #include "function.h"
+#include "ggc.h"
+#include "tree-flow.h"
 #include "diagnostic.h"
+#include "except.h"
+#include "debug.h"
+#include "pointer-set.h"
+#include "ipa-prop.h"
 
 /* I'm not real happy about this, but we need to handle gimple and
    non-gimple trees.  */
-#include "tree-iterator.h"
 #include "tree-gimple.h"
 
+/* Inlining, Saving, Cloning
+
+   Inlining: a function body is duplicated, but the PARM_DECLs are
+   remapped into VAR_DECLs, and non-void RETURN_EXPRs become
+   MODIFY_EXPRs that store to a dedicated returned-value variable.
+   The duplicated eh_region info of the copy will later be appended
+   to the info for the caller; the eh_region info in copied throwing
+   statements and RESX_EXPRs is adjusted accordingly.
+
+   Saving: make a semantically-identical copy of the function body.
+   Necessary when we want to generate code for the body (a destructive
+   operation), but we expect to need this body in the future (e.g. for
+   inlining into another function).
+
+   Cloning: (only in C++) We have one body for a con/de/structor, and
+   multiple function decls, each with a unique parameter list.
+   Duplicate the body, using the given splay tree; some parameters
+   will become constants (like 0 or 1).
+
+   All of these will simultaneously lookup any callgraph edges.  If
+   we're going to inline the duplicated function body, and the given
+   function has some cloned callgraph nodes (one for each place this
+   function will be inlined) those callgraph edges will be duplicated.
+   If we're saving or cloning the body, those callgraph edges will be
+   updated to point into the new body.  (Note that the original
+   callgraph node and edge list will not be altered.)
+
+   See the CALL_EXPR handling case in copy_body_r ().  */
+
 /* 0 if we should not perform inlining.
    1 if we should expand functions calls inline at the tree level.
    2 if we should consider *all* functions to be inline
@@ -72,30 +107,19 @@ int flag_inline_trees = 0;
 
 typedef struct inline_data
 {
-  /* A stack of the functions we are inlining.  For example, if we are
-     compiling `f', which calls `g', which calls `h', and we are
-     inlining the body of `h', the stack will contain, `h', followed
-     by `g', followed by `f'.  The first few elements of the stack may
-     contain other functions that we know we should not recurse into,
-     even though they are not directly being inlined.  */
-  varray_type fns;
-  /* The index of the first element of FNS that really represents an
-     inlined function.  */
-  unsigned first_inlined_fn;
-  /* The label to jump to when a return statement is encountered.  If
-     this value is NULL, then return statements will simply be
-     remapped as return statements, rather than as jumps.  */
-  tree ret_label;
+  /* FUNCTION_DECL for function being inlined.  */
+  tree callee;
+  /* FUNCTION_DECL for function being inlined into.  */
+  tree caller;
+  /* struct function for function being inlined.  Usually this is the same
+     as DECL_STRUCT_FUNCTION (callee), but can be different if saved_cfg
+     and saved_eh are in use.  */
+  struct function *callee_cfun;
   /* The VAR_DECL for the return value.  */
   tree retvar;
   /* The map from local declarations in the inlined function to
      equivalents in the function into which it is being inlined.  */
   splay_tree decl_map;
-  /* Nonzero if we are currently within the cleanup for a
-     TARGET_EXPR.  */
-  int in_target_cleanup_p;
-  /* A list of the functions current function has inlined.  */
-  varray_type inlined_fns;
   /* We use the same mechanism to build clones that we do to perform
      inlining.  However, there are a few places where we need to
      distinguish between those two situations.  This flag is true if
@@ -103,43 +127,42 @@ typedef struct inline_data
   bool cloning_p;
   /* Similarly for saving function body.  */
   bool saving_p;
-  /* Hash table used to prevent walk_tree from visiting the same node
-     umpteen million times.  */
-  htab_t tree_pruner;
+  /* Versioning function is slightly different from inlining. */
+  bool versioning_p;
   /* Callgraph node of function we are inlining into.  */
   struct cgraph_node *node;
   /* Callgraph node of currently inlined function.  */
   struct cgraph_node *current_node;
-  /* Statement iterator.  We need this so we can keep the tree in
-     gimple form when we insert the inlined function.   It is not
-     used when we are not dealing with gimple trees.  */
-  tree_stmt_iterator tsi;
+  /* Current BLOCK.  */
+  tree block;
+  varray_type ipa_info;
+  /* Exception region the inlined call lie in.  */
+  int eh_region;
+  /* Take region number in the function being copied, add this value and
+     get eh region number of the duplicate in the function we inline into.  */
+  int eh_region_offset;
 } inline_data;
 
 /* Prototypes.  */
 
-/* The approximate number of instructions per statement.  This number
-   need not be particularly accurate; it is used only to make
-   decisions about when a function is too big to inline.  */
-#define INSNS_PER_STMT (10)
-
+static tree declare_return_variable (inline_data *, tree, tree, tree *);
 static tree copy_body_r (tree *, int *, void *);
-static tree copy_body (inline_data *);
-static tree expand_call_inline (tree *, int *, void *);
-static void expand_calls_inline (tree *, inline_data *);
+static tree copy_generic_body (inline_data *);
 static bool inlinable_function_p (tree);
 static tree remap_decl (tree, inline_data *);
 static tree remap_type (tree, inline_data *);
-static tree initialize_inlined_parameters (inline_data *, tree,
-                                          tree, tree, tree);
 static void remap_block (tree *, inline_data *);
+static tree remap_decl (tree, inline_data *);
 static tree remap_decls (tree, inline_data *);
 static void copy_bind_expr (tree *, int *, inline_data *);
 static tree mark_local_for_remap_r (tree *, int *, void *);
 static void unsave_expr_1 (tree);
 static tree unsave_r (tree *, int *, void *);
-static void declare_inline_vars (tree bind_expr, tree vars);
+static void declare_inline_vars (tree, tree);
 static void remap_save_expr (tree *, void *, int *);
+static bool replace_ref_tree (inline_data *, tree *);
+static inline bool inlining_p (inline_data *);
+static void add_lexical_block (tree current_block, tree new_block);
 
 /* Insert a tree->tree mapping for ID.  Despite the name suggests
    that the trees should be variables, it is used for more than that.  */
@@ -157,29 +180,38 @@ insert_decl_map (inline_data *id, tree key, tree value)
                       (splay_tree_value) value);
 }
 
-/* Remap DECL during the copying of the BLOCK tree for the function.
-   We are only called to remap local variables in the current function.  */
+/* Remap DECL during the copying of the BLOCK tree for the function.  */
 
 static tree
 remap_decl (tree decl, inline_data *id)
 {
-  splay_tree_node n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
-  tree fn = VARRAY_TOP_TREE (id->fns);
+  splay_tree_node n;
+  tree fn;
+
+  /* We only remap local variables in the current function.  */
+  fn = id->callee;
+
+  /* See if we have remapped this declaration.  */
 
-  /* See if we have remapped this declaration.  If we didn't already have an
-     equivalent for this declaration, create one now.  */
+  n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
+
+  /* If we didn't already have an equivalent for this declaration,
+     create one now.  */
   if (!n)
     {
       /* Make a copy of the variable or label.  */
-      tree t = copy_decl_for_inlining (decl, fn, VARRAY_TREE (id->fns, 0));
+      tree t;
+      t = copy_decl_for_dup (decl, fn, id->caller, id->versioning_p);
+     
+      /* Remember it, so that if we encounter this local entity again
+        we can reuse this copy.  Do this early because remap_type may
+        need this decl for TYPE_STUB_DECL.  */
+      insert_decl_map (id, decl, t);
 
       /* Remap types, if necessary.  */
       TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);
       if (TREE_CODE (t) == TYPE_DECL)
         DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);
-      else if (TREE_CODE (t) == PARM_DECL)
-        DECL_ARG_TYPE_AS_WRITTEN (t)
-         = remap_type (DECL_ARG_TYPE_AS_WRITTEN (t), id);
 
       /* Remap sizes as necessary.  */
       walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL);
@@ -225,27 +257,10 @@ remap_decl (tree decl, inline_data *id)
 }
 
 static tree
-remap_type (tree type, inline_data *id)
+remap_type_1 (tree type, inline_data *id)
 {
-  splay_tree_node node;
   tree new, t;
 
-  if (type == NULL)
-    return type;
-
-  /* See if we have remapped this type.  */
-  node = splay_tree_lookup (id->decl_map, (splay_tree_key) type);
-  if (node)
-    return (tree) node->value;
-
-  /* The type only needs remapping if it's variably modified by a variable
-     in the function we are inlining.  */
-  if (! variably_modified_type_p (type, VARRAY_TOP_TREE (id->fns)))
-    {
-      insert_decl_map (id, type, type);
-      return type;
-    }
-
   /* We do need a copy.  build and register it now.  If this is a pointer or
      reference type, remap the designated type and make a new pointer or
      reference type.  */
@@ -286,6 +301,9 @@ remap_type (tree type, inline_data *id)
       TYPE_NEXT_VARIANT (new) = NULL;
     }
 
+  if (TYPE_STUB_DECL (type))
+    TYPE_STUB_DECL (new) = remap_decl (TYPE_STUB_DECL (type), id);
+
   /* Lazily create pointer and reference types.  */
   TYPE_POINTER_TO (new) = NULL;
   TYPE_REFERENCE_TO (new) = NULL;
@@ -319,10 +337,20 @@ remap_type (tree type, inline_data *id)
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      walk_tree (&TYPE_FIELDS (new), copy_body_r, id, NULL);
+      {
+       tree f, nf = NULL;
+
+       for (f = TYPE_FIELDS (new); f ; f = TREE_CHAIN (f))
+         {
+           t = remap_decl (f, id);
+           DECL_CONTEXT (t) = new;
+           TREE_CHAIN (t) = nf;
+           nf = t;
+         }
+       TYPE_FIELDS (new) = nreverse (nf);
+      }
       break;
 
-    case FILE_TYPE:
     case OFFSET_TYPE:
     default:
       /* Shouldn't have been thought variable sized.  */
@@ -336,6 +364,29 @@ remap_type (tree type, inline_data *id)
 }
 
 static tree
+remap_type (tree type, inline_data *id)
+{
+  splay_tree_node node;
+
+  if (type == NULL)
+    return type;
+
+  /* See if we have remapped this type.  */
+  node = splay_tree_lookup (id->decl_map, (splay_tree_key) type);
+  if (node)
+    return (tree) node->value;
+
+  /* The type only needs remapping if it's variably modified.  */
+  if (! variably_modified_type_p (type, id->callee))
+    {
+      insert_decl_map (id, type, type);
+      return type;
+    }
+
+  return remap_type_1 (type, id);
+}
+
+static tree
 remap_decls (tree decls, inline_data *id)
 {
   tree old_var;
@@ -346,6 +397,17 @@ remap_decls (tree decls, inline_data *id)
     {
       tree new_var;
 
+      /* We can not chain the local static declarations into the unexpanded_var_list
+         as we can't duplicate them or break one decl rule.  Go ahead and link
+         them into unexpanded_var_list.  */
+      if (!lang_hooks.tree_inlining.auto_var_in_fn_p (old_var, id->callee)
+         && !DECL_EXTERNAL (old_var))
+       {
+         cfun->unexpanded_var_list = tree_cons (NULL_TREE, old_var,
+                                                cfun->unexpanded_var_list);
+         continue;
+       }
+
       /* Remap the variable.  */
       new_var = remap_decl (old_var, id);
 
@@ -380,38 +442,39 @@ remap_block (tree *block, inline_data *id)
   new_block = make_node (BLOCK);
   TREE_USED (new_block) = TREE_USED (old_block);
   BLOCK_ABSTRACT_ORIGIN (new_block) = old_block;
+  BLOCK_SOURCE_LOCATION (new_block) = BLOCK_SOURCE_LOCATION (old_block);
   *block = new_block;
 
   /* Remap its variables.  */
   BLOCK_VARS (new_block) = remap_decls (BLOCK_VARS (old_block), id);
 
-  fn = VARRAY_TREE (id->fns, 0);
-#if 1
-  /* FIXME!  It shouldn't be so hard to manage blocks.  Rebuilding them in
-     rest_of_compilation is a good start.  */
+  fn = id->caller;
   if (id->cloning_p)
     /* We're building a clone; DECL_INITIAL is still
        error_mark_node, and current_binding_level is the parm
        binding level.  */
     lang_hooks.decls.insert_block (new_block);
-  else
-    {
-      /* Attach this new block after the DECL_INITIAL block for the
-        function into which this block is being inlined.  In
-        rest_of_compilation we will straighten out the BLOCK tree.  */
-      tree *first_block;
-      if (DECL_INITIAL (fn))
-       first_block = &BLOCK_CHAIN (DECL_INITIAL (fn));
-      else
-       first_block = &DECL_INITIAL (fn);
-      BLOCK_CHAIN (new_block) = *first_block;
-      *first_block = new_block;
-    }
-#endif
   /* Remember the remapped block.  */
   insert_decl_map (id, old_block, new_block);
 }
 
+/* Copy the whole block tree and root it in id->block.  */
+static tree
+remap_blocks (tree block, inline_data *id)
+{
+  tree t;
+  tree new = block;
+
+  if (!block)
+    return NULL;
+
+  remap_block (&new, id);
+  gcc_assert (new != block);
+  for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
+    add_lexical_block (new, remap_blocks (t, id));
+  return new;
+}
+
 static void
 copy_statement_list (tree *tp)
 {
@@ -445,51 +508,46 @@ copy_bind_expr (tree *tp, int *walk_subtrees, inline_data *id)
     BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), id);
 }
 
-/* Called from copy_body via walk_tree.  DATA is really an `inline_data *'.  */
+/* Called from copy_body_id via walk_tree.  DATA is really an
+   `inline_data *'.  */
 
 static tree
 copy_body_r (tree *tp, int *walk_subtrees, void *data)
 {
   inline_data *id = (inline_data *) data;
-  tree fn = VARRAY_TOP_TREE (id->fns);
+  tree fn = id->callee;
+  tree new_block;
 
-#if 0
-  /* All automatic variables should have a DECL_CONTEXT indicating
-     what function they come from.  */
-  if ((TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == LABEL_DECL)
-      && DECL_NAMESPACE_SCOPE_P (*tp))
-    gcc_assert (DECL_EXTERNAL (*tp) || TREE_STATIC (*tp));
-#endif
+  /* Begin by recognizing trees that we'll completely rewrite for the
+     inlining context.  Our output for these trees is completely
+     different from out input (e.g. RETURN_EXPR is deleted, and morphs
+     into an edge).  Further down, we'll handle trees that get
+     duplicated and/or tweaked.  */
 
-  /* If this is a RETURN_EXPR, change it into a MODIFY_EXPR and a
-     GOTO_EXPR with the RET_LABEL as its target.  */
-  if (TREE_CODE (*tp) == RETURN_EXPR && id->ret_label)
+  /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
+     GOTO_STMT with the RET_LABEL as its target.  */
+  if (TREE_CODE (*tp) == RETURN_EXPR && inlining_p (id))
     {
-      tree return_stmt = *tp;
-      tree goto_stmt;
-
-      /* Build the GOTO_EXPR.  */
-      tree assignment = TREE_OPERAND (return_stmt, 0);
-      goto_stmt = build1 (GOTO_EXPR, void_type_node, id->ret_label);
-      TREE_USED (id->ret_label) = 1;
+      tree assignment = TREE_OPERAND (*tp, 0);
 
       /* If we're returning something, just turn that into an
-        assignment into the equivalent of the original
-        RESULT_DECL.  */
-      if (assignment)
-        {
-         /* Do not create a statement containing a naked RESULT_DECL.  */
-         if (TREE_CODE (assignment) == RESULT_DECL)
-           gimplify_stmt (&assignment);
-
-         *tp = build (BIND_EXPR, void_type_node, NULL, NULL, NULL);
-         append_to_statement_list (assignment, &BIND_EXPR_BODY (*tp));
-         append_to_statement_list (goto_stmt, &BIND_EXPR_BODY (*tp));
-        }
-      /* If we're not returning anything just do the jump.  */
-      else
-       *tp = goto_stmt;
+        assignment into the equivalent of the original RESULT_DECL.
+        If the "assignment" is just the result decl, the result
+        decl has already been set (e.g. a recent "foo (&result_decl,
+        ...)"); just toss the entire RETURN_EXPR.  */
+      if (assignment && TREE_CODE (assignment) == MODIFY_EXPR)
+       {
+         /* Replace the RETURN_EXPR with (a copy of) the
+            MODIFY_EXPR hanging underneath.  */
+         *tp = copy_node (assignment);
+       }
+      else /* Else the RETURN_EXPR returns no value.  */
+       {
+         *tp = NULL;
+         return (void *)1;
+       }
     }
+
   /* Local variables and labels need to be replaced by equivalent
      variables.  We don't want to copy static variables; there's only
      one of those, no matter how many times we inline the containing
@@ -504,11 +562,17 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
       /* Replace this variable with the copy.  */
       STRIP_TYPE_NOPS (new_decl);
       *tp = new_decl;
+      *walk_subtrees = 0;
     }
   else if (TREE_CODE (*tp) == STATEMENT_LIST)
     copy_statement_list (tp);
   else if (TREE_CODE (*tp) == SAVE_EXPR)
     remap_save_expr (tp, id->decl_map, walk_subtrees);
+  else if (TREE_CODE (*tp) == LABEL_DECL
+          && (! DECL_CONTEXT (*tp)
+              || decl_function_context (*tp) == id->callee))
+    /* These may need to be remapped for EH handling.  */
+    *tp = remap_decl (*tp, id);
   else if (TREE_CODE (*tp) == BIND_EXPR)
     copy_bind_expr (tp, walk_subtrees, id);
   /* Types may need remapping as well.  */
@@ -517,7 +581,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
 
   /* If this is a constant, we have to copy the node iff the type will be
      remapped.  copy_tree_r will not copy a constant.  */
-  else if (TREE_CODE_CLASS (TREE_CODE (*tp)) == tcc_constant)
+  else if (CONSTANT_CLASS_P (*tp))
     {
       tree new_type = remap_type (TREE_TYPE (*tp), id);
 
@@ -538,8 +602,9 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
      knows not to copy VAR_DECLs, etc., so this is safe.  */
   else
     {
-      tree old_node = *tp;
-
+      /* Here we handle trees that are not completely rewritten.
+        First we detect some inlining-induced bogosities for
+        discarding.  */
       if (TREE_CODE (*tp) == MODIFY_EXPR
          && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
          && (lang_hooks.tree_inlining.auto_var_in_fn_p
@@ -563,54 +628,66 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
                }
            }
        }
-      else if (TREE_CODE (*tp) == INDIRECT_REF)
+      else if (TREE_CODE (*tp) == INDIRECT_REF
+              && !id->versioning_p)
        {
          /* Get rid of *& from inline substitutions that can happen when a
             pointer argument is an ADDR_EXPR.  */
-         tree decl = TREE_OPERAND (*tp, 0), value;
+         tree decl = TREE_OPERAND (*tp, 0);
          splay_tree_node n;
 
          n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
          if (n)
            {
-             value = (tree) n->value;
-             STRIP_NOPS (value);
-             if (TREE_CODE (value) == ADDR_EXPR
-                 && (lang_hooks.types_compatible_p
-                     (TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0)))))
-               {
-                 *tp = TREE_OPERAND (value, 0);
-                 return copy_body_r (tp, walk_subtrees, data);
+             tree new;
+             /* If we happen to get an ADDR_EXPR in n->value, strip
+                it manually here as we'll eventually get ADDR_EXPRs
+                which lie about their types pointed to.  In this case
+                build_fold_indirect_ref wouldn't strip the INDIRECT_REF,
+                but we absolutely rely on that.  As fold_indirect_ref
+                does other useful transformations, try that first, though.  */
+             tree type = TREE_TYPE (TREE_TYPE ((tree)n->value));
+             new = unshare_expr ((tree)n->value);
+             *tp = fold_indirect_ref_1 (type, new);
+             if (! *tp)
+               {
+                 if (TREE_CODE (new) == ADDR_EXPR)
+                   *tp = TREE_OPERAND (new, 0);
+                 else
+                   *tp = build1 (INDIRECT_REF, type, new);
                }
+             *walk_subtrees = 0;
+             return NULL;
            }
        }
 
-      copy_tree_r (tp, walk_subtrees, NULL);
-
-      if (TREE_CODE (*tp) == CALL_EXPR && id->node && get_callee_fndecl (*tp))
+      /* Here is the "usual case".  Copy this tree node, and then
+        tweak some special cases.  */
+      copy_tree_r (tp, walk_subtrees, id->versioning_p ? data : NULL);
+       
+      /* If EXPR has block defined, map it to newly constructed block.
+         When inlining we want EXPRs without block appear in the block
+        of function call.  */
+      if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (*tp))))
        {
-         if (id->saving_p)
-           {
-             struct cgraph_node *node;
-              struct cgraph_edge *edge;
-
-             for (node = id->node->next_clone; node; node = node->next_clone)
-               {
-                 edge = cgraph_edge (node, old_node);
-                 gcc_assert (edge);
-                 edge->call_expr = *tp;
-               }
-           }
-         else
+         new_block = id->block;
+         if (TREE_BLOCK (*tp))
            {
-              struct cgraph_edge *edge
-               = cgraph_edge (id->current_node, old_node);
-
-             if (edge)
-               cgraph_clone_edge (edge, id->node, *tp);
+             splay_tree_node n;
+             n = splay_tree_lookup (id->decl_map,
+                                    (splay_tree_key) TREE_BLOCK (*tp));
+             gcc_assert (n);
+             new_block = (tree) n->value;
            }
+         TREE_BLOCK (*tp) = new_block;
        }
 
+      if (TREE_CODE (*tp) == RESX_EXPR && id->eh_region_offset)
+       TREE_OPERAND (*tp, 0) =
+         build_int_cst
+           (NULL_TREE,
+            id->eh_region_offset + TREE_INT_CST_LOW (TREE_OPERAND (*tp, 0)));
+
       TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);
 
       /* The copied TARGET_EXPR has never been expanded, even if the
@@ -636,25 +713,338 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
+/* Copy basic block, scale profile accordingly.  Edges will be taken care of
+   later  */
+
+static basic_block
+copy_bb (inline_data *id, basic_block bb, int frequency_scale, int count_scale)
+{
+  block_stmt_iterator bsi, copy_bsi;
+  basic_block copy_basic_block;
+
+  /* create_basic_block() will append every new block to
+     basic_block_info automatically.  */
+  copy_basic_block = create_basic_block (NULL, (void *) 0, bb->prev_bb->aux);
+  copy_basic_block->count = bb->count * count_scale / REG_BR_PROB_BASE;
+  copy_basic_block->frequency = (bb->frequency
+                                    * frequency_scale / REG_BR_PROB_BASE);
+  copy_bsi = bsi_start (copy_basic_block);
+
+  for (bsi = bsi_start (bb);
+       !bsi_end_p (bsi); bsi_next (&bsi))
+    {
+      tree stmt = bsi_stmt (bsi);
+      tree orig_stmt = stmt;
+
+      walk_tree (&stmt, copy_body_r, id, NULL);
+
+      /* RETURN_EXPR might be removed,
+         this is signalled by making stmt pointer NULL.  */
+      if (stmt)
+       {
+         tree call, decl;
+          bsi_insert_after (&copy_bsi, stmt, BSI_NEW_STMT);
+         call = get_call_expr_in (stmt);
+         /* We're duplicating a CALL_EXPR.  Find any corresponding
+            callgraph edges and update or duplicate them.  */
+         if (call && (decl = get_callee_fndecl (call)))
+           {
+             if (id->saving_p)
+               {
+                 struct cgraph_node *node;
+                 struct cgraph_edge *edge;
+
+                 /* We're saving a copy of the body, so we'll update the
+                    callgraph nodes in place.  Note that we avoid
+                    altering the original callgraph node; we begin with
+                    the first clone.  */
+                 for (node = id->node->next_clone;
+                      node;
+                      node = node->next_clone)
+                   {
+                     edge = cgraph_edge (node, orig_stmt);
+                     gcc_assert (edge);
+                     edge->call_stmt = stmt;
+                   }
+               }
+             else
+               {
+                 struct cgraph_edge *edge;
+
+                 /* We're cloning or inlining this body; duplicate the
+                    associate callgraph nodes.  */
+                 if (!id->versioning_p)
+                   {
+                     edge = cgraph_edge (id->current_node, orig_stmt);
+                     if (edge)
+                       cgraph_clone_edge (edge, id->node, stmt,
+                                          REG_BR_PROB_BASE, 1, true);
+                   }
+               }
+             if (id->versioning_p)
+               {
+                 /* Update the call_expr on the edges from the new version
+                    to its callees. */
+                 struct cgraph_edge *edge;
+                 edge = cgraph_edge (id->node, orig_stmt);
+                 if (edge)
+                   edge->call_stmt = stmt;
+               }
+           }
+         /* If you think we can abort here, you are wrong.
+            There is no region 0 in tree land.  */
+         gcc_assert (lookup_stmt_eh_region_fn (id->callee_cfun, orig_stmt)
+                     != 0);
+
+         if (tree_could_throw_p (stmt))
+           {
+             int region = lookup_stmt_eh_region_fn (id->callee_cfun, orig_stmt);
+             /* Add an entry for the copied tree in the EH hashtable.
+                When saving or cloning or versioning, use the hashtable in
+                cfun, and just copy the EH number.  When inlining, use the
+                hashtable in the caller, and adjust the region number.  */
+             if (region > 0)
+               add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
+
+             /* If this tree doesn't have a region associated with it,
+                and there is a "current region,"
+                then associate this tree with the current region
+                and add edges associated with this region.  */
+             if ((lookup_stmt_eh_region_fn (id->callee_cfun,
+                                            orig_stmt) <= 0
+                  && id->eh_region > 0)
+                 && tree_could_throw_p (stmt))
+               add_stmt_to_eh_region (stmt, id->eh_region);
+           }
+       }
+    }
+  return copy_basic_block;
+}
+
+/* Copy edges from BB into its copy constructed earlier, scale profile
+   accordingly.  Edges will be taken care of later.  Assume aux
+   pointers to point to the copies of each BB.  */
+static void
+copy_edges_for_bb (basic_block bb, int count_scale)
+{
+  basic_block new_bb = bb->aux;
+  edge_iterator ei;
+  edge old_edge;
+  block_stmt_iterator bsi;
+  int flags;
+
+  /* Use the indices from the original blocks to create edges for the
+     new ones.  */
+  FOR_EACH_EDGE (old_edge, ei, bb->succs)
+    if (!(old_edge->flags & EDGE_EH))
+      {
+       edge new;
+
+       flags = old_edge->flags;
+
+       /* Return edges do get a FALLTHRU flag when the get inlined.  */
+       if (old_edge->dest->index == EXIT_BLOCK && !old_edge->flags
+           && old_edge->dest->aux != EXIT_BLOCK_PTR)
+         flags |= EDGE_FALLTHRU;
+       new = make_edge (new_bb, old_edge->dest->aux, flags);
+       new->count = old_edge->count * count_scale / REG_BR_PROB_BASE;
+       new->probability = old_edge->probability;
+      }
+
+  if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
+    return;
+
+  for (bsi = bsi_start (new_bb); !bsi_end_p (bsi);)
+    {
+      tree copy_stmt;
+
+      copy_stmt = bsi_stmt (bsi);
+      update_stmt (copy_stmt);
+      /* Do this before the possible split_block.  */
+      bsi_next (&bsi);
+
+      /* If this tree could throw an exception, there are two
+         cases where we need to add abnormal edge(s): the
+         tree wasn't in a region and there is a "current
+         region" in the caller; or the original tree had
+         EH edges.  In both cases split the block after the tree,
+         and add abnormal edge(s) as needed; we need both
+         those from the callee and the caller.
+         We check whether the copy can throw, because the const
+         propagation can change an INDIRECT_REF which throws
+         into a COMPONENT_REF which doesn't.  If the copy
+         can throw, the original could also throw.  */
+
+      if (tree_can_throw_internal (copy_stmt))
+       {
+         if (!bsi_end_p (bsi))
+           /* Note that bb's predecessor edges aren't necessarily
+              right at this point; split_block doesn't care.  */
+           {
+             edge e = split_block (new_bb, copy_stmt);
+             new_bb = e->dest;
+             bsi = bsi_start (new_bb);
+           }
+
+           make_eh_edges (copy_stmt);
+       }
+    }
+}
+
+/* Wrapper for remap_decl so it can be used as a callback.  */
+static tree
+remap_decl_1 (tree decl, void *data)
+{
+  return remap_decl (decl, data);
+}
+
+/* Make a copy of the body of FN so that it can be inserted inline in
+   another function.  Walks FN via CFG, returns new fndecl.  */
+
+static tree
+copy_cfg_body (inline_data * id, gcov_type count, int frequency,
+              basic_block entry_block_map, basic_block exit_block_map)
+{
+  tree callee_fndecl = id->callee;
+  /* Original cfun for the callee, doesn't change.  */
+  struct function *callee_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
+  /* Copy, built by this function.  */
+  struct function *new_cfun;
+  /* Place to copy from; when a copy of the function was saved off earlier,
+     use that instead of the main copy.  */
+  struct function *cfun_to_copy =
+    (struct function *) ggc_alloc_cleared (sizeof (struct function));
+  basic_block bb;
+  tree new_fndecl = NULL;
+  bool saving_or_cloning;
+  int count_scale, frequency_scale;
+
+  if (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count)
+    count_scale = (REG_BR_PROB_BASE * count
+                  / ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count);
+  else
+    count_scale = 1;
+
+  if (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->frequency)
+    frequency_scale = (REG_BR_PROB_BASE * frequency
+                      /
+                      ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->frequency);
+  else
+    frequency_scale = count_scale;
+
+  /* Register specific tree functions.  */
+  tree_register_cfg_hooks ();
+
+  /* Must have a CFG here at this point.  */
+  gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
+             (DECL_STRUCT_FUNCTION (callee_fndecl)));
+
+  *cfun_to_copy = *DECL_STRUCT_FUNCTION (callee_fndecl);
+
+  /* If there is a saved_cfg+saved_args lurking in the
+     struct function, a copy of the callee body was saved there, and
+     the 'struct cgraph edge' nodes have been fudged to point into the
+     saved body.  Accordingly, we want to copy that saved body so the
+     callgraph edges will be recognized and cloned properly.  */
+  if (cfun_to_copy->saved_cfg)
+    {
+      cfun_to_copy->cfg = cfun_to_copy->saved_cfg;
+      cfun_to_copy->eh = cfun_to_copy->saved_eh;
+    }
+  id->callee_cfun = cfun_to_copy;
+
+  /* If saving or cloning a function body, create new basic_block_info
+     and label_to_block_maps.  Otherwise, we're duplicating a function
+     body for inlining; insert our new blocks and labels into the
+     existing varrays.  */
+  saving_or_cloning = (id->saving_p || id->cloning_p || id->versioning_p);
+  if (saving_or_cloning)
+    {
+      new_cfun =
+       (struct function *) ggc_alloc_cleared (sizeof (struct function));
+      *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
+      new_cfun->cfg = NULL;
+      new_cfun->decl = new_fndecl = copy_node (callee_fndecl);
+      new_cfun->ib_boundaries_block = (varray_type) 0;
+      DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
+      push_cfun (new_cfun);
+      init_empty_tree_cfg ();
+
+      ENTRY_BLOCK_PTR->count =
+       (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count * count_scale /
+        REG_BR_PROB_BASE);
+      ENTRY_BLOCK_PTR->frequency =
+       (ENTRY_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->frequency *
+        frequency_scale / REG_BR_PROB_BASE);
+      EXIT_BLOCK_PTR->count =
+       (EXIT_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->count * count_scale /
+        REG_BR_PROB_BASE);
+      EXIT_BLOCK_PTR->frequency =
+       (EXIT_BLOCK_PTR_FOR_FUNCTION (callee_cfun)->frequency *
+        frequency_scale / REG_BR_PROB_BASE);
+
+      entry_block_map = ENTRY_BLOCK_PTR;
+      exit_block_map = EXIT_BLOCK_PTR;
+    }
+
+  ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = entry_block_map;
+  EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = exit_block_map;
+
+
+  /* Duplicate any exception-handling regions.  */
+  if (cfun->eh)
+    {
+      if (saving_or_cloning)
+        init_eh_for_function ();
+      id->eh_region_offset = duplicate_eh_regions (cfun_to_copy,
+                                                  remap_decl_1,
+                                                  id, id->eh_region);
+      gcc_assert (inlining_p (id) || !id->eh_region_offset);
+    }
+  /* Use aux pointers to map the original blocks to copy.  */
+  FOR_EACH_BB_FN (bb, cfun_to_copy)
+    bb->aux = copy_bb (id, bb, frequency_scale, count_scale);
+  /* Now that we've duplicated the blocks, duplicate their edges.  */
+  FOR_ALL_BB_FN (bb, cfun_to_copy)
+    copy_edges_for_bb (bb, count_scale);
+  FOR_ALL_BB_FN (bb, cfun_to_copy)
+    bb->aux = NULL;
+
+  if (saving_or_cloning)
+    pop_cfun ();
+
+  return new_fndecl;
+}
+
 /* Make a copy of the body of FN so that it can be inserted inline in
    another function.  */
 
 static tree
-copy_body (inline_data *id)
+copy_generic_body (inline_data *id)
 {
   tree body;
-  tree fndecl = VARRAY_TOP_TREE (id->fns);
+  tree fndecl = id->callee;
 
-  if (fndecl == current_function_decl
-      && cfun->saved_tree)
-    body = cfun->saved_tree;
-  else
-    body = DECL_SAVED_TREE (fndecl);
+  body = DECL_SAVED_TREE (fndecl);
   walk_tree (&body, copy_body_r, id, NULL);
 
   return body;
 }
 
+static tree
+copy_body (inline_data *id, gcov_type count, int frequency,
+          basic_block entry_block_map, basic_block exit_block_map)
+{
+  tree fndecl = id->callee;
+  tree body;
+
+  /* If this body has a CFG, walk CFG and copy.  */
+  gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (fndecl)));
+  body = copy_cfg_body (id, count, frequency, entry_block_map, exit_block_map);
+
+  return body;
+}
+
 /* Return true if VALUE is an ADDR_EXPR of an automatic variable
    defined in function FN, or of a data member thereof.  */
 
@@ -667,16 +1057,17 @@ self_inlining_addr_expr (tree value, tree fn)
     return false;
 
   var = get_base_address (TREE_OPERAND (value, 0));
-             
+
   return var && lang_hooks.tree_inlining.auto_var_in_fn_p (var, fn);
 }
 
 static void
 setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
-                    tree *init_stmts, tree *vars, bool *gimplify_init_stmts_p)
+                    basic_block bb, tree *vars)
 {
   tree init_stmt;
   tree var;
+  tree var_sub;
 
   /* If the parameter is never assigned to, we may not need to
      create a new variable here at all.  Instead, we may be able
@@ -685,11 +1076,6 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
       && !TREE_ADDRESSABLE (p)
       && value && !TREE_SIDE_EFFECTS (value))
     {
-      /* We can't risk substituting complex expressions.  They
-        might contain variables that will be assigned to later.
-        Theoretically, we could check the expression to see if
-        all of the variables that determine its value are
-        read-only, but we don't bother.  */
       /* We may produce non-gimple trees by adding NOPs or introduce
         invalid sharing when operand is not really constant.
         It is not big deal to prohibit constant propagation here as
@@ -711,12 +1097,25 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
   /* Make an equivalent VAR_DECL.  Note that we must NOT remap the type
      here since the type of this decl must be visible to the calling
      function.  */
-  var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
+  var = copy_decl_for_dup (p, fn, id->caller, /*versioning=*/false);
+
+  /* See if the frontend wants to pass this by invisible reference.  If
+     so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
+     replace uses of the PARM_DECL with dereferences.  */
+  if (TREE_TYPE (var) != TREE_TYPE (p)
+      && POINTER_TYPE_P (TREE_TYPE (var))
+      && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p))
+    {
+      insert_decl_map (id, var, var);
+      var_sub = build_fold_indirect_ref (var);
+    }
+  else
+    var_sub = var;
 
   /* Register the VAR_DECL as the equivalent for the PARM_DECL;
      that way, when the PARM_DECL is encountered, it will be
      automatically replaced by the VAR_DECL.  */
-  insert_decl_map (id, p, var);
+  insert_decl_map (id, p, var_sub);
 
   /* Declare this new variable.  */
   TREE_CHAIN (var) = *vars;
@@ -742,6 +1141,7 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
   if (value)
     {
       tree rhs = fold_convert (TREE_TYPE (var), value);
+      block_stmt_iterator bsi = bsi_last (bb);
 
       if (rhs == error_mark_node)
        return;
@@ -749,33 +1149,32 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
       /* We want to use MODIFY_EXPR, not INIT_EXPR here so that we
         keep our trees in gimple form.  */
       init_stmt = build (MODIFY_EXPR, TREE_TYPE (var), var, rhs);
-      append_to_statement_list (init_stmt, init_stmts);
 
       /* If we did not create a gimple value and we did not create a gimple
         cast of a gimple value, then we will need to gimplify INIT_STMTS
         at the end.  Note that is_gimple_cast only checks the outer
-        tree code, not its operand.  Thus the explicit check that it's
+        tree code, not its operand.  Thus the explicit check that its
         operand is a gimple value.  */
       if (!is_gimple_val (rhs)
          && (!is_gimple_cast (rhs)
              || !is_gimple_val (TREE_OPERAND (rhs, 0))))
-       *gimplify_init_stmts_p = true;
+       gimplify_stmt (&init_stmt);
+      if (init_stmt)
+        bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
     }
 }
 
 /* Generate code to initialize the parameters of the function at the
    top of the stack in ID from the ARGS (presented as a TREE_LIST).  */
 
-static tree
+static void
 initialize_inlined_parameters (inline_data *id, tree args, tree static_chain,
-                              tree fn, tree bind_expr)
+                              tree fn, basic_block bb)
 {
-  tree init_stmts = NULL_TREE;
   tree parms;
   tree a;
   tree p;
   tree vars = NULL_TREE;
-  bool gimplify_init_stmts_p = false;
   int argnum = 0;
 
   /* Figure out what the parameters are.  */
@@ -796,37 +1195,30 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain,
       value = lang_hooks.tree_inlining.convert_parm_for_inlining
              (p, a ? TREE_VALUE (a) : NULL_TREE, fn, argnum);
 
-      setup_one_parameter (id, p, value, fn, &init_stmts, &vars,
-                          &gimplify_init_stmts_p);
-    }
-
-  /* Evaluate trailing arguments.  */
-  for (; a; a = TREE_CHAIN (a))
-    {
-      tree value = TREE_VALUE (a);
-      append_to_statement_list (value, &init_stmts);
+      setup_one_parameter (id, p, value, fn, bb, &vars);
     }
 
   /* Initialize the static chain.  */
   p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
+  if (fn == current_function_decl)
+    p = DECL_STRUCT_FUNCTION (fn)->saved_static_chain_decl;
   if (p)
     {
       /* No static chain?  Seems like a bug in tree-nested.c.  */
       gcc_assert (static_chain);
 
-      setup_one_parameter (id, p, static_chain, fn, &init_stmts, &vars,
-                          &gimplify_init_stmts_p);
+      setup_one_parameter (id, p, static_chain, fn, bb, &vars);
     }
 
-  if (gimplify_init_stmts_p)
-    gimplify_body (&init_stmts, current_function_decl);
-
-  declare_inline_vars (bind_expr, vars);
-  return init_stmts;
+  declare_inline_vars (id->block, vars);
 }
 
-/* Declare a return variable to replace the RESULT_DECL for the function we
-   are calling.  RETURN_SLOT_ADDR, if non-null, was a fake parameter that
+/* Declare a return variable to replace the RESULT_DECL for the
+   function we are calling.  An appropriate DECL_STMT is returned.
+   The USE_STMT is filled to contain a use of the declaration to
+   indicate the return value of the function.
+
+   RETURN_SLOT_ADDR, if non-null, was a fake parameter that
    took the address of the result.  MODIFY_DEST, if non-null, was the LHS of
    the MODIFY_EXPR to which this call is the RHS.
 
@@ -838,8 +1230,8 @@ static tree
 declare_return_variable (inline_data *id, tree return_slot_addr,
                         tree modify_dest, tree *use_p)
 {
-  tree callee = VARRAY_TOP_TREE (id->fns);
-  tree caller = VARRAY_TREE (id->fns, 0);
+  tree callee = id->callee;
+  tree caller = id->caller;
   tree result = DECL_RESULT (callee);
   tree callee_type = TREE_TYPE (result);
   tree caller_type = TREE_TYPE (TREE_TYPE (callee));
@@ -889,10 +1281,21 @@ declare_return_variable (inline_data *id, tree return_slot_addr,
       /* If the callee cannot possibly modify MODIFY_DEST, then we can
         reuse it as the result of the call directly.  Don't do this if
         it would promote MODIFY_DEST to addressable.  */
-      else if (!TREE_STATIC (modify_dest)
-              && !TREE_ADDRESSABLE (modify_dest)
-              && !TREE_ADDRESSABLE (result))
-       use_it = true;
+      else if (TREE_ADDRESSABLE (result))
+       use_it = false;
+      else
+       {
+         tree base_m = get_base_address (modify_dest);
+
+         /* If the base isn't a decl, then it's a pointer, and we don't
+            know where that's going to go.  */
+         if (!DECL_P (base_m))
+           use_it = false;
+         else if (is_global_var (base_m))
+           use_it = false;
+         else if (!TREE_ADDRESSABLE (base_m))
+           use_it = true;
+       }
 
       if (use_it)
        {
@@ -904,7 +1307,8 @@ declare_return_variable (inline_data *id, tree return_slot_addr,
 
   gcc_assert (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) == INTEGER_CST);
 
-  var = copy_decl_for_inlining (result, callee, caller);
+  var = copy_decl_for_dup (result, callee, caller, /*versioning=*/false);
+
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
   DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
     = tree_cons (NULL_TREE, var,
@@ -963,7 +1367,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
          && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
        {
          inline_forbidden_reason
-           = N_("%Jfunction %qF can never be inlined because it uses "
+           = G_("function %q+F can never be inlined because it uses "
                 "alloca (override using the always_inline attribute)");
          return node;
        }
@@ -975,7 +1379,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
       if (setjmp_call_p (t))
        {
          inline_forbidden_reason
-           = N_("%Jfunction %qF can never be inlined because it uses setjmp");
+           = G_("function %q+F can never be inlined because it uses setjmp");
          return node;
        }
 
@@ -989,7 +1393,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
          case BUILT_IN_NEXT_ARG:
          case BUILT_IN_VA_END:
            inline_forbidden_reason
-             = N_("%Jfunction %qF can never be inlined because it "
+             = G_("function %q+F can never be inlined because it "
                   "uses variable argument lists");
            return node;
 
@@ -1000,17 +1404,28 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
               function calling __builtin_longjmp to be inlined into the
               function calling __builtin_setjmp, Things will Go Awry.  */
            inline_forbidden_reason
-             = N_("%Jfunction %qF can never be inlined because "
+             = G_("function %q+F can never be inlined because "
                   "it uses setjmp-longjmp exception handling");
            return node;
 
          case BUILT_IN_NONLOCAL_GOTO:
            /* Similarly.  */
            inline_forbidden_reason
-             = N_("%Jfunction %qF can never be inlined because "
+             = G_("function %q+F can never be inlined because "
                   "it uses non-local goto");
            return node;
 
+         case BUILT_IN_RETURN:
+         case BUILT_IN_APPLY_ARGS:
+           /* If a __builtin_apply_args caller would be inlined,
+              it would be saving arguments of the function it has
+              been inlined into.  Similarly __builtin_return would
+              return from the function the inline has been inlined into.  */
+           inline_forbidden_reason
+             = G_("function %q+F can never be inlined because "
+                  "it uses __builtin_return or __builtin_apply_args");
+           return node;
+
          default:
            break;
          }
@@ -1026,7 +1441,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
       if (TREE_CODE (t) != LABEL_DECL)
        {
          inline_forbidden_reason
-           = N_("%Jfunction %qF can never be inlined "
+           = G_("function %q+F can never be inlined "
                 "because it contains a computed goto");
          return node;
        }
@@ -1040,7 +1455,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
             because we cannot remap the destination label used in the
             function that is performing the non-local goto.  */
          inline_forbidden_reason
-           = N_("%Jfunction %qF can never be inlined "
+           = G_("function %q+F can never be inlined "
                 "because it receives a non-local goto");
          return node;
        }
@@ -1057,7 +1472,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
         UNION_TYPE nodes, then it goes into infinite recursion on a
         structure containing a pointer to its own type.  If it doesn't,
         then the type node for S doesn't get adjusted properly when
-        F is inlined, and we abort in find_function_data.
+        F is inlined
 
         ??? This is likely no longer true, but it's too late in the 4.0
         cycle to try to find out.  This should be checked for 4.1.  */
@@ -1065,7 +1480,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
        if (variably_modified_type_p (TREE_TYPE (t), NULL))
          {
            inline_forbidden_reason
-             = N_("%Jfunction %qF can never be inlined "
+             = G_("function %q+F can never be inlined "
                   "because it uses variable sized variables");
            return node;
          }
@@ -1082,9 +1497,20 @@ static tree
 inline_forbidden_p (tree fndecl)
 {
   location_t saved_loc = input_location;
-  tree ret = walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
-                                          inline_forbidden_p_1, fndecl);
+  block_stmt_iterator bsi;
+  basic_block bb;
+  tree ret = NULL_TREE;
+
+  FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (fndecl))
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+       ret = walk_tree_without_duplicates (bsi_stmt_ptr (bsi),
+                                   inline_forbidden_p_1, fndecl);
+       if (ret)
+         goto egress;
+      }
 
+egress:
   input_location = saved_loc;
   return ret;
 }
@@ -1149,9 +1575,9 @@ inlinable_function_p (tree fn)
                         && !DECL_IN_SYSTEM_HEADER (fn));
 
       if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
-       sorry (inline_forbidden_reason, fn, fn);
+       sorry (inline_forbidden_reason, fn);
       else if (do_warning)
-       warning (inline_forbidden_reason, fn, fn);
+       warning (OPT_Winline, inline_forbidden_reason, fn);
 
       inlinable = false;
     }
@@ -1162,6 +1588,23 @@ inlinable_function_p (tree fn)
   return inlinable;
 }
 
+/* Estimate the cost of a memory move.  Use machine dependent
+   word size and take possible memcpy call into account.  */
+
+int
+estimate_move_cost (tree type)
+{
+  HOST_WIDE_INT size;
+
+  size = int_size_in_bytes (type);
+
+  if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO)
+    /* Cost of a memcpy call, 3 arguments and the call.  */
+    return 4;
+  else
+    return ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES);
+}
+
 /* Used by estimate_num_insns.  Estimate number of instructions seen
    by given statement.  */
 
@@ -1191,6 +1634,8 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case COMPONENT_REF:
     case BIT_FIELD_REF:
     case INDIRECT_REF:
+    case ALIGN_INDIRECT_REF:
+    case MISALIGNED_INDIRECT_REF:
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
     case OBJ_TYPE_REF:
@@ -1227,7 +1672,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
 
     /* We don't account constants for now.  Assume that the cost is amortized
        by operations that do use them.  We may re-consider this decision once
-       we are able to optimize the tree before estimating it's size and break
+       we are able to optimize the tree before estimating its size and break
        out static initializers.  */
     case IDENTIFIER_NODE:
     case INTEGER_CST:
@@ -1238,29 +1683,52 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
       *walk_subtrees = 0;
       return NULL;
 
-    /* Recognize assignments of large structures and constructors of
-       big arrays.  */
+    /* Try to estimate the cost of assignments.  We have three cases to
+       deal with:
+       1) Simple assignments to registers;
+       2) Stores to things that must live in memory.  This includes
+          "normal" stores to scalars, but also assignments of large
+          structures, or constructors of big arrays;
+       3) TARGET_EXPRs.
+
+       Let us look at the first two cases, assuming we have "a = b + C":
+       <modify_expr <var_decl "a"> <plus_expr <var_decl "b"> <constant C>>
+       If "a" is a GIMPLE register, the assignment to it is free on almost
+       any target, because "a" usually ends up in a real register.  Hence
+       the only cost of this expression comes from the PLUS_EXPR, and we
+       can ignore the MODIFY_EXPR.
+       If "a" is not a GIMPLE register, the assignment to "a" will most
+       likely be a real store, so the cost of the MODIFY_EXPR is the cost
+       of moving something into "a", which we compute using the function
+       estimate_move_cost.
+
+       The third case deals with TARGET_EXPRs, for which the semantics are
+       that a temporary is assigned, unless the TARGET_EXPR itself is being
+       assigned to something else.  In the latter case we do not need the
+       temporary.  E.g. in <modify_expr <var_decl "a"> <target_expr>>, the
+       MODIFY_EXPR is free.  */
     case INIT_EXPR:
     case MODIFY_EXPR:
-      x = TREE_OPERAND (x, 0);
-      /* FALLTHRU */
-    case TARGET_EXPR:
-    case CONSTRUCTOR:
-      {
-       HOST_WIDE_INT size;
+      /* Is the right and side a TARGET_EXPR?  */
+      if (TREE_CODE (TREE_OPERAND (x, 1)) == TARGET_EXPR)
+       break;
+      /* ... fall through ...  */
 
-       size = int_size_in_bytes (TREE_TYPE (x));
+    case TARGET_EXPR:
+      x = TREE_OPERAND (x, 0);
+      /* Is this an assignments to a register?  */
+      if (is_gimple_reg (x))
+       break;
+      /* Otherwise it's a store, so fall through to compute the move cost.  */
 
-       if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO)
-         *count += 10;
-       else
-         *count += ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES);
-      }
+    case CONSTRUCTOR:
+      *count += estimate_move_cost (TREE_TYPE (x));
       break;
 
-      /* Assign cost of 1 to usual operations.
-        ??? We may consider mapping RTL costs to this.  */
+    /* Assign cost of 1 to usual operations.
+       ??? We may consider mapping RTL costs to this.  */
     case COND_EXPR:
+    case VEC_COND_EXPR:
 
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -1281,6 +1749,8 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case RSHIFT_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
+    case VEC_LSHIFT_EXPR:
+    case VEC_RSHIFT_EXPR:
 
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
@@ -1323,6 +1793,12 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
 
     case ASM_EXPR:
 
+    case REALIGN_LOAD_EXPR:
+
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+
     case RESX_EXPR:
       *count += 1;
       break;
@@ -1344,8 +1820,9 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case CALL_EXPR:
       {
        tree decl = get_callee_fndecl (x);
+       tree arg;
 
-       if (decl && DECL_BUILT_IN (decl))
+       if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
          switch (DECL_FUNCTION_CODE (decl))
            {
            case BUILT_IN_CONSTANT_P:
@@ -1356,11 +1833,24 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
            default:
              break;
            }
-       *count += 10;
+
+       /* Our cost must be kept in sync with cgraph_estimate_size_after_inlining
+          that does use function declaration to figure out the arguments.  */
+       if (!decl)
+         {
+           for (arg = TREE_OPERAND (x, 1); arg; arg = TREE_CHAIN (arg))
+             *count += estimate_move_cost (TREE_TYPE (TREE_VALUE (arg)));
+         }
+       else
+         {
+           for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
+             *count += estimate_move_cost (TREE_TYPE (arg));
+         }
+
+       *count += PARAM_VALUE (PARAM_INLINE_CALL_COST);
        break;
       }
     default:
-      /* Abort here se we know we don't miss any nodes.  */
       gcc_unreachable ();
     }
   return NULL;
@@ -1372,31 +1862,95 @@ int
 estimate_num_insns (tree expr)
 {
   int num = 0;
-  walk_tree_without_duplicates (&expr, estimate_num_insns_1, &num);
+  struct pointer_set_t *visited_nodes;
+  basic_block bb;
+  block_stmt_iterator bsi;
+  struct function *my_function;
+
+  /* If we're given an entire function, walk the CFG.  */
+  if (TREE_CODE (expr) == FUNCTION_DECL)
+    {
+      my_function = DECL_STRUCT_FUNCTION (expr);
+      gcc_assert (my_function && my_function->cfg);
+      visited_nodes = pointer_set_create ();
+      FOR_EACH_BB_FN (bb, my_function)
+       {
+         for (bsi = bsi_start (bb);
+              !bsi_end_p (bsi);
+              bsi_next (&bsi))
+           {
+             walk_tree (bsi_stmt_ptr (bsi), estimate_num_insns_1,
+                        &num, visited_nodes);
+           }
+       }
+      pointer_set_destroy (visited_nodes);
+    }
+  else
+    walk_tree_without_duplicates (&expr, estimate_num_insns_1, &num);
+
   return num;
 }
 
+typedef struct function *function_p;
+
+DEF_VEC_P(function_p);
+DEF_VEC_ALLOC_P(function_p,heap);
+
+/* Initialized with NOGC, making this poisonous to the garbage collector.  */
+static VEC(function_p,heap) *cfun_stack;
+
+void
+push_cfun (struct function *new_cfun)
+{
+  VEC_safe_push (function_p, heap, cfun_stack, cfun);
+  cfun = new_cfun;
+}
+
+void
+pop_cfun (void)
+{
+  cfun = VEC_pop (function_p, cfun_stack);
+}
+
+/* Install new lexical TREE_BLOCK underneath 'current_block'.  */
+static void
+add_lexical_block (tree current_block, tree new_block)
+{
+  tree *blk_p;
+
+  /* Walk to the last sub-block.  */
+  for (blk_p = &BLOCK_SUBBLOCKS (current_block);
+       *blk_p;
+       blk_p = &TREE_CHAIN (*blk_p))
+    ;
+  *blk_p = new_block;
+  BLOCK_SUPERCONTEXT (new_block) = current_block;
+}
+
 /* If *TP is a CALL_EXPR, replace it with its inline expansion.  */
 
-static tree
-expand_call_inline (tree *tp, int *walk_subtrees, void *data)
+static bool
+expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
 {
   inline_data *id;
   tree t;
-  tree expr;
-  tree stmt;
   tree use_retvar;
-  tree decl;
   tree fn;
-  tree arg_inits;
-  tree *inlined_body;
   splay_tree st;
   tree args;
   tree return_slot_addr;
   tree modify_dest;
   location_t saved_location;
-  struct cgraph_edge *edge;
+  struct cgraph_edge *cg_edge;
   const char *reason;
+  basic_block return_block;
+  edge e;
+  block_stmt_iterator bsi, stmt_bsi;
+  bool successfully_inlined = FALSE;
+  tree t_step;
+  tree var;
+  struct cgraph_node *old_node;
+  tree decl;
 
   /* See what we've got.  */
   id = (inline_data *) data;
@@ -1408,39 +1962,6 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
   if (EXPR_HAS_LOCATION (t))
     input_location = EXPR_LOCATION (t);
 
-  /* Recurse, but letting recursive invocations know that we are
-     inside the body of a TARGET_EXPR.  */
-  if (TREE_CODE (*tp) == TARGET_EXPR)
-    {
-#if 0
-      int i, len = TREE_CODE_LENGTH (TARGET_EXPR);
-
-      /* We're walking our own subtrees.  */
-      *walk_subtrees = 0;
-
-      /* Actually walk over them.  This loop is the body of
-        walk_trees, omitting the case where the TARGET_EXPR
-        itself is handled.  */
-      for (i = 0; i < len; ++i)
-       {
-         if (i == 2)
-           ++id->in_target_cleanup_p;
-         walk_tree (&TREE_OPERAND (*tp, i), expand_call_inline, data,
-                    id->tree_pruner);
-         if (i == 2)
-           --id->in_target_cleanup_p;
-       }
-
-      goto egress;
-#endif
-    }
-
-  if (TYPE_P (t))
-    /* Because types were not copied in copy_body, CALL_EXPRs beneath
-       them should not be expanded.  This can happen if the type is a
-       dynamic array type, for example.  */
-    *walk_subtrees = 0;
-
   /* From here on, we're only interested in CALL_EXPRs.  */
   if (TREE_CODE (t) != CALL_EXPR)
     goto egress;
@@ -1471,11 +1992,11 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
   if (!id->current_node->analyzed)
     goto egress;
 
-  edge = cgraph_edge (id->current_node, t);
+  cg_edge = cgraph_edge (id->current_node, stmt);
 
   /* Constant propagation on argument done during previous inlining
      may create new direct call.  Produce an edge for it.  */
-  if (!edge)
+  if (!cg_edge)
     {
       struct cgraph_node *dest = cgraph_node (fn);
 
@@ -1484,47 +2005,77 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
          constant propagating arguments.  In all other cases we hit a bug
          (incorrect node sharing is most common reason for missing edges.  */
       gcc_assert (dest->needed || !flag_unit_at_a_time);
-      cgraph_create_edge (id->node, dest, t)->inline_failed
+      cgraph_create_edge (id->node, dest, stmt,
+                         bb->count, bb->loop_depth)->inline_failed
        = N_("originally indirect function call not considered for inlining");
       goto egress;
     }
 
   /* Don't try to inline functions that are not well-suited to
      inlining.  */
-  if (!cgraph_inline_p (edge, &reason))
+  if (!cgraph_inline_p (cg_edge, &reason))
     {
-      if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
+      if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))
+         /* Avoid warnings during early inline pass. */
+         && (!flag_unit_at_a_time || cgraph_global_info_ready))
        {
-         sorry ("%Jinlining failed in call to %qF: %s", fn, fn, reason);
+         sorry ("inlining failed in call to %q+F: %s", fn, reason);
          sorry ("called from here");
        }
       else if (warn_inline && DECL_DECLARED_INLINE_P (fn)
               && !DECL_IN_SYSTEM_HEADER (fn)
               && strlen (reason)
-              && !lookup_attribute ("noinline", DECL_ATTRIBUTES (fn)))
+              && !lookup_attribute ("noinline", DECL_ATTRIBUTES (fn))
+              /* Avoid warnings during early inline pass. */
+              && (!flag_unit_at_a_time || cgraph_global_info_ready))
        {
-         warning ("%Jinlining failed in call to %qF: %s", fn, fn, reason);
-         warning ("called from here");
+         warning (OPT_Winline, "inlining failed in call to %q+F: %s",
+                  fn, reason);
+         warning (OPT_Winline, "called from here");
        }
       goto egress;
     }
 
 #ifdef ENABLE_CHECKING
-  if (edge->callee->decl != id->node->decl)
-    verify_cgraph_node (edge->callee);
+  if (cg_edge->callee->decl != id->node->decl)
+    verify_cgraph_node (cg_edge->callee);
 #endif
 
-  if (! lang_hooks.tree_inlining.start_inlining (fn))
-    goto egress;
+  /* We will be inlining this callee.  */
+
+  id->eh_region = lookup_stmt_eh_region (stmt);
+
+  /* Split the block holding the CALL_EXPR.  */
+
+  e = split_block (bb, stmt);
+  bb = e->src;
+  return_block = e->dest;
+  remove_edge (e);
+
+  /* split_block splits before the statement, work around this by moving
+     the call into the first half_bb.  Not pretty, but seems easier than
+     doing the CFG manipulation by hand when the CALL_EXPR is in the last
+     statement in BB.  */
+  stmt_bsi = bsi_last (bb);
+  bsi = bsi_start (return_block);
+  if (!bsi_end_p (bsi))
+    bsi_move_before (&stmt_bsi, &bsi);
+  else
+    {
+      tree stmt = bsi_stmt (stmt_bsi);
+      bsi_remove (&stmt_bsi);
+      bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
+    }
+  stmt_bsi = bsi_start (return_block);
 
   /* Build a block containing code to initialize the arguments, the
      actual inline expansion of the body, and a label for the return
      statements within the function to jump to.  The type of the
      statement expression is the return type of the function call.  */
-  stmt = NULL;
-  expr = build (BIND_EXPR, void_type_node, NULL_TREE,
-               stmt, make_node (BLOCK));
-  BLOCK_ABSTRACT_ORIGIN (BIND_EXPR_BLOCK (expr)) = fn;
+  id->block = make_node (BLOCK);
+  BLOCK_ABSTRACT_ORIGIN (id->block) = fn;
+  BLOCK_SOURCE_LOCATION (id->block) = input_location;
+  add_lexical_block (TREE_BLOCK (stmt), id->block);
 
   /* Local declarations will be replaced by their equivalents in this
      map.  */
@@ -1534,231 +2085,156 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
 
   /* Initialize the parameters.  */
   args = TREE_OPERAND (t, 1);
-  return_slot_addr = NULL_TREE;
-  if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (t))
-    {
-      return_slot_addr = TREE_VALUE (args);
-      args = TREE_CHAIN (args);
-      TREE_TYPE (expr) = void_type_node;
-    }
-
-  arg_inits = initialize_inlined_parameters (id, args, TREE_OPERAND (t, 2),
-                                            fn, expr);
-  if (arg_inits)
-    {
-      /* Expand any inlined calls in the initializers.  Do this before we
-        push FN on the stack of functions we are inlining; we want to
-        inline calls to FN that appear in the initializers for the
-        parameters.
-
-        Note we need to save and restore the saved tree statement iterator
-        to avoid having it clobbered by expand_calls_inline.  */
-      tree_stmt_iterator save_tsi;
 
-      save_tsi = id->tsi;
-      expand_calls_inline (&arg_inits, id);
-      id->tsi = save_tsi;
+  initialize_inlined_parameters (id, args, TREE_OPERAND (t, 2), fn, bb);
 
-      /* And add them to the tree.  */
-      append_to_statement_list (arg_inits, &BIND_EXPR_BODY (expr));
-    }
-
-  /* Record the function we are about to inline so that we can avoid
-     recursing into it.  */
-  VARRAY_PUSH_TREE (id->fns, fn);
+  /* Record the function we are about to inline.  */
+  id->callee = fn;
 
-  /* Record the function we are about to inline if optimize_function
-     has not been called on it yet and we don't have it in the list.  */
-  if (! DECL_INLINED_FNS (fn))
-    {
-      int i;
-
-      for (i = VARRAY_ACTIVE_SIZE (id->inlined_fns) - 1; i >= 0; i--)
-       if (VARRAY_TREE (id->inlined_fns, i) == fn)
-         break;
-      if (i < 0)
-       VARRAY_PUSH_TREE (id->inlined_fns, fn);
-    }
+  if (DECL_STRUCT_FUNCTION (fn)->saved_blocks)
+    add_lexical_block (id->block, remap_blocks (DECL_STRUCT_FUNCTION (fn)->saved_blocks, id));
+  else if (DECL_INITIAL (fn))
+    add_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id));
 
   /* Return statements in the function body will be replaced by jumps
      to the RET_LABEL.  */
-  id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-  DECL_ARTIFICIAL (id->ret_label) = 1;
-  DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);
-  insert_decl_map (id, id->ret_label, id->ret_label);
 
   gcc_assert (DECL_INITIAL (fn));
   gcc_assert (TREE_CODE (DECL_INITIAL (fn)) == BLOCK);
 
   /* Find the lhs to which the result of this call is assigned.  */
-  modify_dest = tsi_stmt (id->tsi);
-  if (TREE_CODE (modify_dest) == MODIFY_EXPR)
-    modify_dest = TREE_OPERAND (modify_dest, 0);
+  return_slot_addr = NULL;
+  if (TREE_CODE (stmt) == MODIFY_EXPR)
+    {
+      modify_dest = TREE_OPERAND (stmt, 0);
+
+      /* The function which we are inlining might not return a value,
+        in which case we should issue a warning that the function
+        does not return a value.  In that case the optimizers will
+        see that the variable to which the value is assigned was not
+        initialized.  We do not want to issue a warning about that
+        uninitialized variable.  */
+      if (DECL_P (modify_dest))
+       TREE_NO_WARNING (modify_dest) = 1;
+      if (CALL_EXPR_RETURN_SLOT_OPT (t))
+       {
+         return_slot_addr = build_fold_addr_expr (modify_dest);
+         modify_dest = NULL;
+       }
+    }
   else
     modify_dest = NULL;
 
   /* Declare the return variable for the function.  */
   decl = declare_return_variable (id, return_slot_addr,
-                                 modify_dest, &use_retvar);
+                                 modify_dest, &use_retvar);
+  /* Do this only if declare_return_variable created a new one.  */
+  if (decl && !return_slot_addr && decl != modify_dest)
+    declare_inline_vars (id->block, decl);
 
   /* After we've initialized the parameters, we insert the body of the
      function itself.  */
-  {
-    struct cgraph_node *old_node = id->current_node;
-
-    id->current_node = edge->callee;
-    append_to_statement_list (copy_body (id), &BIND_EXPR_BODY (expr));
-    id->current_node = old_node;
-  }
-  inlined_body = &BIND_EXPR_BODY (expr);
-
-  /* After the body of the function comes the RET_LABEL.  This must come
-     before we evaluate the returned value below, because that evaluation
-     may cause RTL to be generated.  */
-  if (TREE_USED (id->ret_label))
+  old_node = id->current_node;
+
+  /* Anoint the callee-to-be-duplicated as the "current_node."  When
+     CALL_EXPRs within callee are duplicated, the edges from callee to
+     callee's callees (caller's grandchildren) will be cloned.  */
+  id->current_node = cg_edge->callee;
+
+  /* This is it.  Duplicate the callee body.  Assume callee is
+     pre-gimplified.  Note that we must not alter the caller
+     function in any way before this point, as this CALL_EXPR may be
+     a self-referential call; if we're calling ourselves, we need to
+     duplicate our body before altering anything.  */
+  copy_body (id, bb->count, bb->frequency, bb, return_block);
+  id->current_node = old_node;
+
+  /* Add local vars in this inlined callee to caller.  */
+  t_step = id->callee_cfun->unexpanded_var_list;
+  if (id->callee_cfun->saved_unexpanded_var_list)
+    t_step = id->callee_cfun->saved_unexpanded_var_list;
+  for (; t_step; t_step = TREE_CHAIN (t_step))
     {
-      tree label = build1 (LABEL_EXPR, void_type_node, id->ret_label);
-      append_to_statement_list (label, &BIND_EXPR_BODY (expr));
+      var = TREE_VALUE (t_step);
+      if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
+       cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
+                                              cfun->unexpanded_var_list);
+      else
+       cfun->unexpanded_var_list = tree_cons (NULL_TREE, remap_decl (var, id),
+                                              cfun->unexpanded_var_list);
     }
 
   /* Clean up.  */
   splay_tree_delete (id->decl_map);
   id->decl_map = st;
 
-  /* Although, from the semantic viewpoint, the new expression has
-     side-effects only if the old one did, it is not possible, from
-     the technical viewpoint, to evaluate the body of a function
-     multiple times without serious havoc.  */
-  TREE_SIDE_EFFECTS (expr) = 1;
-
-  tsi_link_before (&id->tsi, expr, TSI_SAME_STMT);
-
   /* If the inlined function returns a result that we care about,
-     then we're going to need to splice in a MODIFY_EXPR.  Otherwise
-     the call was a standalone statement and we can just replace it
-     with the BIND_EXPR inline representation of the called function.  */
-  if (!use_retvar || !modify_dest)
-    *tsi_stmt_ptr (id->tsi) = build_empty_stmt ();
+     clobber the CALL_EXPR with a reference to the return variable.  */
+  if (use_retvar && (TREE_CODE (bsi_stmt (stmt_bsi)) != CALL_EXPR))
+    {
+      *tp = use_retvar;
+      maybe_clean_or_replace_eh_stmt (stmt, stmt);
+    }
   else
-    *tp = use_retvar;
+    /* We're modifying a TSI owned by gimple_expand_calls_inline();
+       tsi_delink() will leave the iterator in a sane state.  */
+    bsi_remove (&stmt_bsi);
 
-  /* When we gimplify a function call, we may clear TREE_SIDE_EFFECTS on
-     the call if it is to a "const" function.  Thus the copy of
-     TREE_SIDE_EFFECTS from the CALL_EXPR to the BIND_EXPR above with
-     result in TREE_SIDE_EFFECTS not being set for the inlined copy of a
-     "const" function.
+  bsi_next (&bsi);
+  if (bsi_end_p (bsi))
+    tree_purge_dead_eh_edges (return_block);
 
-     Unfortunately, that is wrong as inlining the function can create/expose
-     interesting side effects (such as setting of a return value).
+  /* If the value of the new expression is ignored, that's OK.  We
+     don't warn about this for CALL_EXPRs, so we shouldn't warn about
+     the equivalent inlined version either.  */
+  TREE_USED (*tp) = 1;
 
-     The easiest solution is to simply recalculate TREE_SIDE_EFFECTS for
-     the toplevel expression.  */
-  recalculate_side_effects (expr);
+  /* Output the inlining info for this abstract function, since it has been
+     inlined.  If we don't do this now, we can lose the information about the
+     variables in the function when the blocks get blown away as soon as we
+     remove the cgraph node.  */
+  (*debug_hooks->outlining_inline_function) (cg_edge->callee->decl);
 
   /* Update callgraph if needed.  */
-  cgraph_remove_node (edge->callee);
-
-  /* Recurse into the body of the just inlined function.  */
-  expand_calls_inline (inlined_body, id);
-  VARRAY_POP (id->fns);
+  cgraph_remove_node (cg_edge->callee);
 
-  /* Don't walk into subtrees.  We've already handled them above.  */
-  *walk_subtrees = 0;
+  /* Declare the 'auto' variables added with this inlined body.  */
+  record_vars (BLOCK_VARS (id->block));
+  id->block = NULL_TREE;
+  successfully_inlined = TRUE;
 
-  lang_hooks.tree_inlining.end_inlining (fn);
-
-  /* Keep iterating.  */
  egress:
   input_location = saved_location;
-  return NULL_TREE;
+  return successfully_inlined;
 }
 
-static void
-expand_calls_inline (tree *stmt_p, inline_data *id)
+/* Expand call statements reachable from STMT_P.
+   We can only have CALL_EXPRs as the "toplevel" tree code or nested
+   in a MODIFY_EXPR.  See tree-gimple.c:get_call_expr_in().  We can
+   unfortunately not use that function here because we need a pointer
+   to the CALL_EXPR, not the tree itself.  */
+
+static bool
+gimple_expand_calls_inline (basic_block bb, inline_data *id)
 {
-  tree stmt = *stmt_p;
-  enum tree_code code = TREE_CODE (stmt);
-  int dummy;
+  block_stmt_iterator bsi;
 
-  switch (code)
+  /* Register specific tree functions.  */
+  tree_register_cfg_hooks ();
+  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
     {
-    case STATEMENT_LIST:
-      {
-       tree_stmt_iterator i;
-       tree new;
-
-       for (i = tsi_start (stmt); !tsi_end_p (i); )
-         {
-           id->tsi = i;
-           expand_calls_inline (tsi_stmt_ptr (i), id);
-
-           new = tsi_stmt (i);
-           if (TREE_CODE (new) == STATEMENT_LIST)
-             {
-               tsi_link_before (&i, new, TSI_SAME_STMT);
-               tsi_delink (&i);
-             }
-           else
-             tsi_next (&i);
-         }
-      }
-      break;
-
-    case COND_EXPR:
-      expand_calls_inline (&COND_EXPR_THEN (stmt), id);
-      expand_calls_inline (&COND_EXPR_ELSE (stmt), id);
-      break;
-
-    case CATCH_EXPR:
-      expand_calls_inline (&CATCH_BODY (stmt), id);
-      break;
-
-    case EH_FILTER_EXPR:
-      expand_calls_inline (&EH_FILTER_FAILURE (stmt), id);
-      break;
-
-    case TRY_CATCH_EXPR:
-    case TRY_FINALLY_EXPR:
-      expand_calls_inline (&TREE_OPERAND (stmt, 0), id);
-      expand_calls_inline (&TREE_OPERAND (stmt, 1), id);
-      break;
-
-    case BIND_EXPR:
-      expand_calls_inline (&BIND_EXPR_BODY (stmt), id);
-      break;
-
-    case COMPOUND_EXPR:
-      /* We're gimple.  We should have gotten rid of all these.  */
-      gcc_unreachable ();
-
-    case RETURN_EXPR:
-      stmt_p = &TREE_OPERAND (stmt, 0);
-      stmt = *stmt_p;
-      if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR)
-       break;
-
-      /* FALLTHRU */
-
-    case MODIFY_EXPR:
-      stmt_p = &TREE_OPERAND (stmt, 1);
-      stmt = *stmt_p;
-      if (TREE_CODE (stmt) == WITH_SIZE_EXPR)
-       {
-         stmt_p = &TREE_OPERAND (stmt, 0);
-         stmt = *stmt_p;
-       }
-      if (TREE_CODE (stmt) != CALL_EXPR)
-       break;
-
-      /* FALLTHRU */
-
-    case CALL_EXPR:
-      expand_call_inline (stmt_p, &dummy, id);
-      break;
-
-    default:
-      break;
+      tree *expr_p = bsi_stmt_ptr (bsi);
+      tree stmt = *expr_p;
+
+      if (TREE_CODE (*expr_p) == MODIFY_EXPR)
+       expr_p = &TREE_OPERAND (*expr_p, 1);
+      if (TREE_CODE (*expr_p) == WITH_SIZE_EXPR)
+       expr_p = &TREE_OPERAND (*expr_p, 0);
+      if (TREE_CODE (*expr_p) == CALL_EXPR)
+       if (expand_call_inline (bb, stmt, expr_p, id))
+         return true;
     }
+  return false;
 }
 
 /* Expand calls to inline functions in the body of FN.  */
@@ -1768,8 +2244,7 @@ optimize_inline_calls (tree fn)
 {
   inline_data id;
   tree prev_fn;
-  tree ifn;
-
+  basic_block bb;
   /* There is no point in performing inlining if errors have already
      occurred -- and we might crash if we try to inline invalid
      code.  */
@@ -1780,38 +2255,31 @@ optimize_inline_calls (tree fn)
   memset (&id, 0, sizeof (id));
 
   id.current_node = id.node = cgraph_node (fn);
-  /* Don't allow recursion into FN.  */
-  VARRAY_TREE_INIT (id.fns, 32, "fns");
-  VARRAY_PUSH_TREE (id.fns, fn);
+  id.caller = fn;
   /* Or any functions that aren't finished yet.  */
   prev_fn = NULL_TREE;
   if (current_function_decl)
     {
-      VARRAY_PUSH_TREE (id.fns, current_function_decl);
+      id.caller = current_function_decl;
       prev_fn = current_function_decl;
     }
+  push_gimplify_context ();
 
-  prev_fn = lang_hooks.tree_inlining.add_pending_fn_decls (&id.fns, prev_fn);
+  /* Reach the trees by walking over the CFG, and note the
+     enclosing basic-blocks in the call edges.  */
+  /* We walk the blocks going forward, because inlined function bodies
+     will split id->current_basic_block, and the new blocks will
+     follow it; we'll trudge through them, processing their CALL_EXPRs
+     along the way.  */
+  FOR_EACH_BB (bb)
+    gimple_expand_calls_inline (bb, &id);
 
-  /* Create the list of functions this call will inline.  */
-  VARRAY_TREE_INIT (id.inlined_fns, 32, "inlined_fns");
 
-  /* Keep track of the low-water mark, i.e., the point where the first
-     real inlining is represented in ID.FNS.  */
-  id.first_inlined_fn = VARRAY_ACTIVE_SIZE (id.fns);
-
-  /* Replace all calls to inline functions with the bodies of those
-     functions.  */
-  id.tree_pruner = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
-  expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
-
-  /* Clean up.  */
-  htab_delete (id.tree_pruner);
-  ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
-  if (VARRAY_ACTIVE_SIZE (id.inlined_fns))
-    memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
-           VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
-  DECL_INLINED_FNS (fn) = ifn;
+  pop_gimplify_context (NULL);
+  /* Renumber the (code) basic_blocks consecutively.  */
+  compact_blocks ();
+  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
+  number_blocks (fn);
 
 #ifdef ENABLE_CHECKING
     {
@@ -1824,6 +2292,11 @@ optimize_inline_calls (tree fn)
        gcc_assert (e->inline_failed);
     }
 #endif
+  /* We need to rescale frequencies again to peak at REG_BR_PROB_BASE
+     as inlining loops might increase the maximum.  */
+  if (ENTRY_BLOCK_PTR->count)
+    counts_to_freqs ();
+  fold_cond_expr_cond ();
 }
 
 /* FN is a function that has a complete body, and CLONE is a function whose
@@ -1836,34 +2309,42 @@ clone_body (tree clone, tree fn, void *arg_map)
   inline_data id;
 
   /* Clone the body, as if we were making an inline call.  But, remap the
-     parameters in the callee to the parameters of caller.  If there's an
-     in-charge parameter, map it to an appropriate constant.  */
+     parameters in the callee to the parameters of caller.  */
   memset (&id, 0, sizeof (id));
-  VARRAY_TREE_INIT (id.fns, 2, "fns");
-  VARRAY_PUSH_TREE (id.fns, clone);
-  VARRAY_PUSH_TREE (id.fns, fn);
+  id.caller = clone;
+  id.callee = fn;
+  id.callee_cfun = DECL_STRUCT_FUNCTION (fn);
   id.decl_map = (splay_tree)arg_map;
 
   /* Cloning is treated slightly differently from inlining.  Set
      CLONING_P so that it's clear which operation we're performing.  */
   id.cloning_p = true;
 
+  /* We're not inside any EH region.  */
+  id.eh_region = -1;
+
   /* Actually copy the body.  */
-  append_to_statement_list_force (copy_body (&id), &DECL_SAVED_TREE (clone));
+  append_to_statement_list_force (copy_generic_body (&id), &DECL_SAVED_TREE (clone));
 }
 
+/* Save duplicate body in FN.  MAP is used to pass around splay tree
+   used to update arguments in restore_body.  */
+
 /* Make and return duplicate of body in FN.  Put copies of DECL_ARGUMENTS
    in *arg_copy and of the static chain, if any, in *sc_copy.  */
 
-tree
+void
 save_body (tree fn, tree *arg_copy, tree *sc_copy)
 {
   inline_data id;
-  tree body, *parg;
+  tree newdecl, *parg;
+  basic_block fn_entry_block;
+  tree t_step;
 
   memset (&id, 0, sizeof (id));
-  VARRAY_TREE_INIT (id.fns, 1, "fns");
-  VARRAY_PUSH_TREE (id.fns, fn);
+  id.callee = fn;
+  id.callee_cfun = DECL_STRUCT_FUNCTION (fn);
+  id.caller = fn;
   id.node = cgraph_node (fn);
   id.saving_p = true;
   id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
@@ -1892,364 +2373,38 @@ save_body (tree fn, tree *arg_copy, tree *sc_copy)
       *sc_copy = new;
     }
 
-  insert_decl_map (&id, DECL_RESULT (fn), DECL_RESULT (fn));
-
-  /* Actually copy the body.  */
-  body = copy_body (&id);
-
-  /* Clean up.  */
-  splay_tree_delete (id.decl_map);
-  return body;
-}
-
-#define WALK_SUBTREE(NODE)                             \
-  do                                                   \
-    {                                                  \
-      result = walk_tree (&(NODE), func, data, pset);  \
-      if (result)                                      \
-       return result;                                  \
-    }                                                  \
-  while (0)
-
-/* This is a subroutine of walk_tree that walks field of TYPE that are to
-   be walked whenever a type is seen in the tree.  Rest of operands and return
-   value are as for walk_tree.  */
-
-static tree
-walk_type_fields (tree type, walk_tree_fn func, void *data,
-                 struct pointer_set_t *pset)
-{
-  tree result = NULL_TREE;
-
-  switch (TREE_CODE (type))
-    {
-    case POINTER_TYPE:
-    case REFERENCE_TYPE:
-      /* We have to worry about mutually recursive pointers.  These can't
-        be written in C.  They can in Ada.  It's pathological, but
-        there's an ACATS test (c38102a) that checks it.  Deal with this
-        by checking if we're pointing to another pointer, that one
-        points to another pointer, that one does too, and we have no htab.
-        If so, get a hash table.  We check three levels deep to avoid
-        the cost of the hash table if we don't need one.  */
-      if (POINTER_TYPE_P (TREE_TYPE (type))
-         && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (type)))
-         && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (TREE_TYPE (type))))
-         && !pset)
-       {
-         result = walk_tree_without_duplicates (&TREE_TYPE (type),
-                                                func, data);
-         if (result)
-           return result;
-
-         break;
-       }
-
-      /* ... fall through ... */
-
-    case COMPLEX_TYPE:
-      WALK_SUBTREE (TREE_TYPE (type));
-      break;
-
-    case METHOD_TYPE:
-      WALK_SUBTREE (TYPE_METHOD_BASETYPE (type));
-
-      /* Fall through.  */
-
-    case FUNCTION_TYPE:
-      WALK_SUBTREE (TREE_TYPE (type));
-      {
-       tree arg;
-
-       /* We never want to walk into default arguments.  */
-       for (arg = TYPE_ARG_TYPES (type); arg; arg = TREE_CHAIN (arg))
-         WALK_SUBTREE (TREE_VALUE (arg));
-      }
-      break;
-
-    case ARRAY_TYPE:
-      /* Don't follow this nodes's type if a pointer for fear that we'll
-        have infinite recursion.  Those types are uninteresting anyway.  */
-      if (!POINTER_TYPE_P (TREE_TYPE (type))
-         && TREE_CODE (TREE_TYPE (type)) != OFFSET_TYPE)
-       WALK_SUBTREE (TREE_TYPE (type));
-      WALK_SUBTREE (TYPE_DOMAIN (type));
-      break;
-
-    case BOOLEAN_TYPE:
-    case ENUMERAL_TYPE:
-    case INTEGER_TYPE:
-    case CHAR_TYPE:
-    case REAL_TYPE:
-      WALK_SUBTREE (TYPE_MIN_VALUE (type));
-      WALK_SUBTREE (TYPE_MAX_VALUE (type));
-      break;
-
-    case OFFSET_TYPE:
-      WALK_SUBTREE (TREE_TYPE (type));
-      WALK_SUBTREE (TYPE_OFFSET_BASETYPE (type));
-      break;
-
-    default:
-      break;
-    }
-
-  return NULL_TREE;
-}
-
-/* Apply FUNC to all the sub-trees of TP in a pre-order traversal.  FUNC is
-   called with the DATA and the address of each sub-tree.  If FUNC returns a
-   non-NULL value, the traversal is aborted, and the value returned by FUNC
-   is returned.  If PSET is non-NULL it is used to record the nodes visited,
-   and to avoid visiting a node more than once.  */
-
-tree
-walk_tree (tree *tp, walk_tree_fn func, void *data, struct pointer_set_t *pset)
-{
-  enum tree_code code;
-  int walk_subtrees;
-  tree result;
-
-#define WALK_SUBTREE_TAIL(NODE)                                \
-  do                                                   \
-    {                                                  \
-       tp = & (NODE);                                  \
-       goto tail_recurse;                              \
-    }                                                  \
-  while (0)
-
- tail_recurse:
-  /* Skip empty subtrees.  */
-  if (!*tp)
-    return NULL_TREE;
-
-  /* Don't walk the same tree twice, if the user has requested
-     that we avoid doing so.  */
-  if (pset && pointer_set_insert (pset, *tp))
-    return NULL_TREE;
-
-  /* Call the function.  */
-  walk_subtrees = 1;
-  result = (*func) (tp, &walk_subtrees, data);
-
-  /* If we found something, return it.  */
-  if (result)
-    return result;
-
-  code = TREE_CODE (*tp);
-
-  /* Even if we didn't, FUNC may have decided that there was nothing
-     interesting below this point in the tree.  */
-  if (!walk_subtrees)
-    {
-      if (code == TREE_LIST)
-       /* But we still need to check our siblings.  */
-       WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
-      else
-       return NULL_TREE;
-    }
+  /* We're not inside any EH region.  */
+  id.eh_region = -1;
 
-  result = lang_hooks.tree_inlining.walk_subtrees (tp, &walk_subtrees, func,
-                                                  data, pset);
-  if (result || ! walk_subtrees)
-    return result;
-
-  /* If this is a DECL_EXPR, walk into various fields of the type that it's
-     defining.  We only want to walk into these fields of a type in this
-     case.  Note that decls get walked as part of the processing of a
-     BIND_EXPR.
-
-     ??? Precisely which fields of types that we are supposed to walk in
-     this case vs. the normal case aren't well defined.  */
-  if (code == DECL_EXPR
-      && TREE_CODE (DECL_EXPR_DECL (*tp)) == TYPE_DECL
-      && TREE_CODE (TREE_TYPE (DECL_EXPR_DECL (*tp))) != ERROR_MARK)
-    {
-      tree *type_p = &TREE_TYPE (DECL_EXPR_DECL (*tp));
-
-      /* Call the function for the type.  See if it returns anything or
-        doesn't want us to continue.  If we are to continue, walk both
-        the normal fields and those for the declaration case.  */
-      result = (*func) (type_p, &walk_subtrees, data);
-      if (result || !walk_subtrees)
-       return NULL_TREE;
-
-      result = walk_type_fields (*type_p, func, data, pset);
-      if (result)
-       return result;
-
-      WALK_SUBTREE (TYPE_SIZE (*type_p));
-      WALK_SUBTREE (TYPE_SIZE_UNIT (*type_p));
-
-      /* If this is a record type, also walk the fields.  */
-      if (TREE_CODE (*type_p) == RECORD_TYPE
-         || TREE_CODE (*type_p) == UNION_TYPE
-         || TREE_CODE (*type_p) == QUAL_UNION_TYPE)
-       {
-         tree field;
-
-         for (field = TYPE_FIELDS (*type_p); field;
-              field = TREE_CHAIN (field))
-           {
-             /* We'd like to look at the type of the field, but we can easily
-                get infinite recursion.  So assume it's pointed to elsewhere
-                in the tree.  Also, ignore things that aren't fields.  */
-             if (TREE_CODE (field) != FIELD_DECL)
-               continue;
-
-             WALK_SUBTREE (DECL_FIELD_OFFSET (field));
-             WALK_SUBTREE (DECL_SIZE (field));
-             WALK_SUBTREE (DECL_SIZE_UNIT (field));
-             if (TREE_CODE (*type_p) == QUAL_UNION_TYPE)
-               WALK_SUBTREE (DECL_QUALIFIER (field));
-           }
-       }
-    }
-
-  else if (code != SAVE_EXPR
-          && code != BIND_EXPR
-          && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
-    {
-      int i, len;
-
-      /* Walk over all the sub-trees of this operand.  */
-      len = TREE_CODE_LENGTH (code);
-      /* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same.
-        But, we only want to walk once.  */
-      if (code == TARGET_EXPR
-         && TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
-       --len;
-
-      /* Go through the subtrees.  We need to do this in forward order so
-         that the scope of a FOR_EXPR is handled properly.  */
-#ifdef DEBUG_WALK_TREE
-      for (i = 0; i < len; ++i)
-       WALK_SUBTREE (TREE_OPERAND (*tp, i));
-#else
-      for (i = 0; i < len - 1; ++i)
-       WALK_SUBTREE (TREE_OPERAND (*tp, i));
-
-      if (len)
-       {
-         /* The common case is that we may tail recurse here.  */
-         if (code != BIND_EXPR
-             && !TREE_CHAIN (*tp))
-           WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, len - 1));
-         else
-           WALK_SUBTREE (TREE_OPERAND (*tp, len - 1));
-       }
-#endif
-    }
+  insert_decl_map (&id, DECL_RESULT (fn), DECL_RESULT (fn));
 
-  /* If this is a type, walk the needed fields in the type.  */
-  else if (TYPE_P (*tp))
+  DECL_STRUCT_FUNCTION (fn)->saved_blocks
+    = remap_blocks (DECL_INITIAL (fn), &id);
+  for (t_step = id.callee_cfun->unexpanded_var_list;
+       t_step;
+       t_step = TREE_CHAIN (t_step))
     {
-      result = walk_type_fields (*tp, func, data, pset);
-      if (result)
-       return result;
-    }
-  else
-    {
-      /* Not one of the easy cases.  We must explicitly go through the
-        children.  */
-      switch (code)
-       {
-       case ERROR_MARK:
-       case IDENTIFIER_NODE:
-       case INTEGER_CST:
-       case REAL_CST:
-       case VECTOR_CST:
-       case STRING_CST:
-       case BLOCK:
-       case PLACEHOLDER_EXPR:
-       case SSA_NAME:
-       case FIELD_DECL:
-       case RESULT_DECL:
-         /* None of thse have subtrees other than those already walked
-            above.  */
-         break;
-
-       case TREE_LIST:
-         WALK_SUBTREE (TREE_VALUE (*tp));
-         WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
-         break;
-
-       case TREE_VEC:
-         {
-           int len = TREE_VEC_LENGTH (*tp);
-
-           if (len == 0)
-             break;
-
-           /* Walk all elements but the first.  */
-           while (--len)
-             WALK_SUBTREE (TREE_VEC_ELT (*tp, len));
-
-           /* Now walk the first one as a tail call.  */
-           WALK_SUBTREE_TAIL (TREE_VEC_ELT (*tp, 0));
-         }
-
-       case COMPLEX_CST:
-         WALK_SUBTREE (TREE_REALPART (*tp));
-         WALK_SUBTREE_TAIL (TREE_IMAGPART (*tp));
-
-       case CONSTRUCTOR:
-         WALK_SUBTREE_TAIL (CONSTRUCTOR_ELTS (*tp));
-
-       case SAVE_EXPR:
-         WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0));
-
-       case BIND_EXPR:
-         {
-           tree decl;
-           for (decl = BIND_EXPR_VARS (*tp); decl; decl = TREE_CHAIN (decl))
-             {
-               /* Walk the DECL_INITIAL and DECL_SIZE.  We don't want to walk
-                  into declarations that are just mentioned, rather than
-                  declared; they don't really belong to this part of the tree.
-                  And, we can see cycles: the initializer for a declaration
-                  can refer to the declaration itself.  */
-               WALK_SUBTREE (DECL_INITIAL (decl));
-               WALK_SUBTREE (DECL_SIZE (decl));
-               WALK_SUBTREE (DECL_SIZE_UNIT (decl));
-             }
-           WALK_SUBTREE_TAIL (BIND_EXPR_BODY (*tp));
-         }
-
-       case STATEMENT_LIST:
-         {
-           tree_stmt_iterator i;
-           for (i = tsi_start (*tp); !tsi_end_p (i); tsi_next (&i))
-             WALK_SUBTREE (*tsi_stmt_ptr (i));
-         }
-         break;
-
-       default:
-         /* ??? This could be a language-defined node.  We really should make
-            a hook for it, but right now just ignore it.  */
-         break;
-       }
+      tree var = TREE_VALUE (t_step);
+      if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
+       cfun->saved_unexpanded_var_list
+         = tree_cons (NULL_TREE, var, cfun->saved_unexpanded_var_list);
+      else 
+       cfun->saved_unexpanded_var_list
+         = tree_cons (NULL_TREE, remap_decl (var, &id),
+                      cfun->saved_unexpanded_var_list);
     }
 
-  /* We didn't find what we were looking for.  */
-  return NULL_TREE;
-
-#undef WALK_SUBTREE
-#undef WALK_SUBTREE_TAIL
-}
-
-/* Like walk_tree, but does not walk duplicate nodes more than once.  */
+  /* Actually copy the body, including a new (struct function *) and CFG.
+     EH info is also duplicated so its labels point into the copied
+     CFG, not the original.  */
+  fn_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (fn));
+  newdecl = copy_body (&id, fn_entry_block->count, fn_entry_block->frequency,
+                      NULL, NULL);
+  DECL_STRUCT_FUNCTION (fn)->saved_cfg = DECL_STRUCT_FUNCTION (newdecl)->cfg;
+  DECL_STRUCT_FUNCTION (fn)->saved_eh = DECL_STRUCT_FUNCTION (newdecl)->eh;
 
-tree
-walk_tree_without_duplicates (tree *tp, walk_tree_fn func, void *data)
-{
-  tree result;
-  struct pointer_set_t *pset;
-
-  pset = pointer_set_create ();
-  result = walk_tree (tp, func, data, pset);
-  pointer_set_destroy (pset);
-  return result;
+  /* Clean up.  */
+  splay_tree_delete (id.decl_map);
 }
 
 /* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
@@ -2258,6 +2413,7 @@ tree
 copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 {
   enum tree_code code = TREE_CODE (*tp);
+  inline_data *id = (inline_data *) data;
 
   /* We make copies of most nodes.  */
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
@@ -2270,6 +2426,11 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       tree chain = TREE_CHAIN (*tp);
       tree new;
 
+      if (id && id->versioning_p && replace_ref_tree (id, tp))
+       {
+         *walk_subtrees = 0;
+         return NULL_TREE;
+       }
       /* Copy the node.  */
       new = copy_node (*tp);
 
@@ -2289,7 +2450,22 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       if (TREE_CODE (*tp) == BIND_EXPR)
        BIND_EXPR_BLOCK (*tp) = NULL_TREE;
     }
+  else if (code == CONSTRUCTOR)
+    {
+      /* CONSTRUCTOR nodes need special handling because
+         we need to duplicate the vector of elements.  */
+      tree new;
+
+      new = copy_node (*tp);
+
+      /* Propagate mudflap marked-ness.  */
+      if (flag_mudflap && mf_marked_p (*tp))
+        mf_mark (new);
 
+      CONSTRUCTOR_ELTS (new) = VEC_copy (constructor_elt, gc,
+                                        CONSTRUCTOR_ELTS (*tp));
+      *tp = new;
+    }
   else if (TREE_CODE_CLASS (code) == tcc_type)
     *walk_subtrees = 0;
   else if (TREE_CODE_CLASS (code) == tcc_declaration)
@@ -2303,7 +2479,8 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
 /* The SAVE_EXPR pointed to by TP is being copied.  If ST contains
    information indicating to what new SAVE_EXPR this one should be mapped,
-   use that one.  Otherwise, create a new node and enter it in ST.  */
+   use that one.  Otherwise, create a new node and enter it in ST.  FN is
+   the function into which the copy will be placed.  */
 
 static void
 remap_save_expr (tree *tp, void *st_, int *walk_subtrees)
@@ -2356,8 +2533,8 @@ mark_local_for_remap_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
 
       /* Copy the decl and remember the copy.  */
       insert_decl_map (id, decl,
-                      copy_decl_for_inlining (decl, DECL_CONTEXT (decl),
-                                              DECL_CONTEXT (decl)));
+                      copy_decl_for_dup (decl, DECL_CONTEXT (decl),
+                                         DECL_CONTEXT (decl),  /*versioning=*/false));
     }
 
   return NULL_TREE;
@@ -2443,8 +2620,8 @@ unsave_expr_now (tree expr)
 
   /* Set up ID.  */
   memset (&id, 0, sizeof (id));
-  VARRAY_TREE_INIT (id.fns, 1, "fns");
-  VARRAY_PUSH_TREE (id.fns, current_function_decl);
+  id.callee = current_function_decl;
+  id.caller = current_function_decl;
   id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
 
   /* Walk the tree once to find local labels.  */
@@ -2476,15 +2653,350 @@ debug_find_tree (tree top, tree search)
   return walk_tree_without_duplicates (&top, debug_find_tree_1, search) != 0;
 }
 
+
 /* Declare the variables created by the inliner.  Add all the variables in
    VARS to BIND_EXPR.  */
 
 static void
-declare_inline_vars (tree bind_expr, tree vars)
+declare_inline_vars (tree block, tree vars)
 {
   tree t;
   for (t = vars; t; t = TREE_CHAIN (t))
     DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
 
-  add_var_to_bind_expr (bind_expr, vars);
+  if (block)
+    BLOCK_VARS (block) = chainon (BLOCK_VARS (block), vars);
+}
+
+
+/* Copy NODE (which must be a DECL).  The DECL originally was in the FROM_FN,
+   but now it will be in the TO_FN.  VERSIONING means that this function 
+   is used by the versioning utility (not inlining or cloning).  */
+
+tree
+copy_decl_for_dup (tree decl, tree from_fn, tree to_fn, bool versioning)
+{
+  tree copy;
+
+  gcc_assert (DECL_P (decl));
+  /* Copy the declaration.  */
+  if (!versioning
+      && (TREE_CODE (decl) == PARM_DECL
+         || TREE_CODE (decl) == RESULT_DECL))
+    {
+      tree type = TREE_TYPE (decl);
+
+      /* For a parameter or result, we must make an equivalent VAR_DECL,
+        not a new PARM_DECL.  */
+      copy = build_decl (VAR_DECL, DECL_NAME (decl), type);
+      TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
+      TREE_READONLY (copy) = TREE_READONLY (decl);
+      TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
+      DECL_COMPLEX_GIMPLE_REG_P (copy) = DECL_COMPLEX_GIMPLE_REG_P (decl);
+    }
+  else
+    {
+      copy = copy_node (decl);
+      /* The COPY is not abstract; it will be generated in TO_FN.  */
+      DECL_ABSTRACT (copy) = 0;
+      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
+        expand_goto_internal.  */
+      if (TREE_CODE (copy) == LABEL_DECL)
+       {
+         TREE_ADDRESSABLE (copy) = 0;
+         LABEL_DECL_UID (copy) = -1;
+       }
+    }
+
+  /* Don't generate debug information for the copy if we wouldn't have
+     generated it for the copy either.  */
+  DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (decl);
+  DECL_IGNORED_P (copy) = DECL_IGNORED_P (decl);
+
+  /* Set the DECL_ABSTRACT_ORIGIN so the debugging routines know what
+     declaration inspired this copy.  */ 
+  DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (decl);
+
+  /* The new variable/label has no RTL, yet.  */
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (copy), TS_DECL_WRTL)
+      && !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;
+
+  /* Set the context for the new declaration.  */
+  if (!DECL_CONTEXT (decl))
+    /* Globals stay global.  */
+    ;
+  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 to, either.  */
+    ;
+  else if (TREE_STATIC (decl))
+    /* Function-scoped static variables should stay in the original
+       function.  */
+    ;
+  else
+    /* Ordinary automatic local variables are now in the scope of the
+       new function.  */
+    DECL_CONTEXT (copy) = to_fn;
+
+  return copy;
+}
+
+/* Return a copy of the function's argument tree.  */
+static tree
+copy_arguments_for_versioning (tree orig_parm, inline_data * id)
+{
+  tree *arg_copy, *parg;
+
+  arg_copy = &orig_parm;
+  for (parg = arg_copy; *parg; parg = &TREE_CHAIN (*parg))
+    {
+      tree new = remap_decl (*parg, id);
+      lang_hooks.dup_lang_specific_decl (new);
+      TREE_CHAIN (new) = TREE_CHAIN (*parg);
+      *parg = new;
+    }
+  return orig_parm;
+}
+
+/* Return a copy of the function's static chain.  */
+static tree
+copy_static_chain (tree static_chain, inline_data * id)
+{
+  tree *chain_copy, *pvar;
+
+  chain_copy = &static_chain;
+  for (pvar = chain_copy; *pvar; pvar = &TREE_CHAIN (*pvar))
+    {
+      tree new = remap_decl (*pvar, id);
+      lang_hooks.dup_lang_specific_decl (new);
+      TREE_CHAIN (new) = TREE_CHAIN (*pvar);
+      *pvar = new;
+    }
+  return static_chain;
+}
+
+/* Return true if the function is allowed to be versioned.
+   This is a guard for the versioning functionality.  */
+bool
+tree_versionable_function_p (tree fndecl)
+{
+  if (fndecl == NULL_TREE)
+    return false;
+  /* ??? There are cases where a function is
+     uninlinable but can be versioned.  */
+  if (!tree_inlinable_function_p (fndecl))
+    return false;
+  
+  return true;
+}
+
+/* Create a copy of a function's tree.
+   OLD_DECL and NEW_DECL are FUNCTION_DECL tree nodes
+   of the original function and the new copied function
+   respectively.  In case we want to replace a DECL 
+   tree with another tree while duplicating the function's 
+   body, TREE_MAP represents the mapping between these 
+   trees.  */
+void
+tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map)
+{
+  struct cgraph_node *old_version_node;
+  struct cgraph_node *new_version_node;
+  inline_data id;
+  tree p, new_fndecl;
+  unsigned i;
+  struct ipa_replace_map *replace_info;
+  basic_block old_entry_block;
+  tree t_step;
+
+  gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL
+             && TREE_CODE (new_decl) == FUNCTION_DECL);
+  DECL_POSSIBLY_INLINED (old_decl) = 1;
+
+  old_version_node = cgraph_node (old_decl);
+  new_version_node = cgraph_node (new_decl);
+
+  allocate_struct_function (new_decl);
+  /* Cfun points to the new allocated function struct at this point.  */
+  cfun->function_end_locus = DECL_SOURCE_LOCATION (new_decl);
+
+  DECL_ARTIFICIAL (new_decl) = 1;
+  DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl);
+
+  /* Generate a new name for the new version. */
+  DECL_NAME (new_decl) =
+    create_tmp_var_name (NULL);
+  /* Create a new SYMBOL_REF rtx for the new name. */
+  if (DECL_RTL (old_decl) != NULL)
+    {
+      SET_DECL_RTL (new_decl, copy_rtx (DECL_RTL (old_decl)));
+      XEXP (DECL_RTL (new_decl), 0) =
+       gen_rtx_SYMBOL_REF (GET_MODE (XEXP (DECL_RTL (old_decl), 0)),
+                           IDENTIFIER_POINTER (DECL_NAME (new_decl)));
+    }
+
+  /* Prepare the data structures for the tree copy.  */
+  memset (&id, 0, sizeof (id));
+  
+  /* The new version. */
+  id.node = new_version_node;
+  
+  /* The old version. */
+  id.current_node = cgraph_node (old_decl);
+  
+  id.versioning_p = true;
+  id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+  id.caller = new_decl;
+  id.callee = old_decl;
+  id.callee_cfun = DECL_STRUCT_FUNCTION (old_decl);
+  
+  current_function_decl = new_decl;
+  
+  /* Copy the function's static chain.  */
+  p = DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl;
+  if (p)
+    DECL_STRUCT_FUNCTION (new_decl)->static_chain_decl =
+      copy_static_chain (DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl,
+                        &id);
+  /* Copy the function's arguments.  */
+  if (DECL_ARGUMENTS (old_decl) != NULL_TREE)
+    DECL_ARGUMENTS (new_decl) =
+      copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id);
+  
+  /* If there's a tree_map, prepare for substitution.  */
+  if (tree_map)
+    for (i = 0; i < VARRAY_ACTIVE_SIZE (tree_map); i++)
+      {
+       replace_info = VARRAY_GENERIC_PTR (tree_map, i);
+       if (replace_info->replace_p && !replace_info->ref_p)
+         insert_decl_map (&id, replace_info->old_tree,
+                          replace_info->new_tree);
+       else if (replace_info->replace_p && replace_info->ref_p)
+         id.ipa_info = tree_map;
+      }
+  
+  DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.callee), &id);
+  
+  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
+  number_blocks (id.caller);
+  
+  if (DECL_STRUCT_FUNCTION (old_decl)->unexpanded_var_list != NULL_TREE)
+    /* Add local vars.  */
+    for (t_step = DECL_STRUCT_FUNCTION (old_decl)->unexpanded_var_list;
+        t_step; t_step = TREE_CHAIN (t_step))
+      {
+       tree var = TREE_VALUE (t_step);
+       if (TREE_STATIC (var) && !TREE_ASM_WRITTEN (var))
+         cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
+                                                cfun->unexpanded_var_list);
+       else
+         cfun->unexpanded_var_list =
+           tree_cons (NULL_TREE, remap_decl (var, &id),
+                      cfun->unexpanded_var_list);
+      }
+  
+  /* Copy the Function's body.  */
+  old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
+    (DECL_STRUCT_FUNCTION (old_decl));
+  new_fndecl = copy_body (&id,
+                         old_entry_block->count,
+                         old_entry_block->frequency, NULL, NULL);
+  
+  DECL_SAVED_TREE (new_decl) = DECL_SAVED_TREE (new_fndecl);
+
+  DECL_STRUCT_FUNCTION (new_decl)->cfg =
+    DECL_STRUCT_FUNCTION (new_fndecl)->cfg;
+  DECL_STRUCT_FUNCTION (new_decl)->eh = DECL_STRUCT_FUNCTION (new_fndecl)->eh;
+  DECL_STRUCT_FUNCTION (new_decl)->ib_boundaries_block =
+    DECL_STRUCT_FUNCTION (new_fndecl)->ib_boundaries_block;
+  DECL_STRUCT_FUNCTION (new_decl)->last_label_uid =
+    DECL_STRUCT_FUNCTION (new_fndecl)->last_label_uid;
+
+  if (DECL_RESULT (old_decl) != NULL_TREE)
+    {
+      tree *res_decl = &DECL_RESULT (old_decl);
+      DECL_RESULT (new_decl) = remap_decl (*res_decl, &id);
+      lang_hooks.dup_lang_specific_decl (DECL_RESULT (new_decl));
+    }
+  
+  current_function_decl = NULL;
+  /* Renumber the lexical scoping (non-code) blocks consecutively.  */
+  number_blocks (new_decl);
+
+  /* Clean up.  */
+  splay_tree_delete (id.decl_map);
+  fold_cond_expr_cond ();
+  return;
+}
+
+/*  Replace an INDIRECT_REF tree of a given DECL tree with a new 
+    given tree.
+    ID->ipa_info keeps the old tree and the new tree.  
+    TP points to the INDIRECT REF tree.  Return true if 
+    the trees were replaced.  */
+static bool
+replace_ref_tree (inline_data * id, tree * tp)
+{
+  bool replaced = false;
+  tree new;
+
+  if (id->ipa_info && VARRAY_ACTIVE_SIZE (id->ipa_info) > 0)
+    {
+      unsigned i;
+
+      for (i = 0; i < VARRAY_ACTIVE_SIZE (id->ipa_info); i++)
+       {
+         struct ipa_replace_map *replace_info;
+         replace_info = VARRAY_GENERIC_PTR (id->ipa_info, i);
+
+         if (replace_info->replace_p && replace_info->ref_p)
+           {
+             tree old_tree = replace_info->old_tree;
+             tree new_tree = replace_info->new_tree;
+
+             if (TREE_CODE (*tp) == INDIRECT_REF
+                 && TREE_OPERAND (*tp, 0) == old_tree)
+               {
+                 new = copy_node (new_tree);
+                 *tp = new;
+                 replaced = true;
+               }
+           }
+       }
+    }
+  return replaced;
+}
+
+/* Return true if we are inlining.  */
+static inline bool
+inlining_p (inline_data * id)
+{
+  return (!id->saving_p && !id->cloning_p && !id->versioning_p);
+}
+
+/* Duplicate a type, fields and all.  */
+
+tree
+build_duplicate_type (tree type)
+{
+  inline_data id;
+
+  memset (&id, 0, sizeof (id));
+  id.callee = current_function_decl;
+  id.caller = current_function_decl;
+  id.callee_cfun = cfun;
+  id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+
+  type = remap_type_1 (type, &id);
+
+  splay_tree_delete (id.decl_map);
+
+  return type;
 }