OSDN Git Service

* cgraph.c (cgraph_create_node): Set node frequency to normal.
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index fbd973b..0c1293e 100644 (file)
@@ -1,5 +1,5 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
@@ -41,7 +41,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "function.h"
-#include "ggc.h"
 #include "tree-flow.h"
 #include "diagnostic.h"
 #include "except.h"
@@ -64,7 +63,7 @@ along with GCC; see the file COPYING3.  If not see
    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.
+   statements and RESX statements are adjusted accordingly.
 
    Cloning: (only in C++) We have one body for a con/de/structor, and
    multiple function decls, each with a unique parameter list.
@@ -118,7 +117,7 @@ eni_weights eni_time_weights;
 
 /* Prototypes.  */
 
-static tree declare_return_variable (copy_body_data *, tree, tree, tree *);
+static tree declare_return_variable (copy_body_data *, tree, tree);
 static void remap_block (tree *, copy_body_data *);
 static void copy_bind_expr (tree *, int *, copy_body_data *);
 static tree mark_local_for_remap_r (tree *, int *, void *);
@@ -171,6 +170,12 @@ insert_debug_decl_map (copy_body_data *id, tree key, tree value)
   *pointer_map_insert (id->debug_map, key) = value;
 }
 
+/* If nonzero, we're remapping the contents of inlined debug
+   statements.  If negative, an error has occurred, such as a
+   reference to a variable that isn't available in the inlined
+   context.  */
+static int processing_debug_stmt = 0;
+
 /* Construct new SSA name for old NAME. ID is the inline context.  */
 
 static tree
@@ -185,12 +190,18 @@ remap_ssa_name (tree name, copy_body_data *id)
   if (n)
     return unshare_expr (*n);
 
+  if (processing_debug_stmt)
+    {
+      processing_debug_stmt = -1;
+      return name;
+    }
+
   /* Do not set DEF_STMT yet as statement is not copied yet. We do that
      in copy_bb.  */
   new_tree = remap_decl (SSA_NAME_VAR (name), id);
 
   /* We might've substituted constant or another SSA_NAME for
-     the variable. 
+     the variable.
 
      Replace the SSA name representing RESULT_DECL by variable during
      inlining:  this saves us from need to introduce PHI node in a case
@@ -199,11 +210,21 @@ remap_ssa_name (tree name, copy_body_data *id)
       && (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
          || !id->transform_return_to_modify))
     {
+      struct ptr_info_def *pi;
       new_tree = make_ssa_name (new_tree, NULL);
       insert_decl_map (id, name, new_tree);
       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_tree)
        = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
       TREE_TYPE (new_tree) = TREE_TYPE (SSA_NAME_VAR (new_tree));
+      /* At least IPA points-to info can be directly transferred.  */
+      if (id->src_cfun->gimple_df
+         && id->src_cfun->gimple_df->ipa_pta
+         && (pi = SSA_NAME_PTR_INFO (name))
+         && !pi->pt.anything)
+       {
+         struct ptr_info_def *new_pi = get_ptr_info (new_tree);
+         new_pi->pt = pi->pt;
+       }
       if (gimple_nop_p (SSA_NAME_DEF_STMT (name)))
        {
          /* By inlining function having uninitialized variable, we might
@@ -223,7 +244,7 @@ remap_ssa_name (tree name, copy_body_data *id)
            {
              gimple_stmt_iterator gsi = gsi_last_bb (id->entry_bb);
              gimple init_stmt;
-             
+
              init_stmt = gimple_build_assign (new_tree,
                                               fold_convert (TREE_TYPE (new_tree),
                                                            integer_zero_node));
@@ -244,22 +265,14 @@ remap_ssa_name (tree name, copy_body_data *id)
   return new_tree;
 }
 
-/* If nonzero, we're remapping the contents of inlined debug
-   statements.  If negative, an error has occurred, such as a
-   reference to a variable that isn't available in the inlined
-   context.  */
-int processing_debug_stmt = 0;
-
 /* Remap DECL during the copying of the BLOCK tree for the function.  */
 
 tree
 remap_decl (tree decl, copy_body_data *id)
 {
   tree *n;
-  tree fn;
 
   /* We only remap local variables in the current function.  */
-  fn = id->src_fn;
 
   /* See if we have remapped this declaration.  */
 
@@ -277,7 +290,7 @@ remap_decl (tree decl, copy_body_data *id)
     {
       /* Make a copy of the variable or label.  */
       tree t = id->copy_decl (decl, id);
-     
+
       /* 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.  */
@@ -307,17 +320,7 @@ remap_decl (tree decl, copy_body_data *id)
          && (TREE_CODE (t) == VAR_DECL
              || TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
        {
-          tree def = gimple_default_def (id->src_cfun, decl);
          get_var_ann (t);
-         if (TREE_CODE (decl) != PARM_DECL && def)
-           {
-             tree map = remap_ssa_name (def, id);
-             /* Watch out RESULT_DECLs whose SSA names map directly
-                to them.  */
-             if (TREE_CODE (map) == SSA_NAME
-                 && gimple_nop_p (SSA_NAME_DEF_STMT (map)))
-               set_default_def (t, map);
-           }
          add_referenced_var (t);
        }
       return t;
@@ -342,6 +345,10 @@ remap_type_1 (tree type, copy_body_data *id)
       new_tree = build_pointer_type_for_mode (remap_type (TREE_TYPE (type), id),
                                         TYPE_MODE (type),
                                         TYPE_REF_CAN_ALIAS_ALL (type));
+      if (TYPE_ATTRIBUTES (type) || TYPE_QUALS (type))
+       new_tree = build_type_attribute_qual_variant (new_tree,
+                                                     TYPE_ATTRIBUTES (type),
+                                                     TYPE_QUALS (type));
       insert_decl_map (id, type, new_tree);
       return new_tree;
     }
@@ -350,6 +357,10 @@ remap_type_1 (tree type, copy_body_data *id)
       new_tree = build_reference_type_for_mode (remap_type (TREE_TYPE (type), id),
                                            TYPE_MODE (type),
                                            TYPE_REF_CAN_ALIAS_ALL (type));
+      if (TYPE_ATTRIBUTES (type) || TYPE_QUALS (type))
+       new_tree = build_type_attribute_qual_variant (new_tree,
+                                                     TYPE_ATTRIBUTES (type),
+                                                     TYPE_QUALS (type));
       insert_decl_map (id, type, new_tree);
       return new_tree;
     }
@@ -485,7 +496,7 @@ remapped_type (tree type, copy_body_data *id)
 
   /* The type only needs remapping if it's variably modified.  */
 /* Decide if DECL can be put into BLOCK_NONLOCAL_VARs.  */
-  
+
 static bool
 can_be_nonlocal (tree decl, copy_body_data *id)
 {
@@ -531,18 +542,18 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
   for (old_var = decls; old_var; old_var = TREE_CHAIN (old_var))
     {
       tree new_var;
-      tree origin_var = DECL_ORIGIN (old_var);
 
       if (can_be_nonlocal (old_var, id))
        {
          if (TREE_CODE (old_var) == VAR_DECL
+             && ! DECL_EXTERNAL (old_var)
              && (var_ann (old_var) || !gimple_in_ssa_p (cfun)))
            cfun->local_decls = tree_cons (NULL_TREE, old_var,
                                                   cfun->local_decls);
          if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
              && !DECL_IGNORED_P (old_var)
              && nonlocalized_list)
-           VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
+           VEC_safe_push (tree, gc, *nonlocalized_list, old_var);
          continue;
        }
 
@@ -552,7 +563,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
       /* If we didn't remap this variable, we can't mess with its
         TREE_CHAIN.  If we remapped this variable to the return slot, it's
         already declared somewhere else, so don't declare it here.  */
-      
+
       if (new_var == id->retvar)
        ;
       else if (!new_var)
@@ -560,7 +571,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
          if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
              && !DECL_IGNORED_P (old_var)
              && nonlocalized_list)
-           VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
+           VEC_safe_push (tree, gc, *nonlocalized_list, old_var);
        }
       else
        {
@@ -581,7 +592,6 @@ remap_block (tree *block, copy_body_data *id)
 {
   tree old_block;
   tree new_block;
-  tree fn;
 
   /* Make the new block.  */
   old_block = *block;
@@ -598,8 +608,6 @@ remap_block (tree *block, copy_body_data *id)
                                        &BLOCK_NONLOCALIZED_VARS (new_block),
                                        id);
 
-  fn = id->dst_fn;
-
   if (id->transform_lang_insert_block)
     id->transform_lang_insert_block (new_block);
 
@@ -1086,13 +1094,13 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
          && id->remapping_type_depth == 0
          && !processing_debug_stmt)
        add_referenced_var (*tp);
-       
+
       /* 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.  */
+        of function call if we are not remapping a type.  */
       if (EXPR_P (*tp))
        {
-         new_block = id->block;
+         new_block = id->remapping_type_depth == 0 ? id->block : NULL;
          if (TREE_BLOCK (*tp))
            {
              tree *n;
@@ -1104,12 +1112,6 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
          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)));
