OSDN Git Service

2008-05-23 Rafael Espindola <espindola@google.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 2b7ab9e..fb4f765 100644 (file)
@@ -1,5 +1,5 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
@@ -127,7 +127,6 @@ eni_weights eni_time_weights;
 /* Prototypes.  */
 
 static tree declare_return_variable (copy_body_data *, tree, tree, tree *);
-static tree copy_generic_body (copy_body_data *);
 static bool inlinable_function_p (tree);
 static void remap_block (tree *, copy_body_data *);
 static tree remap_decls (tree, copy_body_data *);
@@ -140,7 +139,6 @@ static void remap_save_expr (tree *, void *, int *);
 static void add_lexical_block (tree current_block, tree new_block);
 static tree copy_decl_to_var (tree, copy_body_data *);
 static tree copy_result_decl_to_var (tree, copy_body_data *);
-static tree copy_decl_no_change (tree, copy_body_data *);
 static tree copy_decl_maybe_to_var (tree, copy_body_data *);
 
 /* Insert a tree->tree mapping for ID.  Despite the name suggests
@@ -186,15 +184,42 @@ remap_ssa_name (tree name, copy_body_data *id)
     {
       new = make_ssa_name (new, NULL);
       insert_decl_map (id, name, new);
-      if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name)))
-       {
-         SSA_NAME_DEF_STMT (new) = build_empty_stmt ();
-         if (gimple_default_def (id->src_cfun, SSA_NAME_VAR (name)) == name)
-           set_default_def (SSA_NAME_VAR (new), new);
-       }
       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new)
        = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
       TREE_TYPE (new) = TREE_TYPE (SSA_NAME_VAR (new));
+      if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name)))
+       {
+         /* By inlining function having uninitialized variable, we might
+            extend the lifetime (variable might get reused).  This cause
+            ICE in the case we end up extending lifetime of SSA name across
+            abnormal edge, but also increase register presure.
+
+            We simply initialize all uninitialized vars by 0 except for case
+            we are inlining to very first BB.  We can avoid this for all
+            BBs that are not withing strongly connected regions of the CFG,
+            but this is bit expensive to test.
+          */
+         if (id->entry_bb && is_gimple_reg (SSA_NAME_VAR (name))
+             && TREE_CODE (SSA_NAME_VAR (name)) != PARM_DECL
+             && (id->entry_bb != EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
+                 || EDGE_COUNT (id->entry_bb->preds) != 1))
+           {
+             block_stmt_iterator bsi = bsi_last (id->entry_bb);
+             tree init_stmt
+                 = build_gimple_modify_stmt (new,
+                                             fold_convert (TREE_TYPE (new),
+                                                           integer_zero_node));
+             bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
+             SSA_NAME_DEF_STMT (new) = init_stmt;
+             SSA_NAME_IS_DEFAULT_DEF (new) = 0;
+           }
+         else
+           {
+             SSA_NAME_DEF_STMT (new) = build_empty_stmt ();
+             if (gimple_default_def (id->src_cfun, SSA_NAME_VAR (name)) == name)
+               set_default_def (SSA_NAME_VAR (new), new);
+           }
+       }
     }
   else
     insert_decl_map (id, name, new);
@@ -259,7 +284,8 @@ remap_decl (tree decl, copy_body_data *id)
              tree map = remap_ssa_name (def, id);
              /* Watch out RESULT_DECLs whose SSA names map directly
                 to them.  */
-             if (TREE_CODE (map) == SSA_NAME)
+             if (TREE_CODE (map) == SSA_NAME
+                 && IS_EMPTY_STMT (SSA_NAME_DEF_STMT (map)))
                set_default_def (t, map);
            }
          add_referenced_var (t);
