OSDN Git Service

From Jie Zhang <jie.zhang@analog.com>:
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index a28f0a4..b5e7346 100644 (file)
@@ -147,6 +147,30 @@ insert_decl_map (copy_body_data *id, tree key, tree value)
     *pointer_map_insert (id->decl_map, value) = value;
 }
 
+/* Insert a tree->tree mapping for ID.  This is only used for
+   variables.  */
+
+static void
+insert_debug_decl_map (copy_body_data *id, tree key, tree value)
+{
+  if (!gimple_in_ssa_p (id->src_cfun))
+    return;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return;
+
+  if (!target_for_debug_bind (key))
+    return;
+
+  gcc_assert (TREE_CODE (key) == PARM_DECL);
+  gcc_assert (TREE_CODE (value) == VAR_DECL);
+
+  if (!id->debug_map)
+    id->debug_map = pointer_map_create ();
+
+  *pointer_map_insert (id->debug_map, key) = value;
+}
+
 /* Construct new SSA name for old NAME. ID is the inline context.  */
 
 static tree
@@ -220,6 +244,12 @@ 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
@@ -235,6 +265,12 @@ remap_decl (tree decl, copy_body_data *id)
 
   n = (tree *) pointer_map_contains (id->decl_map, decl);
 
+  if (!n && processing_debug_stmt)
+    {
+      processing_debug_stmt = -1;
+      return decl;
+    }
+
   /* If we didn't already have an equivalent for this declaration,
      create one now.  */
   if (!n)
@@ -500,6 +536,7 @@ remap_decls (tree decls, VEC(tree,gc) **nonlocalized_list, copy_body_data *id)
       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);
@@ -600,6 +637,7 @@ copy_statement_list (tree *tp)
   new_tree = alloc_stmt_list ();
   ni = tsi_start (new_tree);
   oi = tsi_start (*tp);
+  TREE_TYPE (new_tree) = TREE_TYPE (*tp);
   *tp = new_tree;
 
   for (; !tsi_end_p (oi); tsi_next (&oi))
@@ -811,7 +849,8 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
         vars.  If not referenced from types only.  */
       if (gimple_in_ssa_p (cfun)
          && TREE_CODE (*tp) == VAR_DECL
-         && id->remapping_type_depth == 0)
+         && id->remapping_type_depth == 0
+         && !processing_debug_stmt)
        add_referenced_var (*tp);
 
       /* We should never have TREE_BLOCK set on non-statements.  */
@@ -1042,10 +1081,11 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
       copy_tree_r (tp, walk_subtrees, NULL);
 
       /* Global variables we haven't seen yet needs to go into referenced
-        vars.  If not referenced from types only.  */
+        vars.  If not referenced from types or debug stmts only.  */
       if (gimple_in_ssa_p (cfun)
          && TREE_CODE (*tp) == VAR_DECL
-         && id->remapping_type_depth == 0)
+         && id->remapping_type_depth == 0
+         && !processing_debug_stmt)
        add_referenced_var (*tp);
        
       /* If EXPR has block defined, map it to newly constructed block.
@@ -1291,8 +1331,17 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
            }
        }
 
-      /* Create a new deep copy of the statement.  */
-      copy = gimple_copy (stmt);
+      if (gimple_debug_bind_p (stmt))
+       {
+         copy = gimple_build_debug_bind (gimple_debug_bind_get_var (stmt),
+                                         gimple_debug_bind_get_value (stmt),
+                                         stmt);
+         VEC_safe_push (gimple, heap, id->debug_stmts, copy);
+         return copy;
+       }
+      else
+       /* Create a new deep copy of the statement.  */
+       copy = gimple_copy (stmt);
     }
 
   /* If STMT has a block defined, map it to the newly constructed
@@ -1309,6 +1358,9 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
 
   gimple_set_block (copy, new_block);
 
+  if (gimple_debug_bind_p (copy))
+    return copy;
+
   /* Remap all the operands in COPY.  */
   memset (&wi, 0, sizeof (wi));
   wi.info = id;
@@ -1383,8 +1435,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
        {
          tree new_rhs;
          new_rhs = force_gimple_operand_gsi (&seq_gsi,
-                                             gimple_assign_rhs1 (stmt),
-                                             true, NULL, true, GSI_SAME_STMT);
+                                             gimple_assign_rhs1 (stmt),
+                                             true, NULL, false, GSI_NEW_STMT);
          gimple_assign_set_rhs1 (stmt, new_rhs);
          id->regimplify = false;
        }