-
       if (TREE_CODE (*tp) != OMP_CLAUSE)
        TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);
 
@@ -1149,6 +1151,35 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
+/* Helper for remap_gimple_stmt.  Given an EH region number for the
+   source function, map that to the duplicate EH region number in
+   the destination function.  */
+
+static int
+remap_eh_region_nr (int old_nr, copy_body_data *id)
+{
+  eh_region old_r, new_r;
+  void **slot;
+
+  old_r = get_eh_region_from_number_fn (id->src_cfun, old_nr);
+  slot = pointer_map_contains (id->eh_map, old_r);
+  new_r = (eh_region) *slot;
+
+  return new_r->index;
+}
+
+/* Similar, but operate on INTEGER_CSTs.  */
+
+static tree
+remap_eh_region_tree_nr (tree old_t_nr, copy_body_data *id)
+{
+  int old_nr, new_nr;
+
+  old_nr = tree_low_cst (old_t_nr, 0);
+  new_nr = remap_eh_region_nr (old_nr, id);
+
+  return build_int_cst (NULL, new_nr);
+}
 
 /* Helper for copy_bb.  Remap statement STMT using the inlining
    information in ID.  Return the new statement copy.  */
@@ -1215,7 +1246,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
        case GIMPLE_TRY:
          s1 = remap_gimple_seq (gimple_try_eval (stmt), id);
          s2 = remap_gimple_seq (gimple_try_cleanup (stmt), id);
-         copy = gimple_build_try (s1, s2, gimple_try_kind (stmt)); 
+         copy = gimple_build_try (s1, s2, gimple_try_kind (stmt));
          break;
 
        case GIMPLE_WITH_CLEANUP_EXPR:
@@ -1338,9 +1369,65 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
          VEC_safe_push (gimple, heap, id->debug_stmts, copy);
          return copy;
        }