@@ -273,24 +299,8 @@ remap_decl (tree decl, copy_body_data *id)
 static tree
 remap_type_1 (tree type, copy_body_data *id)
 {
-  tree *node;
   tree new, t;
 
-  if (type == NULL)
-    return type;
-
-  /* See if we have remapped this type.  */
-  node = (tree *) pointer_map_contains (id->decl_map, type);
-  if (node)
-    return *node;
-
-  /* The type only needs remapping if it's variably modified.  */
-  if (! variably_modified_type_p (type, id->src_fn))
-    {
-      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.  */
@@ -322,7 +332,7 @@ remap_type_1 (tree type, copy_body_data *id)
     {
       t = remap_type (t, id);
       TYPE_MAIN_VARIANT (new) = t;
-      TYPE_NEXT_VARIANT (new) = TYPE_MAIN_VARIANT (t);
+      TYPE_NEXT_VARIANT (new) = TYPE_NEXT_VARIANT (t);
       TYPE_NEXT_VARIANT (t) = new;
     }
   else
@@ -397,6 +407,7 @@ tree
 remap_type (tree type, copy_body_data *id)
 {
   tree *node;
+  tree tmp;
 
   if (type == NULL)
     return type;
@@ -413,7 +424,11 @@ remap_type (tree type, copy_body_data *id)
       return type;
     }
 
-  return remap_type_1 (type, id);
+  id->remapping_type_depth++;
+  tmp = remap_type_1 (type, id);
+  id->remapping_type_depth--;
+
+  return tmp;
 }
 
 static tree
@@ -427,14 +442,14 @@ remap_decls (tree decls, copy_body_data *id)
     {
       tree new_var;
 
-      /* We can not chain the local static declarations into the unexpanded_var_list
+      /* We can not chain the local static declarations into the local_decls
          as we can't duplicate them or break one decl rule.  Go ahead and link
-         them into unexpanded_var_list.  */
+         them into local_decls.  */
       if (!auto_var_in_fn_p (old_var, id->src_fn)
          && !DECL_EXTERNAL (old_var))
        {
-         cfun->unexpanded_var_list = tree_cons (NULL_TREE, old_var,
-                                                cfun->unexpanded_var_list);
+         cfun->local_decls = tree_cons (NULL_TREE, old_var,
+                                                cfun->local_decls);
          continue;
        }
 
@@ -481,7 +496,7 @@ remap_block (tree *block, copy_body_data *id)
   fn = id->dst_fn;
 
   if (id->transform_lang_insert_block)
-    lang_hooks.decls.insert_block (new_block);
+    id->transform_lang_insert_block (new_block);
 
   /* Remember the remapped block.  */
   insert_decl_map (id, old_block, new_block);
@@ -656,7 +671,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
            {
              value = *n;
              STRIP_TYPE_NOPS (value);
-             if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
+             if (TREE_CONSTANT (value) || TREE_READONLY (value))
                {
                  *tp = build_empty_stmt ();
                  return copy_body_r (tp, walk_subtrees, data);
@@ -684,11 +699,18 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
              tree type = TREE_TYPE (TREE_TYPE (*n));
              new = unshare_expr (*n);
              old = *tp;
-             *tp = fold_indirect_ref_1 (type, new);
+             *tp = gimple_fold_indirect_ref (new);
              if (! *tp)
                {
                  if (TREE_CODE (new) == ADDR_EXPR)
-                   *tp = TREE_OPERAND (new, 0);
+                   {
+                     *tp = fold_indirect_ref_1 (type, new);
+                     /* ???  We should either assert here or build
+                        a VIEW_CONVERT_EXPR instead of blindly leaking
+                        incompatible types to our IL.  */
+                     if (! *tp)
+                       *tp = TREE_OPERAND (new, 0);
+                   }
                  else
                    {
                      *tp = build1 (INDIRECT_REF, type, new);
@@ -704,9 +726,10 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
         tweak some special cases.  */
       copy_tree_r (tp, walk_subtrees, NULL);
 
-      /* Global variables we didn't seen yet needs to go into referenced
-        vars.  */
-      if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL)
+      /* Global variables we haven't seen yet needs to go into referenced
+        vars.  If not referenced from types only.  */
+      if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL
+         && id->remapping_type_depth == 0)
        add_referenced_var (*tp);
        
       /* If EXPR has block defined, map it to newly constructed block.
@@ -748,6 +771,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
         and friends are up-to-date.  */
       else if (TREE_CODE (*tp) == ADDR_EXPR)
        {
+         int invariant = is_gimple_min_invariant (*tp);
          walk_tree (&TREE_OPERAND (*tp, 0), copy_body_r, id, NULL);
          /* Handle the case where we substituted an INDIRECT_REF
             into the operand of the ADDR_EXPR.  */
@@ -755,6 +779,10 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
            *tp = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0);
          else
            recompute_tree_invariant_for_addr_expr (*tp);
+         /* If this used to be invariant, but is not any longer,
+            then regimplification is probably needed.  */
+         if (invariant && !is_gimple_min_invariant (*tp))
+           id->regimplify = true;
          *walk_subtrees = 0;
        }
     }
@@ -792,6 +820,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
       tree stmt = bsi_stmt (bsi);
       tree orig_stmt = stmt;
 
+      id->regimplify = false;
       walk_tree (&stmt, copy_body_r, id, NULL);
 
       /* RETURN_EXPR might be removed,
@@ -804,9 +833,10 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
 
          /* With return slot optimization we can end up with
             non-gimple (foo *)&this->m, fix that here.  */
-         if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
-             && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == NOP_EXPR
-             && !is_gimple_val (TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0)))
+         if ((TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+              && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == NOP_EXPR
+              && !is_gimple_val (TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0)))
+             || id->regimplify)
            gimplify_stmt (&stmt);
 
           bsi_insert_after (&copy_bsi, stmt, BSI_NEW_STMT);