@@ -1496,67 +1548,69 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
             callgraph edges and update or duplicate them.  */
          if (is_gimple_call (stmt))
            {
-             struct cgraph_edge *edge = cgraph_edge (id->src_node, orig_stmt);
+             struct cgraph_edge *edge;
              int flags;
 
              switch (id->transform_call_graph_edges)
                {
-             case CB_CGE_DUPLICATE:
-               if (edge)
-                 cgraph_clone_edge (edge, id->dst_node, stmt,
-                                          REG_BR_PROB_BASE, 1,
-                                          edge->frequency, true);
-               break;
-
-             case CB_CGE_MOVE_CLONES:
-               cgraph_set_call_stmt_including_clones (id->dst_node, orig_stmt, stmt);
-               break;
-
-             case CB_CGE_MOVE:
-               if (edge)
-                 cgraph_set_call_stmt (edge, stmt);
-               break;
-
-             default:
-               gcc_unreachable ();
+               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);
+                 break;
+
+               case CB_CGE_MOVE_CLONES:
+                 cgraph_set_call_stmt_including_clones (id->dst_node,
+                                                        orig_stmt, stmt);
+                 edge = cgraph_edge (id->dst_node, stmt);
+                 break;
+
+               case CB_CGE_MOVE:
+                 edge = cgraph_edge (id->dst_node, orig_stmt);
+                 if (edge)
+                   cgraph_set_call_stmt (edge, stmt);
+                 break;
+
+               default:
+                 gcc_unreachable ();
                }
 
-           edge = cgraph_edge (id->src_node, orig_stmt);
-           /* Constant propagation on argument done during inlining
-              may create new direct call.  Produce an edge for it.  */
-           if ((!edge 
-                || (edge->indirect_call
-                    && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
-               && is_gimple_call (stmt)
-               && (fn = gimple_call_fndecl (stmt)) != NULL)
-             {
-               struct cgraph_node *dest = cgraph_node (fn);
-
-               /* We have missing edge in the callgraph.  This can happen in one case
-                  where previous inlining turned indirect call into direct call by
-                  constant propagating arguments.  In all other cases we hit a bug
-                  (incorrect node sharing is most common reason for missing edges.  */
-               gcc_assert (dest->needed || !dest->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),
-                                                      bb->loop_depth,
-                                                      CIF_ORIGINALLY_INDIRECT_CALL);
-               else
-                 cgraph_create_edge (id->dst_node, dest, stmt,
-                                     bb->count, CGRAPH_FREQ_BASE,
-                                     bb->loop_depth)->inline_failed
-                   = CIF_ORIGINALLY_INDIRECT_CALL;
-               if (dump_file)
-                 {
-                    fprintf (dump_file, "Created new direct edge to %s",
-                             cgraph_node_name (dest));
-                 }
-             }
+             /* Constant propagation on argument done during inlining
+                may create new direct call.  Produce an edge for it.  */
+             if ((!edge 
+                  || (edge->indirect_call
+                      && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
+                 && is_gimple_call (stmt)
+                 && (fn = gimple_call_fndecl (stmt)) != NULL)
+               {
+                 struct cgraph_node *dest = cgraph_node (fn);
+
+                 /* 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
+                    other cases we hit a bug (incorrect node sharing is the
+                    most common reason for missing edges).  */
+                 gcc_assert (dest->needed || !dest->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),
+                      bb->loop_depth, CIF_ORIGINALLY_INDIRECT_CALL);
+                 else
+                   cgraph_create_edge (id->dst_node, dest, stmt,
+                                       bb->count, CGRAPH_FREQ_BASE,
+                                       bb->loop_depth)->inline_failed
+                     = CIF_ORIGINALLY_INDIRECT_CALL;
+                 if (dump_file)
+                   {
+                     fprintf (dump_file, "Created new direct edge to %s",
+                              cgraph_node_name (dest));
+                   }
+               }
 
              flags = gimple_call_flags (stmt);
-
              if (flags & ECF_MAY_BE_ALLOCA)
                cfun->calls_alloca = true;
              if (flags & ECF_RETURNS_TWICE)
@@ -1601,7 +1655,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                add_stmt_to_eh_region (stmt, id->eh_region);
            }
 
-         if (gimple_in_ssa_p (cfun))
+         if (gimple_in_ssa_p (cfun) && !is_gimple_debug (stmt))
            {
              ssa_op_iter i;
              tree def;
@@ -1730,9 +1784,12 @@ copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb)
       bool can_throw, nonlocal_goto;
 
       copy_stmt = gsi_stmt (si);
-      update_stmt (copy_stmt);
-      if (gimple_in_ssa_p (cfun))
-        mark_symbols_for_renaming (copy_stmt);
+      if (!is_gimple_debug (copy_stmt))
+       {
+         update_stmt (copy_stmt);
+         if (gimple_in_ssa_p (cfun))
+           mark_symbols_for_renaming (copy_stmt);
+       }
 
       /* Do this before the possible split_block.  */
       gsi_next (&si);
@@ -1826,7 +1883,8 @@ 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));
            }
        }
     }