-      else
-       /* Create a new deep copy of the statement.  */
-       copy = gimple_copy (stmt);
+
+      /* Create a new deep copy of the statement.  */
+      copy = gimple_copy (stmt);
+
+      /* Remap the region numbers for __builtin_eh_{pointer,filter},
+        RESX and EH_DISPATCH.  */
+      if (id->eh_map)
+       switch (gimple_code (copy))
+         {
+         case GIMPLE_CALL:
+           {
+             tree r, fndecl = gimple_call_fndecl (copy);
+             if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+               switch (DECL_FUNCTION_CODE (fndecl))
+                 {
+                 case BUILT_IN_EH_COPY_VALUES:
+                   r = gimple_call_arg (copy, 1);
+                   r = remap_eh_region_tree_nr (r, id);
+                   gimple_call_set_arg (copy, 1, r);
+                   /* FALLTHRU */
+
+                 case BUILT_IN_EH_POINTER:
+                 case BUILT_IN_EH_FILTER:
+                   r = gimple_call_arg (copy, 0);
+                   r = remap_eh_region_tree_nr (r, id);
+                   gimple_call_set_arg (copy, 0, r);
+                   break;
+
+                 default:
+                   break;
+                 }
+
+             /* Reset alias info if we didn't apply measures to
+                keep it valid over inlining by setting DECL_PT_UID.  */
+             if (!id->src_cfun->gimple_df
+                 || !id->src_cfun->gimple_df->ipa_pta)
+               gimple_call_reset_alias_info (copy);
+           }
+           break;
+
+         case GIMPLE_RESX:
+           {
+             int r = gimple_resx_region (copy);
+             r = remap_eh_region_nr (r, id);
+             gimple_resx_set_region (copy, r);
+           }
+           break;
+
+         case GIMPLE_EH_DISPATCH:
+           {
+             int r = gimple_eh_dispatch_region (copy);
+             r = remap_eh_region_nr (r, id);
+             gimple_eh_dispatch_set_region (copy, r);
+           }
+           break;
+
+         default:
+           break;
+         }
     }
 
   /* If STMT has a block defined, map it to the newly constructed
@@ -1366,7 +1453,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
   if (skip_first)
     walk_tree (gimple_op_ptr (copy, 1), remap_gimple_op_r, &wi, NULL);
   else
-    walk_gimple_op (copy, remap_gimple_op_r, &wi); 
+    walk_gimple_op (copy, remap_gimple_op_r, &wi);
 
   /* Clear the copied virtual operands.  We are not remapping them here
      but are going to recreate them from scratch.  */
@@ -1376,12 +1463,6 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
       gimple_set_vuse (copy, NULL_TREE);
     }
 
-  /* We have to handle EH region remapping of GIMPLE_RESX specially because
-     the region number is not an operand.  */
-  if (gimple_code (stmt) == GIMPLE_RESX && id->eh_region_offset)
-    {
-      gimple_resx_set_region (copy, gimple_resx_region (stmt) + id->eh_region_offset);
-    }
   return copy;
 }
 
@@ -1396,6 +1477,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
   gimple_stmt_iterator gsi, copy_gsi, seq_gsi;
   basic_block copy_basic_block;
   tree decl;
+  gcov_type freq;
 
   /* create_basic_block() will append every new block to
      basic_block_info automatically.  */
@@ -1405,11 +1487,12 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
 
   /* We are going to rebuild frequencies from scratch.  These values
      have just small importance to drive canonicalize_loop_headers.  */
-  copy_basic_block->frequency = ((gcov_type)bb->frequency
-                                * frequency_scale / REG_BR_PROB_BASE);
+  freq = ((gcov_type)bb->frequency * frequency_scale / REG_BR_PROB_BASE);
 
-  if (copy_basic_block->frequency > BB_FREQ_MAX)
-    copy_basic_block->frequency = BB_FREQ_MAX;
+  /* We recompute frequencies after inlining, so this is quite safe.  */
+  if (freq > BB_FREQ_MAX)
+    freq = BB_FREQ_MAX;
+  copy_basic_block->frequency = freq;
 
   copy_gsi = gsi_start_bb (copy_basic_block);
 
@@ -1555,9 +1638,35 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                case CB_CGE_DUPLICATE:
                  edge = cgraph_edge (id->src_node, orig_stmt);
                  if (edge)
-                   edge = cgraph_clone_edge (edge, id->dst_node, stmt,
-                                             REG_BR_PROB_BASE, 1,
-                                             edge->frequency, true);
+                   {
+                     int edge_freq = edge->frequency;
+                     edge = cgraph_clone_edge (edge, id->dst_node, stmt,
+                                               gimple_uid (stmt),
+                                               REG_BR_PROB_BASE, CGRAPH_FREQ_BASE,
+                                               edge->frequency, true);
+                     /* We could also just rescale the frequency, but
+                        doing so would introduce roundoff errors and make
+                        verifier unhappy.  */
+                     edge->frequency
+                       = compute_call_stmt_bb_frequency (id->dst_node->decl,
+                                                         copy_basic_block);
+                     if (dump_file
+                         && profile_status_for_function (cfun) != PROFILE_ABSENT
+                         && (edge_freq > edge->frequency + 10
+                             || edge_freq < edge->frequency - 10))
+                       {
+                         fprintf (dump_file, "Edge frequency estimated by "
+                                  "cgraph %i diverge from inliner's estimate %i\n",
+                                  edge_freq,
+                                  edge->frequency);
+                         fprintf (dump_file,
+                                  "Orig bb: %i, orig bb freq %i, new bb freq %i\n",
+                                  bb->index,
+                                  bb->frequency,
+                                  copy_basic_block->frequency);
+                       }
+                     stmt = cgraph_redirect_edge_call_stmt_to_callee (edge);
+                   }
                  break;
 
                case CB_CGE_MOVE_CLONES:
@@ -1578,7 +1687,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
 
              /* Constant propagation on argument done during inlining
                 may create new direct call.  Produce an edge for it.  */