@@ -815,9 +845,95 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
             into multiple statements, we need to process all of them.  */
          while (!bsi_end_p (copy_bsi))
            {
-             stmt = bsi_stmt (copy_bsi);
+             tree *stmtp = bsi_stmt_ptr (copy_bsi);
+             tree stmt = *stmtp;
              call = get_call_expr_in (stmt);
 
+             if (call && CALL_EXPR_VA_ARG_PACK (call) && id->call_expr)
+               {
+                 /* __builtin_va_arg_pack () should be replaced by
+                    all arguments corresponding to ... in the caller.  */
+                 tree p, *argarray, new_call, *call_ptr;
+                 int nargs = call_expr_nargs (id->call_expr);
+
+                 for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+                   nargs--;
+
+                 argarray = (tree *) alloca ((nargs + call_expr_nargs (call))
+                                             * sizeof (tree));
+
+                 memcpy (argarray, CALL_EXPR_ARGP (call),
+                         call_expr_nargs (call) * sizeof (*argarray));
+                 memcpy (argarray + call_expr_nargs (call),
+                         CALL_EXPR_ARGP (id->call_expr)
+                         + (call_expr_nargs (id->call_expr) - nargs),
+                         nargs * sizeof (*argarray));
+
+                 new_call = build_call_array (TREE_TYPE (call),
+                                              CALL_EXPR_FN (call),
+                                              nargs + call_expr_nargs (call),
+                                              argarray);
+                 /* Copy all CALL_EXPR flags, locus and block, except
+                    CALL_EXPR_VA_ARG_PACK flag.  */
+                 CALL_EXPR_STATIC_CHAIN (new_call)
+                   = CALL_EXPR_STATIC_CHAIN (call);
+                 CALL_EXPR_TAILCALL (new_call) = CALL_EXPR_TAILCALL (call);
+                 CALL_EXPR_RETURN_SLOT_OPT (new_call)
+                   = CALL_EXPR_RETURN_SLOT_OPT (call);
+                 CALL_FROM_THUNK_P (new_call) = CALL_FROM_THUNK_P (call);
+                 CALL_CANNOT_INLINE_P (new_call)
+                   = CALL_CANNOT_INLINE_P (call);
+                 TREE_NOTHROW (new_call) = TREE_NOTHROW (call);
+                 SET_EXPR_LOCUS (new_call, EXPR_LOCUS (call));
+                 TREE_BLOCK (new_call) = TREE_BLOCK (call);
+
+                 call_ptr = stmtp;
+                 if (TREE_CODE (*call_ptr) == GIMPLE_MODIFY_STMT)
+                   call_ptr = &GIMPLE_STMT_OPERAND (*call_ptr, 1);
+                 if (TREE_CODE (*call_ptr) == WITH_SIZE_EXPR)
+                   call_ptr = &TREE_OPERAND (*call_ptr, 0);
+                 gcc_assert (*call_ptr == call);
+                 if (call_ptr == stmtp)
+                   {
+                     bsi_replace (&copy_bsi, new_call, true);
+                     stmtp = bsi_stmt_ptr (copy_bsi);
+                     stmt = *stmtp;
+                   }
+                 else
+                   {
+                     *call_ptr = new_call;
+                     stmt = *stmtp;
+                     update_stmt (stmt);
+                   }
+               }
+             else if (call
+                      && id->call_expr
+                      && (decl = get_callee_fndecl (call))
+                      && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+                      && DECL_FUNCTION_CODE (decl)
+                         == BUILT_IN_VA_ARG_PACK_LEN)
+               {
+                 /* __builtin_va_arg_pack_len () should be replaced by
+                    the number of anonymous arguments.  */
+                 int nargs = call_expr_nargs (id->call_expr);
+                 tree count, *call_ptr, p;
+
+                 for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+                   nargs--;
+
+                 count = build_int_cst (integer_type_node, nargs);
+                 call_ptr = stmtp;
+                 if (TREE_CODE (*call_ptr) == GIMPLE_MODIFY_STMT)
+                   call_ptr = &GIMPLE_STMT_OPERAND (*call_ptr, 1);
+                 if (TREE_CODE (*call_ptr) == WITH_SIZE_EXPR)
+                   call_ptr = &TREE_OPERAND (*call_ptr, 0);
+                 gcc_assert (*call_ptr == call && call_ptr != stmtp);
+                 *call_ptr = count;
+                 stmt = *stmtp;
+                 update_stmt (stmt);
+                 call = NULL_TREE;
+               }
+
              /* Statements produced by inlining can be unfolded, especially
                 when we constant propagated some operands.  We can't fold
                 them right now for two reasons:
@@ -932,16 +1048,19 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
    across EH edges from basic block within inlined functions destinating
    to landing pads in function we inline into.
 
-   The function mark PHI_RESULT of such PHI nodes for renaming; it is
-   safe the EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI
-   must be set.  This means, that there will be no overlapping live ranges
+   The function fills in PHI_RESULTs of such PHI nodes if they refer
+   to gimple regs.  Otherwise, the function mark PHI_RESULT of such
+   PHI nodes for renaming.  For non-gimple regs, renaming is safe: the
+   EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI must be
+   set, and this means that there will be no overlapping live ranges
    for the underlying symbol.
 
    This might change in future if we allow redirecting of EH edges and
    we might want to change way build CFG pre-inlining to include
    all the possible edges then.  */
 static void
-update_ssa_across_eh_edges (basic_block bb)
+update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb,
+                                 bool can_throw, bool nonlocal_goto)
 {
   edge e;
   edge_iterator ei;
@@ -952,13 +1071,35 @@ update_ssa_across_eh_edges (basic_block bb)
       {
        tree phi;
 
-       gcc_assert (e->flags & EDGE_EH);
+       gcc_assert (e->flags & EDGE_ABNORMAL);
+       if (!nonlocal_goto)
+         gcc_assert (e->flags & EDGE_EH);
+       if (!can_throw)
+         gcc_assert (!(e->flags & EDGE_EH));
        for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
          {
+           edge re;
+
+           /* There shouldn't be any PHI nodes in the ENTRY_BLOCK.  */
+           gcc_assert (!e->dest->aux);
+
            gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
                        (PHI_RESULT (phi)));
-           mark_sym_for_renaming
-             (SSA_NAME_VAR (PHI_RESULT (phi)));
+
+           if (!is_gimple_reg (PHI_RESULT (phi)))
+             {
+               mark_sym_for_renaming
+                 (SSA_NAME_VAR (PHI_RESULT (phi)));
+               continue;
+             }
+
+           re = find_edge (ret_bb, e->dest);
+           gcc_assert (re);
+           gcc_assert ((re->flags & (EDGE_EH | EDGE_ABNORMAL))
+                       == (e->flags & (EDGE_EH | EDGE_ABNORMAL)));
+
+           SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e),
+                    USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (phi, re)));
          }
       }
 }