@@ -2007,6 +2065,82 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   return new_fndecl;
 }
 
+/* Copy the debug STMT using ID.  We deal with these statements in a
+   special way: if any variable in their VALUE expression wasn't
+   remapped yet, we won't remap it, because that would get decl uids
+   out of sync, causing codegen differences between -g and -g0.  If
+   this arises, we drop the VALUE expression altogether.  */
+
+static void
+copy_debug_stmt (gimple stmt, copy_body_data *id)
+{
+  tree t, *n;
+  struct walk_stmt_info wi;
+
+  t = id->block;
+  if (gimple_block (stmt))
+    {
+      tree *n;
+      n = (tree *) pointer_map_contains (id->decl_map, gimple_block (stmt));
+      if (n)
+       t = *n;
+    }
+  gimple_set_block (stmt, t);
+
+  /* Remap all the operands in COPY.  */
+  memset (&wi, 0, sizeof (wi));
+  wi.info = id;
+
+  processing_debug_stmt = 1;
+
+  t = gimple_debug_bind_get_var (stmt);
+
+  if (TREE_CODE (t) == PARM_DECL && id->debug_map
+      && (n = (tree *) pointer_map_contains (id->debug_map, t)))
+    {
+      gcc_assert (TREE_CODE (*n) == VAR_DECL);
+      t = *n;
+    }
+  else
+    walk_tree (&t, remap_gimple_op_r, &wi, NULL);
+
+  gimple_debug_bind_set_var (stmt, t);
+
+  if (gimple_debug_bind_has_value_p (stmt))
+    walk_tree (gimple_debug_bind_get_value_ptr (stmt),
+              remap_gimple_op_r, &wi, NULL);
+
+  /* Punt if any decl couldn't be remapped.  */
+  if (processing_debug_stmt < 0)
+    gimple_debug_bind_reset_value (stmt);
+
+  processing_debug_stmt = 0;
+
+  update_stmt (stmt);
+  if (gimple_in_ssa_p (cfun))
+    mark_symbols_for_renaming (stmt);
+}
+
+/* Process deferred debug stmts.  In order to give values better odds
+   of being successfully remapped, we delay the processing of debug
+   stmts until all other stmts that might require remapping are
+   processed.  */
+
+static void
+copy_debug_stmts (copy_body_data *id)
+{
+  size_t i;
+  gimple stmt;
+
+  if (!id->debug_stmts)
+    return;
+
+  for (i = 0; VEC_iterate (gimple, id->debug_stmts, i, stmt); i++)
+    copy_debug_stmt (stmt, id);
+
+  VEC_free (gimple, heap, id->debug_stmts);
+}
+
 /* Make a copy of the body of SRC_FN so that it can be inserted inline in
    another function.  */
 
@@ -2021,6 +2155,9 @@ copy_tree_body (copy_body_data *id)
   return body;
 }
 
+/* Make a copy of the body of FN so that it can be inserted inline in
+   another function.  */
+
 static tree
 copy_body (copy_body_data *id, gcov_type count, int frequency,
           basic_block entry_block_map, basic_block exit_block_map)
@@ -2031,6 +2168,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);
+  copy_debug_stmts (id);
 
   return body;
 }
@@ -2051,8 +2189,51 @@ self_inlining_addr_expr (tree value, tree fn)
   return var && auto_var_in_fn_p (var, fn);
 }
 