-             if ((!edge 
+             if ((!edge
                   || (edge->indirect_call
                       && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
                  && is_gimple_call (stmt)
@@ -1588,18 +1697,23 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
 
                  /* We have missing edge in the callgraph.  This can happen
                     when previous inlining turned an indirect call into a
-                    direct call by constant propagating arguments.  In all
+                    direct call by constant propagating arguments or we are
+                    producing dead clone (for further clonning).  In all
                     other cases we hit a bug (incorrect node sharing is the
                     most common reason for missing edges).  */
-                 gcc_assert (dest->needed || !dest->analyzed);
+                 gcc_assert (dest->needed || !dest->analyzed
+                             || !id->src_node->analyzed);
                  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)
                    cgraph_create_edge_including_clones
-                     (id->dst_node, dest, stmt, bb->count,
-                      compute_call_stmt_bb_frequency (id->dst_node->decl, bb),
+                     (id->dst_node, dest, orig_stmt, stmt, bb->count,
+                      compute_call_stmt_bb_frequency (id->dst_node->decl,
+                                                      copy_basic_block),
                       bb->loop_depth, CIF_ORIGINALLY_INDIRECT_CALL);
                  else
                    cgraph_create_edge (id->dst_node, dest, stmt,
-                                       bb->count, CGRAPH_FREQ_BASE,
+                                       bb->count,
+                                       compute_call_stmt_bb_frequency
+                                         (id->dst_node->decl, copy_basic_block),
                                        bb->loop_depth)->inline_failed
                      = CIF_ORIGINALLY_INDIRECT_CALL;
                  if (dump_file)
@@ -1616,43 +1730,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                cfun->calls_setjmp = true;
            }
 
-         /* If you think we can abort here, you are wrong.
-            There is no region 0 in gimple.  */
-         gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) != 0);
-
-         if (stmt_could_throw_p (stmt)
-             /* When we are cloning for inlining, we are supposed to
-                construct a clone that calls precisely the same functions
-                as original.  However IPA optimizers might've proved
-                earlier some function calls as non-trapping that might
-                render some basic blocks dead that might become
-                unreachable.
-
-                We can't update SSA with unreachable blocks in CFG and thus
-                we prevent the scenario by preserving even the "dead" eh
-                edges until the point they are later removed by
-                fixup_cfg pass.  */
-             || (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
-                 && lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) > 0))
-           {
-             int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
-
-             /* Add an entry for the copied tree in the EH hashtable.
-                When 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->src_cfun, orig_stmt) <= 0
-                 && id->eh_region > 0
-                 && stmt_could_throw_p (stmt))
-               add_stmt_to_eh_region (stmt, id->eh_region);
-           }
+         maybe_duplicate_eh_stmt_fn (cfun, stmt, id->src_cfun, orig_stmt,
+                                     id->eh_map, id->eh_lp_nr);
 
          if (gimple_in_ssa_p (cfun) && !is_gimple_debug (stmt))
            {
@@ -1821,7 +1900,9 @@ copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb)
            }
        }
 
-      if (can_throw)
+      if (gimple_code (copy_stmt) == GIMPLE_EH_DISPATCH)
+       make_eh_dispatch_edges (copy_stmt);
+      else if (can_throw)
        make_eh_edges (copy_stmt);
 
       if (nonlocal_goto)
@@ -1882,7 +1963,7 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
                  new_arg = force_gimple_operand (new_arg, &stmts, true, NULL);
                  gsi_insert_seq_on_edge_immediate (new_edge, stmts);
                }
-             add_phi_arg (new_phi, new_arg, new_edge, 
+             add_phi_arg (new_phi, new_arg, new_edge,
                           gimple_phi_arg_location_from_edge (phi, old_edge));
            }
        }
@@ -1902,24 +1983,16 @@ remap_decl_1 (tree decl, void *data)
    NEW_FNDECL to be build.  CALLEE_FNDECL is the original */
 
 static void
-initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
-                int frequency)
+initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count)
 {
   struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
-  gcov_type count_scale, frequency_scale;
+  gcov_type count_scale;
 
   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
     count_scale = (REG_BR_PROB_BASE * count
                   / ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count);
   else
-    count_scale = 1;
-
-  if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency)
-    frequency_scale = (REG_BR_PROB_BASE * frequency
-                      /
-                      ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency);
-  else
-    frequency_scale = count_scale;
+    count_scale = REG_BR_PROB_BASE;
 
   /* Register specific tree functions.  */
   gimple_register_cfg_hooks ();
@@ -1939,12 +2012,8 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
   cfun->function_end_locus = src_cfun->function_end_locus;
   cfun->curr_properties = src_cfun->curr_properties;
   cfun->last_verified = src_cfun->last_verified;
-  if (src_cfun->ipa_transforms_to_apply)
-    cfun->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
-                                             src_cfun->ipa_transforms_to_apply);
   cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
   cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
-  cfun->function_frequency = src_cfun->function_frequency;
   cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
   cfun->stdarg = src_cfun->stdarg;
   cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p;
@@ -1955,18 +2024,17 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
 
   init_empty_tree_cfg ();
 
+  profile_status_for_function (cfun) = profile_status_for_function (src_cfun);
   ENTRY_BLOCK_PTR->count =
     (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
      REG_BR_PROB_BASE);
-  ENTRY_BLOCK_PTR->frequency =
-    (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
-     frequency_scale / REG_BR_PROB_BASE);
+  ENTRY_BLOCK_PTR->frequency
+    = ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency;
   EXIT_BLOCK_PTR->count =
     (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
      REG_BR_PROB_BASE);
   EXIT_BLOCK_PTR->frequency =
-    (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
-     frequency_scale / REG_BR_PROB_BASE);
+    EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency;
   if (src_cfun->eh)
     init_eh_for_function ();
 
@@ -1983,7 +2051,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
    another function.  Walks FN via CFG, returns new fndecl.  */
 
 static tree
-copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
+copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
               basic_block entry_block_map, basic_block exit_block_map)
 {
   tree callee_fndecl = id->src_fn;
@@ -1992,21 +2060,14 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   struct function *cfun_to_copy;
   basic_block bb;
   tree new_fndecl = NULL;
-  gcov_type count_scale, frequency_scale;
+  gcov_type count_scale;
   int last;
 
   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
     count_scale = (REG_BR_PROB_BASE * count
                   / ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count);
   else
-    count_scale = 1;
-
-  if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency)
-    frequency_scale = (REG_BR_PROB_BASE * frequency
-                      /
-                      ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency);
-  else
-    frequency_scale = count_scale;
+    count_scale = REG_BR_PROB_BASE;
 
   /* Register specific tree functions.  */
   gimple_register_cfg_hooks ();
@@ -2024,11 +2085,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
 
   /* Duplicate any exception-handling regions.  */
   if (cfun->eh)
-    {
-      id->eh_region_offset
-       = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
-                               0, id->eh_region);
-    }
+    id->eh_map = duplicate_eh_regions (cfun_to_copy, NULL, id->eh_lp_nr,
+                                      remap_decl_1, id);
 
   /* Use aux pointers to map the original blocks to copy.  */
   FOR_EACH_BB_FN (bb, cfun_to_copy)
@@ -2061,6 +2119,12 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   entry_block_map->aux = NULL;
   exit_block_map->aux = NULL;
 
+  if (id->eh_map)
+    {
+      pointer_map_destroy (id->eh_map);
+      id->eh_map = NULL;
+    }
+
   return new_fndecl;
 }
 
@@ -2100,6 +2164,12 @@ copy_debug_stmt (gimple stmt, copy_body_data *id)
       gcc_assert (TREE_CODE (*n) == VAR_DECL);
       t = *n;
     }
+  else if (TREE_CODE (t) == VAR_DECL
+          && !TREE_STATIC (t)
+          && gimple_in_ssa_p (cfun)
+          && !pointer_map_contains (id->decl_map, t)
+          && !var_ann (t))
+    /* T is a non-localized variable.  */;
   else
     walk_tree (&t, remap_gimple_op_r, &wi, NULL);
 
@@ -2158,7 +2228,7 @@ copy_tree_body (copy_body_data *id)
    another function.  */
 
 static tree
-copy_body (copy_body_data *id, gcov_type count, int frequency,
+copy_body (copy_body_data *id, gcov_type count, int frequency_scale,
           basic_block entry_block_map, basic_block exit_block_map)
 {
   tree fndecl = id->src_fn;
@@ -2166,7 +2236,7 @@ copy_body (copy_body_data *id, gcov_type count, int frequency,
 
   /* 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);
+  body = copy_cfg_body (id, count, frequency_scale, entry_block_map, exit_block_map);
   copy_debug_stmts (id);
 
   return body;
@@ -2476,28 +2546,30 @@ initialize_inlined_parameters (copy_body_data *id, gimple stmt,
    is set only for CALL_EXPR_RETURN_SLOT_OPT.  MODIFY_DEST, if non-null,
    was the LHS of the MODIFY_EXPR to which this call is the RHS.
 
-   The return value is a (possibly null) value that is the result of the
-   function as seen by the callee.  *USE_P is a (possibly null) value that
-   holds the result as seen by the caller.  */
+   The return value is a (possibly null) value that holds the result
+   as seen by the caller.  */
 
 static tree
-declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
-                        tree *use_p)
+declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest)
 {
   tree callee = id->src_fn;
   tree caller = id->dst_fn;
   tree result = DECL_RESULT (callee);
   tree callee_type = TREE_TYPE (result);
-  tree caller_type = TREE_TYPE (TREE_TYPE (callee));
+  tree caller_type;
   tree var, use;
 
+  /* Handle type-mismatches in the function declaration return type
+     vs. the call expression.  */
+  if (modify_dest)
+    caller_type = TREE_TYPE (modify_dest);
+  else
+    caller_type = TREE_TYPE (TREE_TYPE (callee));
+
   /* We don't need to do anything for functions that don't return
      anything.  */
   if (!result || VOID_TYPE_P (callee_type))
-    {
-      *use_p = NULL_TREE;
-      return NULL_TREE;
-    }
+    return NULL_TREE;
 
   /* If there was a return slot, then the return value is the
      dereferenced address of that object.  */
@@ -2512,7 +2584,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
          STRIP_USELESS_TYPE_CONVERSION (return_slot_addr);
 
          /* We are going to construct *&return_slot and we can't do that
-            for variables believed to be not addressable. 
+            for variables believed to be not addressable.
 
             FIXME: This check possibly can match, because values returned
             via return slot optimization are not believed to have address
@@ -2630,7 +2702,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
   use = var;
   if (!useless_type_conversion_p (caller_type, TREE_TYPE (var)))
     use = fold_convert (caller_type, var);
-    
+
   STRIP_USELESS_TYPE_CONVERSION (use);
 
   if (DECL_BY_REFERENCE (result))
@@ -2648,8 +2720,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
   /* Remember this so we can ignore it in remap_decls.  */
   id->retvar = var;
 
-  *use_p = use;
-  return var;
+  return use;
 }
 
 /* Callback through walk_tree.  Determine if a DECL_INITIAL makes reference
@@ -2670,39 +2741,6 @@ has_label_address_in_static_1 (tree *nodep, int *walk_subtrees, void *fnp)
   return NULL_TREE;
 }
 
-/* Callback through walk_tree.  Determine if we've got an aggregate
-   type that we can't support; return non-null if so.  */
-
-static tree
-cannot_copy_type_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
-                    void *data ATTRIBUTE_UNUSED)
-{
-  tree t, node = *nodep;
-
-  if (TREE_CODE (node) == RECORD_TYPE || TREE_CODE (node) == UNION_TYPE)
-    {
-      /* We cannot inline a function of the form
-
-          void F (int i) { struct S { int ar[i]; } s; }
-
-        Attempting to do so produces a catch-22.
-        If walk_tree examines the TYPE_FIELDS chain of RECORD_TYPE/
-        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. 
-
-        ??? 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.  */
-      for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t))
-       if (variably_modified_type_p (TREE_TYPE (t), NULL))
-         return node;
-    }
-
-  return NULL_TREE;
-}
-
-
 /* Determine if the function can be copied.  If so return NULL.  If
    not return a string describng the reason for failure.  */
 