@@ -967,7 +1108,7 @@ update_ssa_across_eh_edges (basic_block bb)
    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)
+copy_edges_for_bb (basic_block bb, int count_scale, basic_block ret_bb)
 {
   basic_block new_bb = (basic_block) bb->aux;
   edge_iterator ei;
@@ -999,6 +1140,7 @@ copy_edges_for_bb (basic_block bb, int count_scale)
   for (bsi = bsi_start (new_bb); !bsi_end_p (bsi);)
     {
       tree copy_stmt;
+      bool can_throw, nonlocal_goto;
 
       copy_stmt = bsi_stmt (bsi);
       update_stmt (copy_stmt);
@@ -1019,7 +1161,10 @@ copy_edges_for_bb (basic_block bb, int count_scale)
          into a COMPONENT_REF which doesn't.  If the copy
          can throw, the original could also throw.  */
 
-      if (tree_can_throw_internal (copy_stmt))
+      can_throw = tree_can_throw_internal (copy_stmt);
+      nonlocal_goto = tree_can_make_abnormal_goto (copy_stmt);
+
+      if (can_throw || nonlocal_goto)
        {
          if (!bsi_end_p (bsi))
            /* Note that bb's predecessor edges aren't necessarily
@@ -1031,12 +1176,18 @@ copy_edges_for_bb (basic_block bb, int count_scale)
              new_bb->aux = e->src->aux;
              bsi = bsi_start (new_bb);
            }
+       }
 
-           make_eh_edges (copy_stmt);
+      if (can_throw)
+       make_eh_edges (copy_stmt);
 
-          if (gimple_in_ssa_p (cfun))
-            update_ssa_across_eh_edges (bb_for_stmt (copy_stmt));
-       }
+      if (nonlocal_goto)
+       make_abnormal_goto_edges (bb_for_stmt (copy_stmt), true);
+
+      if ((can_throw || nonlocal_goto)
+         && gimple_in_ssa_p (cfun))
+       update_ssa_across_abnormal_edges (bb_for_stmt (copy_stmt), ret_bb,
+                                         can_throw, nonlocal_goto);
     }
 }
 
@@ -1072,6 +1223,17 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
 
              walk_tree (&new_arg, copy_body_r, id, NULL);
              gcc_assert (new_arg);
+             /* With return slot optimization we can end up with
+                non-gimple (foo *)&this->m, fix that here.  */
+             if (TREE_CODE (new_arg) != SSA_NAME
+                 && TREE_CODE (new_arg) != FUNCTION_DECL
+                 && !is_gimple_val (new_arg))
+               {
+                 tree stmts = NULL_TREE;
+                 new_arg = force_gimple_operand (new_arg, &stmts,
+                                                 true, NULL);
+                 bsi_insert_on_edge_immediate (new_edge, stmts);
+               }
              add_phi_arg (new_phi, new_arg, new_edge);
            }
        }
@@ -1115,7 +1277,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
   *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
   new_cfun->funcdef_no = get_next_funcdef_no ();
   VALUE_HISTOGRAMS (new_cfun) = NULL;
-  new_cfun->unexpanded_var_list = NULL;
+  new_cfun->local_decls = NULL;
   new_cfun->cfg = NULL;
   new_cfun->decl = new_fndecl /*= copy_node (callee_fndecl)*/;
   DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
@@ -1139,7 +1301,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
 
   if (src_cfun->gimple_df)
     {
-      init_tree_ssa ();
+      init_tree_ssa (cfun);
       cfun->gimple_df->in_ssa_p = true;
       init_ssa_operands ();
     }
@@ -1208,7 +1370,7 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   last = last_basic_block;
   /* 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);
+    copy_edges_for_bb (bb, count_scale, exit_block_map);
   if (gimple_in_ssa_p (cfun))
     FOR_ALL_BB_FN (bb, cfun_to_copy)
       copy_phis_for_bb (bb, id);
@@ -1230,7 +1392,7 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
 /* Make a copy of the body of FN so that it can be inserted inline in
    another function.  */
 
-static tree
+tree
 copy_generic_body (copy_body_data *id)
 {
   tree body;
@@ -1278,7 +1440,6 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 {
   tree init_stmt;
   tree var;
-  tree var_sub;
   tree rhs = value;
   tree def = (gimple_in_ssa_p (cfun)
              ? gimple_default_def (id->src_cfun, p) : NULL);
@@ -1286,7 +1447,16 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
   if (value
       && value != error_mark_node
       && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
-    rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
+    {
+      if (fold_convertible_p (TREE_TYPE (p), value))
+       rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
+      else
+       /* ???  For valid (GIMPLE) programs we should not end up here.
+          Still if something has gone wrong and we end up with truly
+          mismatched types here, fall back to using a VIEW_CONVERT_EXPR
+          to not leak invalid GIMPLE to the following passes.  */
+       rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value);
+    }
 
   /* If the parameter is never assigned to, has no SSA_NAMEs created,
      we may not need to create a new variable here at all.  Instead, we may
@@ -1325,23 +1495,10 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
       add_referenced_var (var);
     }
 
-  /* 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_sub);
+  insert_decl_map (id, p, var);
 
   /* Declare this new variable.  */
   TREE_CHAIN (var) = *vars;
@@ -1385,6 +1542,14 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
       return;
     }
 
+  /* If the value of argument is never used, don't care about initializing
+     it.  */
+  if (gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
+    {
+      gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
+      return;
+    }
+
   /* Initialize this VAR_DECL from the equivalent argument.  Convert
      the argument to the proper type in case it was promoted.  */
   if (value)
@@ -1393,7 +1558,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 
       if (rhs == error_mark_node)
        {
-         insert_decl_map (id, p, var_sub);
+         insert_decl_map (id, p, var);
          return;
        }
 
@@ -1560,6 +1725,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
        {
          var = return_slot;
          gcc_assert (TREE_CODE (var) != SSA_NAME);
+         TREE_ADDRESSABLE (var) |= TREE_ADDRESSABLE (result);
        }
       if ((TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
            || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
@@ -1631,9 +1797,9 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
     }
 
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
-  DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
+  DECL_STRUCT_FUNCTION (caller)->local_decls
     = tree_cons (NULL_TREE, var,
-                DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list);
+                DECL_STRUCT_FUNCTION (caller)->local_decls);
 
   /* Do not have the rest of GCC warn about this variable as it should
      not be visible to the user.  */
@@ -1717,7 +1883,6 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
            /* We cannot inline functions that take a variable number of
               arguments.  */
          case BUILT_IN_VA_START:
-         case BUILT_IN_STDARG_START:
          case BUILT_IN_NEXT_ARG:
          case BUILT_IN_VA_END:
            inline_forbidden_reason
@@ -1820,6 +1985,27 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
   return NULL_TREE;
 }
 
+static tree
+inline_forbidden_p_2 (tree *nodep, int *walk_subtrees,
+                     void *fnp)
+{
+  tree node = *nodep;
+  tree fn = (tree) fnp;
+
+  if (TREE_CODE (node) == LABEL_DECL && DECL_CONTEXT (node) == fn)
+    {
+      inline_forbidden_reason
+       = G_("function %q+F can never be inlined "
+            "because it saves address of local label in a static variable");
+      return node;
+    }
+
+  if (TYPE_P (node))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
 /* Return subexpression representing possible alloca call, if any.  */
 static tree
 inline_forbidden_p (tree fndecl)
@@ -1828,16 +2014,31 @@ inline_forbidden_p (tree fndecl)
   block_stmt_iterator bsi;
   basic_block bb;
   tree ret = NULL_TREE;
+  struct function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  tree step;
 
-  FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (fndecl))
+  FOR_EACH_BB_FN (bb, fun)
     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);
+                                           inline_forbidden_p_1, fndecl);
        if (ret)
          goto egress;
       }
 