+/* Append to BB a debug annotation that binds VAR to VALUE, inheriting
+   lexical block and line number information from base_stmt, if given,
+   or from the last stmt of the block otherwise.  */
+
+static gimple
+insert_init_debug_bind (copy_body_data *id,
+                       basic_block bb, tree var, tree value,
+                       gimple base_stmt)
+{
+  gimple note;
+  gimple_stmt_iterator gsi;
+  tree tracked_var;
+
+  if (!gimple_in_ssa_p (id->src_cfun))
+    return NULL;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return NULL;
+
+  tracked_var = target_for_debug_bind (var);
+  if (!tracked_var)
+    return NULL;
+
+  if (bb)
+    {
+      gsi = gsi_last_bb (bb);
+      if (!base_stmt && !gsi_end_p (gsi))
+       base_stmt = gsi_stmt (gsi);
+    }
+
+  note = gimple_build_debug_bind (tracked_var, value, base_stmt);
+
+  if (bb)
+    {
+      if (!gsi_end_p (gsi))
+       gsi_insert_after (&gsi, note, GSI_SAME_STMT);
+      else
+       gsi_insert_before (&gsi, note, GSI_SAME_STMT);
+    }
+
+  return note;
+}
+
 static void
-insert_init_stmt (basic_block bb, gimple init_stmt)
+insert_init_stmt (copy_body_data *id, basic_block bb, gimple init_stmt)
 {
   /* If VAR represents a zero-sized variable, it's possible that the
      assignment statement may result in no gimple statements.  */
@@ -2064,7 +2245,8 @@ insert_init_stmt (basic_block bb, gimple init_stmt)
          from a rhs with a conversion.  Handle that here by forcing the
         rhs into a temporary.  gimple_regimplify_operands is not
         prepared to do this for us.  */
-      if (!is_gimple_reg (gimple_assign_lhs (init_stmt))
+      if (!is_gimple_debug (init_stmt)
+         && !is_gimple_reg (gimple_assign_lhs (init_stmt))
          && is_gimple_reg_type (TREE_TYPE (gimple_assign_lhs (init_stmt)))
          && gimple_assign_rhs_class (init_stmt) == GIMPLE_UNARY_RHS)
        {
@@ -2079,6 +2261,18 @@ insert_init_stmt (basic_block bb, gimple init_stmt)
       gsi_insert_after (&si, init_stmt, GSI_NEW_STMT);
       gimple_regimplify_operands (init_stmt, &si);
       mark_symbols_for_renaming (init_stmt);
+
+      if (!is_gimple_debug (init_stmt) && MAY_HAVE_DEBUG_STMTS)
+       {
+         tree var, def = gimple_assign_lhs (init_stmt);
+
+         if (TREE_CODE (def) == SSA_NAME)
+           var = SSA_NAME_VAR (def);
+         else
+           var = def;
+
+         insert_init_debug_bind (id, bb, var, def, init_stmt);
+       }
     }
 }
 
@@ -2109,9 +2303,29 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
        rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value);
     }
 
+  /* Make an equivalent VAR_DECL.  Note that we must NOT remap the type
+     here since the type of this decl must be visible to the calling
+     function.  */
+  var = copy_decl_to_var (p, id);
+
+  /* We're actually using the newly-created var.  */
+  if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
+    {
+      get_var_ann (var);
+      add_referenced_var (var);
+    }
+
+  /* Declare this new variable.  */
+  TREE_CHAIN (var) = *vars;
+  *vars = var;
+
+  /* Make gimplifier happy about this variable.  */
+  DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
+
   /* 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
-     be able to just use the argument value.  */
+     we would not need to create a new variable here at all, if it
+     weren't for debug info.  Still, we can just use the argument
+     value.  */
   if (TREE_READONLY (p)
       && !TREE_ADDRESSABLE (p)
       && value && !TREE_SIDE_EFFECTS (value)
@@ -2132,32 +2346,16 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
          && ! self_inlining_addr_expr (value, fn))
        {
          insert_decl_map (id, p, value);
-         return NULL;
+         insert_debug_decl_map (id, p, var);
+         return insert_init_debug_bind (id, bb, var, value, NULL);
        }
     }
 