@@ -2745,16 +2783,6 @@ copy_forbidden (struct function *fun, tree fndecl)
                      "address of local label in a static variable");
          goto fail;
        }
-
-      if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)
-         && variably_modified_type_p (TREE_TYPE (decl), NULL)
-         && walk_tree_without_duplicates (&TREE_TYPE (decl),
-                                          cannot_copy_type_1, NULL))
-       {
-         reason = G_("function %q+F can never be copied "
-                     "because it uses variable sized variables");
-         goto fail;
-       }
     }
 
  fail:
@@ -3036,6 +3064,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights,
     case MINUS_EXPR:
     case MULT_EXPR:
 
+    case ADDR_SPACE_CONVERT_EXPR:
     case FIXED_CONVERT_EXPR:
     case FIX_TRUNC_EXPR:
 
@@ -3189,14 +3218,6 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
       lhs = gimple_assign_lhs (stmt);
       rhs = gimple_assign_rhs1 (stmt);
 
-      /* EH magic stuff is most probably going to be optimized out.
-         We rarely really need to save EH info for unwinding
-         nested exceptions.  */
-      if (TREE_CODE (lhs) == FILTER_EXPR
-         || TREE_CODE (lhs) == EXC_PTR_EXPR
-          || TREE_CODE (rhs) == FILTER_EXPR
-         || TREE_CODE (rhs) == EXC_PTR_EXPR)
-       return 0;
       if (is_gimple_reg (lhs))
        cost = 0;
       else
@@ -3220,7 +3241,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
 
     case GIMPLE_SWITCH:
       /* Take into account cost of the switch + guess 2 conditional jumps for
-         each case label.  
+         each case label.
 
         TODO: once the switch expansion logic is sufficiently separated, we can
         do better job on estimating cost of the switch.  */
@@ -3243,7 +3264,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
          cost = weights->target_builtin_call_cost;
        else
          cost = weights->call_cost;
-       
+
        if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
          switch (DECL_FUNCTION_CODE (decl))
            {
@@ -3257,6 +3278,12 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
              cost = weights->target_builtin_call_cost;
              break;
 
+           /* Exception state returns or moves registers around.  */
+           case BUILT_IN_EH_FILTER:
+           case BUILT_IN_EH_POINTER:
+           case BUILT_IN_EH_COPY_VALUES:
+             return 0;
+
            default:
              break;
            }
@@ -3307,8 +3334,18 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
       return 0;
 
     case GIMPLE_ASM:
+      return asm_str_count (gimple_asm_string (stmt));
+
     case GIMPLE_RESX:
-      return 1;
+      /* This is either going to be an external function call with one
+        argument, or two register copy statements plus a goto.  */
+      return 2;
+
+    case GIMPLE_EH_DISPATCH:
+      /* ??? This is going to turn into a switch statement.  Ideally
+        we'd have a look at the eh region and estimate the number of
+        edges involved.  */
+      return 10;
 
     case GIMPLE_BIND:
       return estimate_num_insns_seq (gimple_bind_body (stmt), weights);
@@ -3446,7 +3483,7 @@ get_indirect_callee_fndecl (struct cgraph_node *node, gimple stmt)
 static bool
 expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 {
-  tree retvar, use_retvar;
+  tree use_retvar;
   tree fn;
   struct pointer_map_t *st, *dst;
   tree return_slot;
@@ -3504,6 +3541,13 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 
   cg_edge = cgraph_edge (id->dst_node, stmt);
 
+  /* Don't inline functions with different EH personalities.  */
+  if (DECL_FUNCTION_PERSONALITY (cg_edge->caller->decl)
+      && DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl)
+      && (DECL_FUNCTION_PERSONALITY (cg_edge->caller->decl)
+         != DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl)))
+    goto egress;
+
   /* Don't try to inline functions that are not well-suited to
      inlining.  */
   if (!cgraph_inline_p (cg_edge, &reason))
@@ -3543,7 +3587,12 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 #endif
 
   /* We will be inlining this callee.  */
-  id->eh_region = lookup_stmt_eh_region (stmt);
+  id->eh_lp_nr = lookup_stmt_eh_lp (stmt);
+
+  /* Update the callers EH personality.  */
+  if (DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl))
+    DECL_FUNCTION_PERSONALITY (cg_edge->caller->decl)
+      = DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl);
 
   /* Split the block holding the GIMPLE_CALL.  */
   e = split_block (bb, stmt);
@@ -3653,7 +3702,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
     }
 
   /* Declare the return variable for the function.  */
-  retvar = declare_return_variable (id, return_slot, modify_dest, &use_retvar);
+  use_retvar = declare_return_variable (id, return_slot, modify_dest);
 
   /* Add local vars in this inlined callee to caller.  */
   t_step = id->src_cfun->local_decls;
@@ -3671,19 +3720,27 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
                                       cfun->local_decls);
     }
 
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Inlining ");
+      print_generic_expr (dump_file, id->src_fn, 0);
+      fprintf (dump_file, " to ");
+      print_generic_expr (dump_file, id->dst_fn, 0);
+      fprintf (dump_file, " with frequency %i\n", cg_edge->frequency);
+    }
+
   /* 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);
+  copy_body (id, bb->count,
+            cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE,
+            bb, return_block);
 
-  /* Reset the escaped and callused solutions.  */
+  /* Reset the escaped solution.  */
   if (cfun->gimple_df)