+  for (step = fun->local_decls; step; step = TREE_CHAIN (step))
+    {
+      tree decl = TREE_VALUE (step);
+      if (TREE_CODE (decl) == VAR_DECL
+         && TREE_STATIC (decl)
+         && !DECL_EXTERNAL (decl)
+         && DECL_INITIAL (decl))
+       ret = walk_tree_without_duplicates (&DECL_INITIAL (decl),
+                                           inline_forbidden_p_2, fndecl);
+       if (ret)
+         goto egress;
+    }
+
 egress:
   input_location = saved_loc;
   return ret;
@@ -1936,20 +2137,6 @@ inlinable_function_p (tree fn)
   return inlinable;
 }
 
-/* Return true if we shall disregard inlining limits for the function
-   FN during inlining.  */
-
-bool
-disregard_inline_limits_p (tree fn)
-{
-  /* GNU extern inline functions are supposed to be cheap.  */
-  if (DECL_DECLARED_INLINE_P (fn)
-      && DECL_EXTERNAL (fn))
-    return true;
-
-  return lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) != NULL_TREE;
-}
-
 /* Estimate the cost of a memory move.  Use machine dependent
    word size and take possible memcpy call into account.  */
 
@@ -2018,8 +2205,8 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case COMPOUND_EXPR:
     case BIND_EXPR:
     case WITH_CLEANUP_EXPR:
-    case NOP_EXPR:
-    case CONVERT_EXPR:
+    case PAREN_EXPR:
+    CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
     case ADDR_EXPR:
@@ -2031,7 +2218,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case EH_FILTER_EXPR:
     case STATEMENT_LIST:
     case ERROR_MARK:
-    case NON_LVALUE_EXPR:
     case FDESC_EXPR:
     case VA_ARG_EXPR:
     case TRY_CATCH_EXPR:
@@ -2047,6 +2233,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case OMP_RETURN:
     case OMP_CONTINUE:
     case OMP_SECTIONS_SWITCH:
+    case OMP_ATOMIC_STORE:
       break;
 
     /* We don't account constants for now.  Assume that the cost is amortized
@@ -2060,6 +2247,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case COMPLEX_CST:
     case VECTOR_CST:
     case STRING_CST:
+    case PREDICT_EXPR:
       *walk_subtrees = 0;
       return NULL;
 
@@ -2204,9 +2392,12 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case SWITCH_EXPR:
-      /* TODO: Cost of a switch should be derived from the number of
-        branches.  */
-      d->count += d->weights->switch_cost;
+      /* Take into account cost of the switch + guess 2 conditional jumps for
+         each case label.  
+
+        TODO: once the switch expansion logic is sufficiently separated, we can
+        do better job on estimating cost of the switch.  */
+      d->count += TREE_VEC_LENGTH (SWITCH_LABELS (x)) * 2;
       break;
 
     /* Few special cases of expensive operations.  This is useful
@@ -2226,8 +2417,17 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case CALL_EXPR:
       {
        tree decl = get_callee_fndecl (x);
+       tree addr = CALL_EXPR_FN (x);
+       tree funtype = TREE_TYPE (addr);
+
+       gcc_assert (POINTER_TYPE_P (funtype));
+       funtype = TREE_TYPE (funtype);
 
-       cost = d->weights->call_cost;
+       if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
+         cost = d->weights->target_builtin_call_cost;
+       else
+         cost = d->weights->call_cost;
+       
        if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
          switch (DECL_FUNCTION_CODE (decl))
            {
@@ -2244,21 +2444,34 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
              break;
            }
 
+       if (decl)
+         funtype = TREE_TYPE (decl);
+
        /* 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)
+          that does use function declaration to figure out the arguments. 
+
+          When we deal with function with no body nor prototype, base estimates on
+          actual parameters of the call expression.  Otherwise use either the actual
+          arguments types or function declaration for more precise answer.  */
+       if (decl && DECL_ARGUMENTS (decl))
+         {
+           tree arg;
+           for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
+             d->count += estimate_move_cost (TREE_TYPE (arg));
+         }
+       else if (funtype && prototype_p (funtype))
+         {
+           tree t;
+           for (t = TYPE_ARG_TYPES (funtype); t; t = TREE_CHAIN (t))
+             d->count += estimate_move_cost (TREE_VALUE (t));
+         }
+       else
          {
            tree a;
            call_expr_arg_iterator iter;
            FOR_EACH_CALL_EXPR_ARG (a, iter, x)
              d->count += estimate_move_cost (TREE_TYPE (a));
          }
-       else
-         {
-           tree arg;
-           for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
-             d->count += estimate_move_cost (TREE_TYPE (arg));
-         }
 
        d->count += cost;
        break;
@@ -2273,6 +2486,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case OMP_ORDERED:
     case OMP_CRITICAL:
     case OMP_ATOMIC:
+    case OMP_ATOMIC_LOAD:
       /* OpenMP directives are generally very expensive.  */
       d->count += d->weights->omp_cost;
       break;
@@ -2328,13 +2542,13 @@ void
 init_inline_once (void)
 {
   eni_inlining_weights.call_cost = PARAM_VALUE (PARAM_INLINE_CALL_COST);
+  eni_inlining_weights.target_builtin_call_cost = 1;
   eni_inlining_weights.div_mod_cost = 10;
-  eni_inlining_weights.switch_cost = 1;
   eni_inlining_weights.omp_cost = 40;
 
   eni_size_weights.call_cost = 1;
+  eni_size_weights.target_builtin_call_cost = 1;
   eni_size_weights.div_mod_cost = 1;
-  eni_size_weights.switch_cost = 10;
   eni_size_weights.omp_cost = 40;
 
   /* Estimating time for call is difficult, since we have no idea what the
@@ -2342,32 +2556,11 @@ init_inline_once (void)
      underestimating the cost does less harm than overestimating it, so
      we choose a rather small value here.  */
   eni_time_weights.call_cost = 10;
+  eni_time_weights.target_builtin_call_cost = 10;
   eni_time_weights.div_mod_cost = 10;
-  eni_time_weights.switch_cost = 4;
   eni_time_weights.omp_cost = 40;
 }
 
-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)
@@ -2377,7 +2570,7 @@ add_lexical_block (tree current_block, tree new_block)
   /* Walk to the last sub-block.  */
   for (blk_p = &BLOCK_SUBBLOCKS (current_block);
        *blk_p;
-       blk_p = &TREE_CHAIN (*blk_p))
+       blk_p = &BLOCK_CHAIN (*blk_p))
     ;
   *blk_p = new_block;
   BLOCK_SUPERCONTEXT (new_block) = current_block;