-  /* Make an equivalent VAR_DECL.  Note that we must NOT remap the type
-     here since the type of this decl must be visible to the calling
-     function.  */
-  var = copy_decl_to_var (p, id);
-  if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
-    {
-      get_var_ann (var);
-      add_referenced_var (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);
 
-  /* Declare this new variable.  */
-  TREE_CHAIN (var) = *vars;
-  *vars = var;
-
-  /* Make gimplifier happy about this variable.  */
-  DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
-
   /* Even if P was TREE_READONLY, the new VAR should not be.
      In the original code, we would have constructed a
      temporary, and then the function body would have never
@@ -2179,15 +2377,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 
      Do replacement at -O0 for const arguments replaced by constant.
      This is important for builtin_constant_p and other construct requiring
-     constant argument to be visible in inlined function body.
-
-     FIXME: This usually kills the last connection in between inlined
-     function parameter and the actual value in debug info.  Can we do
-     better here?  If we just inserted the statement, copy propagation
-     would kill it anyway as it always did in older versions of GCC.
-
-     We might want to introduce a notion that single SSA_NAME might
-     represent multiple variables for purposes of debugging. */
+     constant argument to be visible in inlined function body.  */
   if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p)
       && (optimize
           || (TREE_READONLY (p)
@@ -2197,7 +2387,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
     {
       insert_decl_map (id, def, rhs);
-      return NULL;
+      return insert_init_debug_bind (id, bb, var, rhs, NULL);
     }
 
   /* If the value of argument is never used, don't care about initializing
@@ -2205,7 +2395,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
   if (optimize && gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
     {
       gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
-      return NULL;
+      return insert_init_debug_bind (id, bb, var, rhs, NULL);
     }
 
   /* Initialize this VAR_DECL from the equivalent argument.  Convert
@@ -2215,7 +2405,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);
-         return NULL;
+         return insert_init_debug_bind (id, bb, var, rhs, NULL);
        }
 
       STRIP_USELESS_TYPE_CONVERSION (rhs);
@@ -2233,7 +2423,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
         init_stmt = gimple_build_assign (var, rhs);
 
       if (bb && init_stmt)
-        insert_init_stmt (bb, init_stmt);
+        insert_init_stmt (id, bb, init_stmt);
     }
   return init_stmt;
 }
@@ -3114,6 +3304,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
     case GIMPLE_PHI:
     case GIMPLE_RETURN:
     case GIMPLE_PREDICT:
+    case GIMPLE_DEBUG:
       return 0;
 
     case GIMPLE_ASM:
@@ -3258,7 +3449,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 {
   tree retvar, use_retvar;
   tree fn;
-  struct pointer_map_t *st;
+  struct pointer_map_t *st, *dst;
   tree return_slot;
   tree modify_dest;
   location_t saved_location;
@@ -3398,6 +3589,8 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
      map.  */
   st = id->decl_map;
   id->decl_map = pointer_map_create ();
+  dst = id->debug_map;
+  id->debug_map = NULL;
 
   /* Record the function we are about to inline.  */
   id->src_fn = fn;
@@ -3494,6 +3687,11 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
     }
 
   /* Clean up.  */
+  if (id->debug_map)
+    {
+      pointer_map_destroy (id->debug_map);
+      id->debug_map = dst;
+    }
   pointer_map_destroy (id->decl_map);
   id->decl_map = st;
 
@@ -3722,6 +3920,8 @@ optimize_inline_calls (tree fn)
   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.  */
   compact_blocks ();
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
@@ -3957,6 +4157,7 @@ unsave_expr_now (tree expr)
   id.src_fn = current_function_decl;
   id.dst_fn = current_function_decl;
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
 
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
@@ -3972,6 +4173,8 @@ unsave_expr_now (tree expr)
 
   /* Clean up.  */
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
 
   return expr;
 }
@@ -4103,6 +4306,7 @@ copy_gimple_seq_and_replace_locals (gimple_seq seq)
   id.src_fn = current_function_decl;
   id.dst_fn = current_function_decl;
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
 
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
@@ -4127,6 +4331,8 @@ copy_gimple_seq_and_replace_locals (gimple_seq seq)
 
   /* Clean up.  */
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
 
   return copy;
 }