-    {
-      pt_solution_reset (&cfun->gimple_df->escaped);
-      pt_solution_reset (&cfun->gimple_df->callused);
-    }
+    pt_solution_reset (&cfun->gimple_df->escaped);
 
   /* Clean up.  */
   if (id->debug_map)
@@ -3813,7 +3870,48 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
              gimple old_stmt = gsi_stmt (gsi);
              tree old_decl = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
 
-             if (fold_stmt (&gsi))
+             if (old_decl && DECL_BUILT_IN (old_decl))
+               {
+                 /* Folding builtins can create multiple instructions,
+                    we need to look at all of them.  */
+                 gimple_stmt_iterator i2 = gsi;
+                 gsi_prev (&i2);
+                 if (fold_stmt (&gsi))
+                   {
+                     gimple new_stmt;
+                     if (gsi_end_p (i2))
+                       i2 = gsi_start_bb (BASIC_BLOCK (first));
+                     else
+                       gsi_next (&i2);
+                     while (1)
+                       {
+                         new_stmt = gsi_stmt (i2);
+                         update_stmt (new_stmt);
+                         cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
+                                                            new_stmt);
+
+                         if (new_stmt == gsi_stmt (gsi))
+                           {
+                             /* It is okay to check only for the very last
+                                of these statements.  If it is a throwing
+                                statement nothing will change.  If it isn't
+                                this can remove EH edges.  If that weren't
+                                correct then because some intermediate stmts
+                                throw, but not the last one.  That would mean
+                                we'd have to split the block, which we can't
+                                here and we'd loose anyway.  And as builtins
+                                probably never throw, this all
+                                is mood anyway.  */
+                             if (maybe_clean_or_replace_eh_stmt (old_stmt,
+                                                                 new_stmt))
+                               gimple_purge_dead_eh_edges (BASIC_BLOCK (first));
+                             break;
+                           }
+                         gsi_next (&i2);
+                       }
+                   }
+               }
+             else if (fold_stmt (&gsi))
                {
                  /* Re-read the statement from GSI as fold_stmt() may
                     have changed it.  */
@@ -3822,7 +3920,8 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
 
                  if (is_gimple_call (old_stmt)
                      || is_gimple_call (new_stmt))
-                   cgraph_update_edges_for_call_stmt (old_stmt, old_decl, new_stmt);
+                   cgraph_update_edges_for_call_stmt (old_stmt, old_decl,
+                                                      new_stmt);
 
                  if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
                    gimple_purge_dead_eh_edges (BASIC_BLOCK (first));
@@ -3852,7 +3951,6 @@ unsigned int
 optimize_inline_calls (tree fn)
 {
   copy_body_data id;
-  tree prev_fn;
   basic_block bb;
   int last = n_basic_blocks;
   struct gimplify_ctx gctx;
@@ -3869,12 +3967,8 @@ optimize_inline_calls (tree fn)
   id.src_node = id.dst_node = cgraph_node (fn);
   id.dst_fn = fn;
   /* Or any functions that aren't finished yet.  */
-  prev_fn = NULL_TREE;
   if (current_function_decl)
-    {
-      id.dst_fn = current_function_decl;
-      prev_fn = current_function_decl;
-    }
+    id.dst_fn = current_function_decl;
 
   id.copy_decl = copy_decl_maybe_to_var;
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
@@ -3914,11 +4008,11 @@ optimize_inline_calls (tree fn)
        gcc_assert (e->inline_failed);
     }
 #endif
-  
+
   /* Fold the statements before compacting/renumbering the basic blocks.  */
   fold_marked_statements (last, id.statements_to_fold);
   pointer_set_destroy (id.statements_to_fold);
-  
+
   gcc_assert (!id.debug_stmts);
 
   /* Renumber the (code) basic_blocks consecutively.  */
@@ -4386,14 +4480,14 @@ copy_decl_for_dup_finish (copy_body_data *id, tree decl, tree copy)
   DECL_IGNORED_P (copy) = DECL_IGNORED_P (decl);
 
   /* Set the DECL_ABSTRACT_ORIGIN so the debugging routines know what
-     declaration inspired this copy.  */ 
+     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;
 
@@ -4429,6 +4523,8 @@ copy_decl_to_var (tree decl, copy_body_data *id)
 
   copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
                     VAR_DECL, DECL_NAME (decl), type);
+  if (DECL_PT_UID_SET_P (decl))
+    SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
   TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
@@ -4454,6 +4550,8 @@ copy_result_decl_to_var (tree decl, copy_body_data *id)
 
   copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
                     VAR_DECL, DECL_NAME (decl), type);
+  if (DECL_PT_UID_SET_P (decl))
+    SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
   TREE_READONLY (copy) = TREE_READONLY (decl);
   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
   if (!DECL_BY_REFERENCE (decl))
@@ -4604,7 +4702,7 @@ delete_unreachable_blocks_update_callgraph (copy_body_data *id)
                          else
                            cgraph_remove_edge (e);
                        }
-                      
+
                      if (node->clones)
                        node = node->clones;
                      else if (node->next_sibling_clone)
@@ -4625,30 +4723,6 @@ delete_unreachable_blocks_update_callgraph (copy_body_data *id)
 
   if (changed)
     tidy_fallthru_edges ();
-#ifdef ENABLE_CHECKING0
-  verify_cgraph_node (id->dst_node);
-  if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
-      && id->dst_node->clones)
-    {
-      struct cgraph_node *node;
-      for (node = id->dst_node->clones; node != id->dst_node;)
-       {
-         verify_cgraph_node (node);
-          
-         if (node->clones)
-           node = node->clones;
-         else if (node->next_sibling_clone)
-           node = node->next_sibling_clone;
-         else
-           {
-             while (node != id->dst_node && !node->next_sibling_clone)
-               node = node->clone_of;
-             if (node != id->dst_node)
-               node = node->next_sibling_clone;
-           }
-       }
-     }
-#endif
   return changed;
 }
 