@@ -2390,7 +2583,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
 {
   copy_body_data *id;
   tree t;
-  tree use_retvar;
+  tree retvar, use_retvar;
   tree fn;
   struct pointer_map_t *st;
   tree return_slot;
@@ -2553,7 +2746,11 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   id->src_fn = fn;
   id->src_node = cg_edge->callee;
   id->src_cfun = DECL_STRUCT_FUNCTION (fn);
+  id->call_expr = t;
 
+  gcc_assert (!id->src_cfun->after_inlining);
+
+  id->entry_bb = bb;
   initialize_inlined_parameters (id, t, fn, bb);
 
   if (DECL_INITIAL (fn))
@@ -2588,9 +2785,27 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   else
     modify_dest = NULL;
 
+  /* If we are inlining a call to the C++ operator new, we don't want
+     to use type based alias analysis on the return value.  Otherwise
+     we may get confused if the compiler sees that the inlined new
+     function returns a pointer which was just deleted.  See bug
+     33407.  */
+  if (DECL_IS_OPERATOR_NEW (fn))
+    {
+      return_slot = NULL;
+      modify_dest = NULL;
+    }
+
   /* Declare the return variable for the function.  */
-  declare_return_variable (id, return_slot,
-                          modify_dest, &use_retvar);
+  retvar = declare_return_variable (id, return_slot,
+                                   modify_dest, &use_retvar);
+
+  if (DECL_IS_OPERATOR_NEW (fn))
+    {
+      gcc_assert (TREE_CODE (retvar) == VAR_DECL
+                 && POINTER_TYPE_P (TREE_TYPE (retvar)));
+      DECL_NO_TBAA_P (retvar) = 1;
+    }
 
   /* This is it.  Duplicate the callee body.  Assume callee is
      pre-gimplified.  Note that we must not alter the caller
@@ -2600,16 +2815,16 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   copy_body (id, bb->count, bb->frequency, bb, return_block);
 
   /* Add local vars in this inlined callee to caller.  */
-  t_step = id->src_cfun->unexpanded_var_list;
+  t_step = id->src_cfun->local_decls;
   for (; t_step; t_step = TREE_CHAIN (t_step))
     {
       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);
+       cfun->local_decls = tree_cons (NULL_TREE, var,
+                                              cfun->local_decls);
       else
-       cfun->unexpanded_var_list = tree_cons (NULL_TREE, remap_decl (var, id),
-                                              cfun->unexpanded_var_list);
+       cfun->local_decls = tree_cons (NULL_TREE, remap_decl (var, id),
+                                              cfun->local_decls);
     }
 
   /* Clean up.  */
@@ -2637,15 +2852,15 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
       if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
          && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME)
        {
-         tree name = TREE_OPERAND (stmt, 0);
-         tree var = SSA_NAME_VAR (TREE_OPERAND (stmt, 0));
+         tree name = GIMPLE_STMT_OPERAND (stmt, 0);
+         tree var = SSA_NAME_VAR (GIMPLE_STMT_OPERAND (stmt, 0));
          tree def = gimple_default_def (cfun, var);
 
          /* If the variable is used undefined, make this name undefined via
             move.  */
          if (def)
            {
-             TREE_OPERAND (stmt, 1) = def;
+             GIMPLE_STMT_OPERAND (stmt, 1) = def;
              update_stmt (stmt);
            }
          /* Otherwise make this variable undefined.  */
@@ -2728,11 +2943,17 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
          if (pointer_set_contains (statements, bsi_stmt (bsi)))
            {
              tree old_stmt = bsi_stmt (bsi);
+             tree old_call = get_call_expr_in (old_stmt);
+
              if (fold_stmt (bsi_stmt_ptr (bsi)))
                {
                  update_stmt (bsi_stmt (bsi));
-                 if (maybe_clean_or_replace_eh_stmt (old_stmt, bsi_stmt (bsi)))
-                    tree_purge_dead_eh_edges (BASIC_BLOCK (first));
+                 if (old_call)
+                   cgraph_update_edges_for_call_stmt (old_stmt, old_call,
+                                                      bsi_stmt (bsi));
+                 if (maybe_clean_or_replace_eh_stmt (old_stmt,
+                                                     bsi_stmt (bsi)))
+                   tree_purge_dead_eh_edges (BASIC_BLOCK (first));
                }
            }
       }
@@ -2753,60 +2974,6 @@ has_abnormal_outgoing_edge_p (basic_block bb)
   return false;
 }
 
-/* When a block from the inlined function contains a call with side-effects
-   in the middle gets inlined in a function with non-locals labels, the call
-   becomes a potential non-local goto so we need to add appropriate edge.  */
-
-static void
-make_nonlocal_label_edges (void)
-{
-  block_stmt_iterator bsi;
-  basic_block bb;
-
-  FOR_EACH_BB (bb)
-    {
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       {
-         tree stmt = bsi_stmt (bsi);
-         if (tree_can_make_abnormal_goto (stmt))
-           {
-             if (stmt == bsi_stmt (bsi_last (bb)))
-               {
-                 if (!has_abnormal_outgoing_edge_p (bb))
-                   make_abnormal_goto_edges (bb, true);
-               }
-             else
-               {
-                 edge e = split_block (bb, stmt);
-                 bb = e->src;
-                 make_abnormal_goto_edges (bb, true);
-               }
-             break;
-           }
-
-         /* Update PHIs on nonlocal goto receivers we (possibly)
-            just created new edges into.  */
-         if (TREE_CODE (stmt) == LABEL_EXPR
-             && gimple_in_ssa_p (cfun))
-           {
-             tree target = LABEL_EXPR_LABEL (stmt);
-             if (DECL_NONLOCAL (target))
-               {
-                 tree phi;
-
-                 for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-                   {
-                     gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
-                                 (PHI_RESULT (phi)));
-                     mark_sym_for_renaming
-                       (SSA_NAME_VAR (PHI_RESULT (phi)));
-                   }
-               }
-           }
-       }
-    }
-}
-
 /* Expand calls to inline functions in the body of FN.  */
 
 unsigned int