@@ -4349,7 +4555,8 @@ copy_static_chain (tree static_chain, copy_body_data * id)
 bool
 tree_versionable_function_p (tree fndecl)
 {
-  return copy_forbidden (DECL_STRUCT_FUNCTION (fndecl), fndecl) == NULL;
+  return (!lookup_attribute ("noclone", DECL_ATTRIBUTES (fndecl))
+         && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl), fndecl) == NULL);
 }
 
 /* Delete all unreachable basic blocks and update callgraph.
@@ -4446,6 +4653,42 @@ delete_unreachable_blocks_update_callgraph (copy_body_data *id)
   return changed;
 }
 
+/* Update clone info after duplication.  */
+
+static void
+update_clone_info (copy_body_data * id)
+{
+  struct cgraph_node *node;
+  if (!id->dst_node->clones)
+    return;
+  for (node = id->dst_node->clones; node != id->dst_node;)
+    {
+      /* First update replace maps to match the new body.  */
+      if (node->clone.tree_map)
+        {
+         unsigned int i;
+          for (i = 0; i < VEC_length (ipa_replace_map_p, node->clone.tree_map); i++)
+           {
+             struct ipa_replace_map *replace_info;
+             replace_info = VEC_index (ipa_replace_map_p, node->clone.tree_map, i);
+             walk_tree (&replace_info->old_tree, copy_tree_body_r, id, NULL);
+             walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL);
+           }
+       }
+      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;
+       }
+    }
+}
+
 /* 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
@@ -4465,7 +4708,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
   tree p;
   unsigned i;
   struct ipa_replace_map *replace_info;
-  basic_block old_entry_block;
+  basic_block old_entry_block, bb;
   VEC (gimple, heap) *init_stmts = VEC_alloc (gimple, heap, 10);
 
   tree t_step;
@@ -4493,8 +4736,9 @@ tree_function_versioning (tree old_decl, tree new_decl,
 
   /* Generate a new name for the new version. */
   id.statements_to_fold = pointer_set_create ();
-  
+
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
   id.src_fn = old_decl;
   id.dst_fn = new_decl;
   id.src_node = old_version_node;
@@ -4596,12 +4840,13 @@ tree_function_versioning (tree old_decl, tree new_decl,
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (new_decl);
 
-  if (VEC_length (gimple, init_stmts))
-    {
-      basic_block bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR));
-      while (VEC_length (gimple, init_stmts))
-       insert_init_stmt (bb, VEC_pop (gimple, init_stmts));
-    }
+  /* We want to create the BB unconditionally, so that the addition of
+     debug stmts doesn't affect BB count, which may in the end cause
+     codegen differences.  */
+  bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR));
+  while (VEC_length (gimple, init_stmts))
+    insert_init_stmt (&id, bb, VEC_pop (gimple, init_stmts));
+  update_clone_info (&id);
 
   /* Remap the nonlocal_goto_save_area, if any.  */
   if (cfun->nonlocal_goto_save_area)
@@ -4615,6 +4860,8 @@ tree_function_versioning (tree old_decl, tree new_decl,
 
   /* Clean up.  */
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
 
@@ -4626,6 +4873,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
 
+  gcc_assert (!id.debug_stmts);
   VEC_free (gimple, heap, init_stmts);
   pop_cfun ();
   current_function_decl = old_current_function_decl;
@@ -4700,11 +4948,14 @@ build_duplicate_type (tree type)
   id.dst_fn = current_function_decl;
   id.src_cfun = cfun;
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
   id.copy_decl = copy_decl_no_change;
 
   type = remap_type_1 (type, &id);
 
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
 
   TYPE_CANONICAL (type) = type;
 
@@ -4712,9 +4963,10 @@ build_duplicate_type (tree type)
 }
 
 /* Return whether it is safe to inline a function because it used different
-   target specific options or different optimization options.  */
+   target specific options or call site actual types mismatch parameter types.
+   E is the call edge to be checked.  */
 bool
-tree_can_inline_p (tree caller, tree callee)
+tree_can_inline_p (struct cgraph_edge *e)
 {
 #if 0
   /* This causes a regression in SPEC in that it prevents a cold function from
@@ -4743,7 +4995,25 @@ tree_can_inline_p (tree caller, tree callee)
        return false;
     }
 #endif
+  tree caller, callee;
+
+  caller = e->caller->decl;
+  callee = e->callee->decl;
 
   /* Allow the backend to decide if inlining is ok.  */
-  return targetm.target_option.can_inline_p (caller, callee);
+  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);
+      return false;
+    }
+
+  if (!gimple_check_call_args (e->call_stmt))
+    {
+      e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
+      gimple_call_set_cannot_inline (e->call_stmt, true);
+      return false;
+    }
+
+  return true;
 }