@@ -4691,9 +4765,9 @@ update_clone_info (copy_body_data * id)
 /* 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 
+   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. If UPDATE_CLONES is set, the call_stmt fields
    of edges of clones of the function will be updated.  */
 void
@@ -4729,6 +4803,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 
   DECL_ARTIFICIAL (new_decl) = 1;
   DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl);
+  DECL_FUNCTION_PERSONALITY (new_decl) = DECL_FUNCTION_PERSONALITY (old_decl);
 
   /* Prepare the data structures for the tree copy.  */
   memset (&id, 0, sizeof (id));
@@ -4743,7 +4818,20 @@ tree_function_versioning (tree old_decl, tree new_decl,
   id.src_node = old_version_node;
   id.dst_node = new_version_node;
   id.src_cfun = DECL_STRUCT_FUNCTION (old_decl);
-  
+  if (id.src_node->ipa_transforms_to_apply)
+    {
+      VEC(ipa_opt_pass,heap) * old_transforms_to_apply = id.dst_node->ipa_transforms_to_apply;
+      unsigned int i;
+
+      id.dst_node->ipa_transforms_to_apply = VEC_copy (ipa_opt_pass, heap,
+                                                      id.src_node->ipa_transforms_to_apply);
+      for (i = 0; i < VEC_length (ipa_opt_pass, old_transforms_to_apply); i++)
+        VEC_safe_push (ipa_opt_pass, heap, id.dst_node->ipa_transforms_to_apply,
+                      VEC_index (ipa_opt_pass,
+                                 old_transforms_to_apply,
+                                 i));
+    }
+
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges
     = update_clones ? CB_CGE_MOVE_CLONES : CB_CGE_MOVE;
@@ -4755,17 +4843,16 @@ tree_function_versioning (tree old_decl, tree new_decl,
   old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
     (DECL_STRUCT_FUNCTION (old_decl));
   initialize_cfun (new_decl, old_decl,
-                  old_entry_block->count,
-                  old_entry_block->frequency);
+                  old_entry_block->count);
   push_cfun (DECL_STRUCT_FUNCTION (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);
-  
+
   /* If there's a tree_map, prepare for substitution.  */
   if (tree_map)
     for (i = 0; i < VEC_length (ipa_replace_map_p, tree_map); i++)
@@ -4780,7 +4867,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 
            if (TREE_CODE (op) == VIEW_CONVERT_EXPR)
              op = TREE_OPERAND (op, 0);
-           
+
            if (TREE_CODE (op) == ADDR_EXPR)
              {
                op = TREE_OPERAND (op, 0);
@@ -4803,12 +4890,12 @@ tree_function_versioning (tree old_decl, tree new_decl,
     DECL_ARGUMENTS (new_decl) =
       copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id,
                                     args_to_skip, &vars);
-  
+
   DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
-  
+
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (id.dst_fn);
-  
+
   declare_inline_vars (DECL_INITIAL (new_decl), vars);
 
   if (DECL_STRUCT_FUNCTION (old_decl)->local_decls != NULL_TREE)
@@ -4824,18 +4911,18 @@ tree_function_versioning (tree old_decl, tree new_decl,
            tree_cons (NULL_TREE, remap_decl (var, &id),
                       cfun->local_decls);
       }
-  
+
   /* Copy the Function's body.  */
-  copy_body (&id, old_entry_block->count, old_entry_block->frequency,
+  copy_body (&id, old_entry_block->count, REG_BR_PROB_BASE,
             ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR);
-  
+
   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));
     }
-  
+
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (new_decl);
 
@@ -4921,7 +5008,7 @@ maybe_inline_call_in_expr (tree exp)
       id.do_not_unshare = true;
 
       /* We're not inside any EH region.  */
-      id.eh_region = -1;
+      id.eh_lp_nr = 0;
 
       t = copy_tree_body (&id);
       pointer_map_destroy (decl_map);
@@ -4994,23 +5081,46 @@ tree_can_inline_p (struct cgraph_edge *e)
        return false;
     }
 #endif
-  tree caller, callee;
+  tree caller, callee, lhs;
 
   caller = e->caller->decl;
   callee = e->callee->decl;
 
+  /* We cannot inline a function that uses a different EH personality
+     than the caller.  */
+  if (DECL_FUNCTION_PERSONALITY (caller)
+      && DECL_FUNCTION_PERSONALITY (callee)
+      && (DECL_FUNCTION_PERSONALITY (caller)
+         != DECL_FUNCTION_PERSONALITY (callee)))
+    {
+      e->inline_failed = CIF_UNSPECIFIED;
+      gimple_call_set_cannot_inline (e->call_stmt, true);
+      return false;
+    }
+
   /* Allow the backend to decide if inlining is ok.  */
   if (!targetm.target_option.can_inline_p (caller, callee))
     {
       e->inline_failed = CIF_TARGET_OPTION_MISMATCH;
       gimple_call_set_cannot_inline (e->call_stmt, true);
+      e->call_stmt_cannot_inline_p = true;
       return false;
     }
 
-  if (!gimple_check_call_args (e->call_stmt))
+  /* Do not inline calls where we cannot triviall work around mismatches
+     in argument or return types.  */
+  if (e->call_stmt
+      && ((DECL_RESULT (callee)
+          && !DECL_BY_REFERENCE (DECL_RESULT (callee))
+          && (lhs = gimple_call_lhs (e->call_stmt)) != NULL_TREE
+          && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)),
+                                         TREE_TYPE (lhs))
+          && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs))
+         || !gimple_check_call_args (e->call_stmt)))
     {
       e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
       gimple_call_set_cannot_inline (e->call_stmt, true);
+      e->call_stmt_cannot_inline_p = true;
       return false;
     }