@@ -2839,7 +3006,7 @@ optimize_inline_calls (tree fn)
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
   id.transform_new_cfg = false;
   id.transform_return_to_modify = true;
-  id.transform_lang_insert_block = false;
+  id.transform_lang_insert_block = NULL;
   id.statements_to_fold = pointer_set_create ();
 
   push_gimplify_context ();
@@ -2885,8 +3052,6 @@ optimize_inline_calls (tree fn)
   cgraph_node_remove_callees (id.dst_node);
 
   fold_cond_expr_cond ();
-  if (current_function_has_nonlocal_label)
-    make_nonlocal_label_edges ();
   /* It would be nice to check SSA/CFG/statement consistency here, but it is
      not possible yet - the IPA passes might make various functions to not
      throw and they don't care to proactively update local EH info.  This is
@@ -2896,36 +3061,6 @@ optimize_inline_calls (tree fn)
          | (profile_status != PROFILE_ABSENT ? TODO_rebuild_frequencies : 0));
 }
 
-/* FN is a function that has a complete body, and CLONE is a function whose
-   body is to be set to a copy of FN, mapping argument declarations according
-   to the ARG_MAP splay_tree.  */
-
-void
-clone_body (tree clone, tree fn, void *arg_map)
-{
-  copy_body_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.  */
-  memset (&id, 0, sizeof (id));
-  id.src_fn = fn;
-  id.dst_fn = clone;
-  id.src_cfun = DECL_STRUCT_FUNCTION (fn);
-  id.decl_map = (struct pointer_map_t *)arg_map;
-
-  id.copy_decl = copy_decl_no_change;
-  id.transform_call_graph_edges = CB_CGE_DUPLICATE;
-  id.transform_new_cfg = true;
-  id.transform_return_to_modify = false;
-  id.transform_lang_insert_block = true;
-
-  /* We're not inside any EH region.  */
-  id.eh_region = -1;
-
-  /* Actually copy the body.  */
-  append_to_statement_list_force (copy_generic_body (&id), &DECL_SAVED_TREE (clone));
-}
-
 /* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
 
 tree
@@ -3146,7 +3281,7 @@ unsave_expr_now (tree expr)
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
   id.transform_new_cfg = false;
   id.transform_return_to_modify = false;
-  id.transform_lang_insert_block = false;
+  id.transform_lang_insert_block = NULL;
 
   /* Walk the tree once to find local labels.  */
   walk_tree_without_duplicates (&expr, mark_local_for_remap_r, &id);
@@ -3189,9 +3324,7 @@ declare_inline_vars (tree block, tree vars)
     {
       DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
       gcc_assert (!TREE_STATIC (t) && !TREE_ASM_WRITTEN (t));
-      cfun->unexpanded_var_list =
-       tree_cons (NULL_TREE, t,
-                  cfun->unexpanded_var_list);
+      cfun->local_decls = tree_cons (NULL_TREE, t, cfun->local_decls);
     }
 
   if (block)
@@ -3292,7 +3425,7 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
 }
 
 
-static tree
+tree
 copy_decl_no_change (tree decl, copy_body_data *id)
 {
   tree copy;
@@ -3428,7 +3561,7 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
     = update_clones ? CB_CGE_MOVE_CLONES : CB_CGE_MOVE;
   id.transform_new_cfg = true;
   id.transform_return_to_modify = false;
-  id.transform_lang_insert_block = false;
+  id.transform_lang_insert_block = NULL;
 
   current_function_decl = new_decl;
   old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
@@ -3464,19 +3597,18 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map,
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (id.dst_fn);
   
-  if (DECL_STRUCT_FUNCTION (old_decl)->unexpanded_var_list != NULL_TREE)
+  if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
     /* Add local vars.  */
-    for (t_step = DECL_STRUCT_FUNCTION (old_decl)->unexpanded_var_list;
+    for (t_step = DECL_STRUCT_FUNCTION (old_decl)->local_decls;
         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);
+         cfun->local_decls = tree_cons (NULL_TREE, var, cfun->local_decls);
        else
-         cfun->unexpanded_var_list =
+         cfun->local_decls =
            tree_cons (NULL_TREE, remap_decl (var, &id),
-                      cfun->unexpanded_var_list);
+                      cfun->local_decls);
       }
   
   /* Copy the Function's body.  */
@@ -3535,10 +3667,13 @@ build_duplicate_type (tree type)
   id.dst_fn = current_function_decl;
   id.src_cfun = cfun;
   id.decl_map = pointer_map_create ();
+  id.copy_decl = copy_decl_no_change;
 
   type = remap_type_1 (type, &id);
 
   pointer_map_destroy (id.decl_map);
 
+  TYPE_CANONICAL (type) = type;
+
   return type;
 }