OSDN Git Service

2012-04-13 Tom de Vries <tom@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / ipa-split.c
index fabd6d1..9dddf39 100644 (file)
@@ -1,5 +1,5 @@
 /* Function splitting pass
-   Copyright (C) 2010, 2011
+   Copyright (C) 2010, 2011, 2012
    Free Software Foundation, Inc.
    Contributed by Jan Hubicka  <jh@suse.cz>
 
@@ -46,7 +46,7 @@ along with GCC; see the file COPYING3.  If not see
      }
 
    When func becomes inlinable and when cheap_test is often true, inlining func,
-   but not fund.part leads to performance imrovement similar as inlining
+   but not fund.part leads to performance improvement similar as inlining
    original func while the code size growth is smaller.
 
    The pass is organized in three stages:
@@ -92,6 +92,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "fibheap.h"
 #include "params.h"
 #include "gimple-pretty-print.h"
+#include "ipa-inline.h"
 
 /* Per basic block info.  */
 
@@ -112,7 +113,7 @@ struct split_point
   /* Size of the partitions.  */
   unsigned int header_time, header_size, split_time, split_size;
 
-  /* SSA names that need to be passed into spit funciton.  */
+  /* SSA names that need to be passed into spit function.  */
   bitmap ssa_names_to_pass;
 
   /* Basic block where we split (that will become entry point of new function.  */
@@ -130,6 +131,10 @@ struct split_point
 
 struct split_point best_split_point;
 
+/* Set of basic blocks that are not allowed to dominate a split point.  */
+
+static bitmap forbidden_dominators;
+
 static tree find_retval (basic_block return_bb);
 
 /* Callback for walk_stmt_load_store_addr_ops.  If T is non-SSA automatic
@@ -169,8 +174,9 @@ static void
 dump_split_point (FILE * file, struct split_point *current)
 {
   fprintf (file,
-          "Split point at BB %i header time:%i header size: %i"
-          " split time: %i split size: %i\n  bbs: ",
+          "Split point at BB %i\n"
+          "  header time: %i header size: %i\n"
+          "  split time: %i split size: %i\n  bbs: ",
           current->entry_bb->index, current->header_time,
           current->header_size, current->split_time, current->split_size);
   dump_bitmap (file, current->split_bbs);
@@ -270,6 +276,83 @@ done:
   return ok;
 }
 
+/* If STMT is a call, check the callee against a list of forbidden
+   predicate functions.  If a match is found, look for uses of the
+   call result in condition statements that compare against zero.
+   For each such use, find the block targeted by the condition
+   statement for the nonzero result, and set the bit for this block
+   in the forbidden dominators bitmap.  The purpose of this is to avoid
+   selecting a split point where we are likely to lose the chance
+   to optimize away an unused function call.  */
+
+static void
+check_forbidden_calls (gimple stmt)
+{
+  imm_use_iterator use_iter;
+  use_operand_p use_p;
+  tree lhs;
+
+  /* At the moment, __builtin_constant_p is the only forbidden
+     predicate function call (see PR49642).  */
+  if (!gimple_call_builtin_p (stmt, BUILT_IN_CONSTANT_P))
+    return;
+
+  lhs = gimple_call_lhs (stmt);
+
+  if (!lhs || TREE_CODE (lhs) != SSA_NAME)
+    return;
+
+  FOR_EACH_IMM_USE_FAST (use_p, use_iter, lhs)
+    {
+      tree op1;
+      basic_block use_bb, forbidden_bb;
+      enum tree_code code;
+      edge true_edge, false_edge;
+      gimple use_stmt = USE_STMT (use_p);
+
+      if (gimple_code (use_stmt) != GIMPLE_COND)
+       continue;
+
+      /* Assuming canonical form for GIMPLE_COND here, with constant
+        in second position.  */
+      op1 = gimple_cond_rhs (use_stmt);
+      code = gimple_cond_code (use_stmt);
+      use_bb = gimple_bb (use_stmt);
+
+      extract_true_false_edges_from_block (use_bb, &true_edge, &false_edge);
+
+      /* We're only interested in comparisons that distinguish
+        unambiguously from zero.  */
+      if (!integer_zerop (op1) || code == LE_EXPR || code == GE_EXPR)
+       continue;
+
+      if (code == EQ_EXPR)
+       forbidden_bb = false_edge->dest;
+      else
+       forbidden_bb = true_edge->dest;
+
+      bitmap_set_bit (forbidden_dominators, forbidden_bb->index);
+    }
+}
+
+/* If BB is dominated by any block in the forbidden dominators set,
+   return TRUE; else FALSE.  */
+
+static bool
+dominated_by_forbidden (basic_block bb)
+{
+  unsigned dom_bb;
+  bitmap_iterator bi;
+
+  EXECUTE_IF_SET_IN_BITMAP (forbidden_dominators, 1, dom_bb, bi)
+    {
+      if (dominated_by_p (CDI_DOMINATORS, bb, BASIC_BLOCK (dom_bb)))
+       return true;
+    }
+
+  return false;
+}
+
 /* We found an split_point CURRENT.  NON_SSA_VARS is bitmap of all non ssa
    variables used and RETURN_BB is return basic block.
    See if we can split function here.  */
@@ -285,7 +368,7 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
   edge_iterator ei;
   gimple_stmt_iterator bsi;
   unsigned int i;
-  int incomming_freq = 0;
+  int incoming_freq = 0;
   tree retval;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -293,16 +376,16 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
 
   FOR_EACH_EDGE (e, ei, current->entry_bb->preds)
     if (!bitmap_bit_p (current->split_bbs, e->src->index))
-      incomming_freq += EDGE_FREQUENCY (e);
+      incoming_freq += EDGE_FREQUENCY (e);
 
   /* Do not split when we would end up calling function anyway.  */
-  if (incomming_freq
+  if (incoming_freq
       >= (ENTRY_BLOCK_PTR->frequency
          * PARAM_VALUE (PARAM_PARTIAL_INLINING_ENTRY_PROBABILITY) / 100))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file,
-                "  Refused: incomming frequency is too large.\n");
+                "  Refused: incoming frequency is too large.\n");
       return;
     }
 
@@ -313,8 +396,8 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
       return;
     }
 
-  /* Verify that PHI args on entry are either virutal or all their operands
-     incomming from header are the same.  */
+  /* Verify that PHI args on entry are either virtual or all their operands
+     incoming from header are the same.  */
   for (bsi = gsi_start_phis (current->entry_bb); !gsi_end_p (bsi); gsi_next (&bsi))
     {
       gimple stmt = gsi_stmt (bsi);
@@ -411,8 +494,17 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
                 "  Refused: split part has non-ssa uses\n");
       return;
     }
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "  Accepted!\n");
+
+  /* If the split point is dominated by a forbidden block, reject
+     the split.  */
+  if (!bitmap_empty_p (forbidden_dominators)
+      && dominated_by_forbidden (current->entry_bb))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file,
+                "  Refused: split point dominated by forbidden block\n");
+      return;
+    }
 
   /* See if retval used by return bb is computed by header or split part.
      When it is computed by split part, we need to produce return statement
@@ -451,6 +543,30 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
   else
     current->split_part_set_retval = true;
 
+  /* split_function fixes up at most one PHI non-virtual PHI node in return_bb,
+     for the return value.  If there are other PHIs, give up.  */
+  if (return_bb != EXIT_BLOCK_PTR)
+    {
+      gimple_stmt_iterator psi;
+
+      for (psi = gsi_start_phis (return_bb); !gsi_end_p (psi); gsi_next (&psi))
+       if (is_gimple_reg (gimple_phi_result (gsi_stmt (psi)))
+           && !(retval
+                && current->split_part_set_retval
+                && TREE_CODE (retval) == SSA_NAME
+                && !DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))
+                && SSA_NAME_DEF_STMT (retval) == gsi_stmt (psi)))
+         {
+           if (dump_file && (dump_flags & TDF_DETAILS))
+             fprintf (dump_file,
+                      "  Refused: return bb has extra PHIs\n");
+           return;
+         }
+    }
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "  Accepted!\n");
+
   /* At the moment chose split point with lowest frequency and that leaves
      out smallest size of header.
      In future we might re-consider this heuristics.  */
@@ -496,51 +612,45 @@ static basic_block
 find_return_bb (void)
 {
   edge e;
-  edge_iterator ei;
   basic_block return_bb = EXIT_BLOCK_PTR;
+  gimple_stmt_iterator bsi;
+  bool found_return = false;
+  tree retval = NULL_TREE;
 
-  if (EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 1)
-    FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
-      {
-       gimple_stmt_iterator bsi;
-       bool found_return = false;
-       tree retval = NULL_TREE;
+  if (!single_pred_p (EXIT_BLOCK_PTR))
+    return return_bb;
+
+  e = single_pred_edge (EXIT_BLOCK_PTR);
+  for (bsi = gsi_last_bb (e->src); !gsi_end_p (bsi); gsi_prev (&bsi))
+    {
+      gimple stmt = gsi_stmt (bsi);
+      if (gimple_code (stmt) == GIMPLE_LABEL
+         || is_gimple_debug (stmt)
+         || gimple_clobber_p (stmt))
+       ;
+      else if (gimple_code (stmt) == GIMPLE_ASSIGN
+              && found_return
+              && gimple_assign_single_p (stmt)
+              && (auto_var_in_fn_p (gimple_assign_rhs1 (stmt),
+                                    current_function_decl)
+                  || is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
+              && retval == gimple_assign_lhs (stmt))
+       ;
+      else if (gimple_code (stmt) == GIMPLE_RETURN)
+       {
+         found_return = true;
+         retval = gimple_return_retval (stmt);
+       }
+      else
+       break;
+    }
+  if (gsi_end_p (bsi) && found_return)
+    return_bb = e->src;
 
-       for (bsi = gsi_last_bb (e->src); !gsi_end_p (bsi); gsi_prev (&bsi))
-         {
-           gimple stmt = gsi_stmt (bsi);
-           if (gimple_code (stmt) == GIMPLE_LABEL
-               || is_gimple_debug (stmt))
-             ;
-           else if (gimple_code (stmt) == GIMPLE_ASSIGN
-                    && found_return
-                    && gimple_assign_single_p (stmt)
-                    && (auto_var_in_fn_p (gimple_assign_rhs1 (stmt),
-                                          current_function_decl)
-                        || is_gimple_min_invariant
-                             (gimple_assign_rhs1 (stmt)))
-                    && retval == gimple_assign_lhs (stmt))
-             ;
-           else if (gimple_code (stmt) == GIMPLE_RETURN)
-             {
-               found_return = true;
-               retval = gimple_return_retval (stmt);
-             }
-           else
-             break;
-         }
-       if (gsi_end_p (bsi) && found_return)
-         {
-           if (retval)
-             return e->src;
-           else
-             return_bb = e->src;
-         }
-      }
   return return_bb;
 }
 
-/* Given return basicblock RETURN_BB, see where return value is really
+/* Given return basic block RETURN_BB, see where return value is really
    stored.  */
 static tree
 find_retval (basic_block return_bb)
@@ -549,7 +659,8 @@ find_retval (basic_block return_bb)
   for (bsi = gsi_start_bb (return_bb); !gsi_end_p (bsi); gsi_next (&bsi))
     if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
       return gimple_return_retval (gsi_stmt (bsi));
-    else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN)
+    else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN
+            && !gimple_clobber_p (gsi_stmt (bsi)))
       return gimple_assign_rhs1 (gsi_stmt (bsi));
   return NULL;
 }
@@ -625,16 +736,18 @@ visit_bb (basic_block bb, basic_block return_bb,
       if (is_gimple_debug (stmt))
        continue;
 
+      if (gimple_clobber_p (stmt))
+       continue;
+
       /* FIXME: We can split regions containing EH.  We can not however
         split RESX, EH_DISPATCH and EH_POINTER referring to same region
         into different partitions.  This would require tracking of
         EH regions and checking in consider_split_point if they 
         are not used elsewhere.  */
-      if (gimple_code (stmt) == GIMPLE_RESX
-         && stmt_can_throw_external (stmt))
+      if (gimple_code (stmt) == GIMPLE_RESX)
        {
          if (dump_file && (dump_flags & TDF_DETAILS))
-           fprintf (dump_file, "Cannot split: external resx.\n");
+           fprintf (dump_file, "Cannot split: resx.\n");
          can_split = false;
        }
       if (gimple_code (stmt) == GIMPLE_EH_DISPATCH)
@@ -657,6 +770,7 @@ visit_bb (basic_block bb, basic_block return_bb,
             way to store builtin_stack_save result in non-SSA variable
             since all calls to those are compiler generated.  */
          case BUILT_IN_APPLY:
+         case BUILT_IN_APPLY_ARGS:
          case BUILT_IN_VA_START:
            if (dump_file && (dump_flags & TDF_DETAILS))
              fprintf (dump_file,
@@ -703,7 +817,7 @@ visit_bb (basic_block bb, basic_block return_bb,
                                                   mark_nonssa_use,
                                                   mark_nonssa_use);
     }
-  /* Record also uses comming from PHI operand in return BB.  */
+  /* Record also uses coming from PHI operand in return BB.  */
   FOR_EACH_EDGE (e, ei, bb->succs)
     if (e->dest == return_bb)
       {
@@ -741,11 +855,11 @@ typedef struct
   bitmap bbs_visited;
 
   /* Last examined edge in DFS walk.  Since we walk unoriented graph,
-     the value is up to sum of incomming and outgoing edges of BB.  */
+     the value is up to sum of incoming and outgoing edges of BB.  */
   unsigned int edge_num;
 
   /* Stack entry index of earliest BB reachable from current BB
-     or any BB visited later in DFS valk.  */
+     or any BB visited later in DFS walk.  */
   int earliest;
 
   /* Overall time and size of all BBs reached from this BB in DFS walk.  */
@@ -888,8 +1002,8 @@ find_split_points (int overall_time, int overall_size)
                   && (intptr_t)dest->aux < entry->earliest)
            entry->earliest = (intptr_t)dest->aux;
        }
-      /* We are done with examing the edges. pop off the value from stack and
-        merge stuff we cummulate during the walk.  */
+      /* We are done with examining the edges.  Pop off the value from stack
+        and merge stuff we accumulate during the walk.  */
       else if (entry->bb != ENTRY_BLOCK_PTR)
        {
          stack_entry *prev = VEC_index (stack_entry, stack,
@@ -930,10 +1044,10 @@ static void
 split_function (struct split_point *split_point)
 {
   VEC (tree, heap) *args_to_pass = NULL;
-  bitmap args_to_skip = BITMAP_ALLOC (NULL);
+  bitmap args_to_skip;
   tree parm;
   int num = 0;
-  struct cgraph_node *node;
+  struct cgraph_node *node, *cur_node = cgraph_get_node (current_function_decl);
   basic_block return_bb = find_return_bb ();
   basic_block call_bb;
   gimple_stmt_iterator gsi;
@@ -943,7 +1057,6 @@ split_function (struct split_point *split_point)
   tree retval = NULL, real_retval = NULL;
   bool split_part_return_p = false;
   gimple last_stmt = NULL;
-  bool conv_needed = false;
   unsigned int i;
   tree arg;
 
@@ -953,23 +1066,40 @@ split_function (struct split_point *split_point)
       dump_split_point (dump_file, split_point);
     }
 
+  if (cur_node->local.can_change_signature)
+    args_to_skip = BITMAP_ALLOC (NULL);
+  else
+    args_to_skip = NULL;
+
   /* Collect the parameters of new function and args_to_skip bitmap.  */
   for (parm = DECL_ARGUMENTS (current_function_decl);
        parm; parm = DECL_CHAIN (parm), num++)
-    if (!is_gimple_reg (parm)
-       || !gimple_default_def (cfun, parm)
-       || !bitmap_bit_p (split_point->ssa_names_to_pass,
-                         SSA_NAME_VERSION (gimple_default_def (cfun, parm))))
+    if (args_to_skip
+       && (!is_gimple_reg (parm)
+           || !gimple_default_def (cfun, parm)
+           || !bitmap_bit_p (split_point->ssa_names_to_pass,
+                             SSA_NAME_VERSION (gimple_default_def (cfun,
+                                                                   parm)))))
       bitmap_set_bit (args_to_skip, num);
     else
       {
-       arg = gimple_default_def (cfun, parm);
-       if (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm))
-           != TYPE_MAIN_VARIANT (TREE_TYPE (arg)))
+       /* This parm might not have been used up to now, but is going to be
+          used, hence register it.  */
+       add_referenced_var (parm);
+       if (is_gimple_reg (parm))
          {
-           conv_needed = true;
-           arg = fold_convert (DECL_ARG_TYPE (parm), arg);
+           arg = gimple_default_def (cfun, parm);
+           if (!arg)
+             {
+               arg = make_ssa_name (parm, gimple_build_nop ());
+               set_default_def (parm, arg);
+             }
          }
+       else
+         arg = parm;
+
+       if (!useless_type_conversion_p (DECL_ARG_TYPE (parm), TREE_TYPE (arg)))
+         arg = fold_convert (DECL_ARG_TYPE (parm), arg);
        VEC_safe_push (tree, heap, args_to_pass, arg);
       }
 
@@ -1016,26 +1146,58 @@ split_function (struct split_point *split_point)
       e->probability = REG_BR_PROB_BASE;
       e->count = new_return_bb->count;
       bitmap_set_bit (split_point->split_bbs, new_return_bb->index);
-      /* We change CFG in a way tree-inline is not able to compensate on while
-        updating PHIs.  There are only virtuals in return_bb, so recompute
-        them.  */
+    }
+  /* When we pass around the value, use existing return block.  */
+  else
+    bitmap_set_bit (split_point->split_bbs, return_bb->index);
+
+  /* If RETURN_BB has virtual operand PHIs, they must be removed and the
+     virtual operand marked for renaming as we change the CFG in a way that
+     tree-inline is not able to compensate for.
+
+     Note this can happen whether or not we have a return value.  If we have
+     a return value, then RETURN_BB may have PHIs for real operands too.  */
+  if (return_bb != EXIT_BLOCK_PTR)
+    {
+      bool phi_p = false;
       for (gsi = gsi_start_phis (return_bb); !gsi_end_p (gsi);)
        {
          gimple stmt = gsi_stmt (gsi);
-         gcc_assert (!is_gimple_reg (gimple_phi_result (stmt)));
+         if (is_gimple_reg (gimple_phi_result (stmt)))
+           {
+             gsi_next (&gsi);
+             continue;
+           }
          mark_virtual_phi_result_for_renaming (stmt);
          remove_phi_node (&gsi, true);
+         phi_p = true;
        }
+      /* In reality we have to rename the reaching definition of the
+        virtual operand at return_bb as we will eventually release it
+        when we remove the code region we outlined.
+        So we have to rename all immediate virtual uses of that region
+        if we didn't see a PHI definition yet.  */
+      /* ???  In real reality we want to set the reaching vdef of the
+         entry of the SESE region as the vuse of the call and the reaching
+        vdef of the exit of the SESE region as the vdef of the call.  */
+      if (!phi_p)
+       for (gsi = gsi_start_bb (return_bb); !gsi_end_p (gsi); gsi_next (&gsi))
+         {
+           gimple stmt = gsi_stmt (gsi);
+           if (gimple_vuse (stmt))
+             {
+               gimple_set_vuse (stmt, NULL_TREE);
+               update_stmt (stmt);
+             }
+           if (gimple_vdef (stmt))
+             break;
+         }
     }
-  /* When we pass aorund the value, use existing return block.  */
-  else
-    bitmap_set_bit (split_point->split_bbs, return_bb->index);
 
   /* Now create the actual clone.  */
   rebuild_cgraph_edges ();
-  node = cgraph_function_versioning (cgraph_node (current_function_decl),
-                                    NULL, NULL,
-                                    args_to_skip,
+  node = cgraph_function_versioning (cur_node, NULL, NULL, args_to_skip,
+                                    !split_part_return_p,
                                     split_point->split_bbs,
                                     split_point->entry_bb, "part");
   /* For usual cloning it is enough to clear builtin only when signature
@@ -1046,7 +1208,7 @@ split_function (struct split_point *split_point)
       DECL_BUILT_IN_CLASS (node->decl) = NOT_BUILT_IN;
       DECL_FUNCTION_CODE (node->decl) = (enum built_in_function) 0;
     }
-  cgraph_node_remove_callees (cgraph_node (current_function_decl));
+  cgraph_node_remove_callees (cur_node);
   if (!split_part_return_p)
     TREE_THIS_VOLATILE (node->decl) = 1;
   if (dump_file)
@@ -1068,14 +1230,13 @@ split_function (struct split_point *split_point)
 
   /* Produce the call statement.  */
   gsi = gsi_last_bb (call_bb);
-  if (conv_needed)
-    FOR_EACH_VEC_ELT (tree, args_to_pass, i, arg)
-      if (!is_gimple_val (arg))
-       {
-         arg = force_gimple_operand_gsi (&gsi, arg, true, NULL_TREE,
-                                         false, GSI_NEW_STMT);
-         VEC_replace (tree, args_to_pass, i, arg);
-       }
+  FOR_EACH_VEC_ELT (tree, args_to_pass, i, arg)
+    if (!is_gimple_val (arg))
+      {
+       arg = force_gimple_operand_gsi (&gsi, arg, true, NULL_TREE,
+                                       false, GSI_CONTINUE_LINKING);
+       VEC_replace (tree, args_to_pass, i, arg);
+      }
   call = gimple_build_call_vec (node->decl, args_to_pass);
   gimple_set_block (call, DECL_INITIAL (current_function_decl));
 
@@ -1139,7 +1300,8 @@ split_function (struct split_point *split_point)
                            gimple_return_set_retval (gsi_stmt (bsi), retval);
                            break;
                          }
-                       else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN)
+                       else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN
+                                && !gimple_clobber_p (gsi_stmt (bsi)))
                          {
                            gimple_assign_set_rhs1 (gsi_stmt (bsi), retval);
                            break;
@@ -1148,11 +1310,31 @@ split_function (struct split_point *split_point)
                    }
                }
              if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
-               gimple_call_set_lhs (call, build_simple_mem_ref (retval));
+               {
+                 gimple_call_set_lhs (call, build_simple_mem_ref (retval));
+                 gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+               }
              else
-               gimple_call_set_lhs (call, retval);
+               {
+                 tree restype;
+                 restype = TREE_TYPE (DECL_RESULT (current_function_decl));
+                 gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+                 if (!useless_type_conversion_p (TREE_TYPE (retval), restype))
+                   {
+                     gimple cpy;
+                     tree tem = create_tmp_reg (restype, NULL);
+                     tem = make_ssa_name (tem, call);
+                     cpy = gimple_build_assign_with_ops (NOP_EXPR, retval,
+                                                         tem, NULL_TREE);
+                     gsi_insert_after (&gsi, cpy, GSI_NEW_STMT);
+                     retval = tem;
+                   }
+                 gimple_call_set_lhs (call, retval);
+                 update_stmt (call);
+               }
            }
-          gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+         else
+           gsi_insert_after (&gsi, call, GSI_NEW_STMT);
        }
       /* We don't use return block (there is either no return in function or
         multiple of them).  So create new basic block with return statement.
@@ -1206,7 +1388,7 @@ split_function (struct split_point *split_point)
     }
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
-  compute_inline_parameters (node);
+  compute_inline_parameters (node, true);
 }
 
 /* Execute function splitting pass.  */
@@ -1218,12 +1400,13 @@ execute_split_functions (void)
   basic_block bb;
   int overall_time = 0, overall_size = 0;
   int todo = 0;
-  struct cgraph_node *node = cgraph_node (current_function_decl);
+  struct cgraph_node *node = cgraph_get_node (current_function_decl);
 
-  if (flags_from_decl_or_type (current_function_decl) & ECF_NORETURN)
+  if (flags_from_decl_or_type (current_function_decl)
+      & (ECF_NORETURN|ECF_MALLOC))
     {
       if (dump_file)
-       fprintf (dump_file, "Not splitting: noreturn function.\n");
+       fprintf (dump_file, "Not splitting: noreturn/malloc function.\n");
       return 0;
     }
   if (MAIN_NAME_P (DECL_NAME (current_function_decl)))
@@ -1234,16 +1417,16 @@ execute_split_functions (void)
     }
   /* This can be relaxed; function might become inlinable after splitting
      away the uninlinable part.  */
-  if (!node->local.inlinable)
+  if (!inline_summary (node)->inlinable)
     {
       if (dump_file)
        fprintf (dump_file, "Not splitting: not inlinable.\n");
       return 0;
     }
-  if (node->local.disregard_inline_limits)
+  if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
     {
       if (dump_file)
-       fprintf (dump_file, "Not splitting: disregading inline limits.\n");
+       fprintf (dump_file, "Not splitting: disregarding inline limits.\n");
       return 0;
     }
   /* This can be relaxed; most of versioning tests actually prevents
@@ -1265,7 +1448,9 @@ execute_split_functions (void)
   /* See if it makes sense to try to split.
      It makes sense to split if we inline, that is if we have direct calls to
      handle or direct calls are possibly going to appear as result of indirect
-     inlining or LTO.
+     inlining or LTO.  Also handle -fprofile-generate as LTO to allow non-LTO
+     training for LTO -fprofile-use build.
+
      Note that we are not completely conservative about disqualifying functions
      called once.  It is possible that the caller is called more then once and
      then inlining would still benefit.  */
@@ -1289,6 +1474,10 @@ execute_split_functions (void)
       return 0;
     }
 
+  /* Initialize bitmap to track forbidden calls.  */
+  forbidden_dominators = BITMAP_ALLOC (NULL);
+  calculate_dominance_info (CDI_DOMINATORS);
+
   /* Compute local info about basic blocks and determine function size/time.  */
   VEC_safe_grow_cleared (bb_info, heap, bb_info_vec, last_basic_block + 1);
   memset (&best_split_point, 0, sizeof (best_split_point));
@@ -1310,6 +1499,7 @@ execute_split_functions (void)
          this_time = estimate_num_insns (stmt, &eni_time_weights) * freq;
          size += this_size;
          time += this_time;
+         check_forbidden_calls (stmt);
 
          if (dump_file && (dump_flags & TDF_DETAILS))
            {
@@ -1331,15 +1521,21 @@ execute_split_functions (void)
       BITMAP_FREE (best_split_point.split_bbs);
       todo = TODO_update_ssa | TODO_cleanup_cfg;
     }
+  BITMAP_FREE (forbidden_dominators);
   VEC_free (bb_info, heap, bb_info_vec);
   bb_info_vec = NULL;
   return todo;
 }
 
+/* Gate function splitting pass.  When doing profile feedback, we want
+   to execute the pass after profiling is read.  So disable one in 
+   early optimization.  */
+
 static bool
 gate_split_functions (void)
 {
-  return flag_partial_inlining;
+  return (flag_partial_inlining
+         && !profile_arc_flag && !flag_branch_probabilities);
 }
 
 struct gimple_opt_pass pass_split_functions =
@@ -1357,6 +1553,47 @@ struct gimple_opt_pass pass_split_functions =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  TODO_verify_all                              /* todo_flags_finish */
+ }
+};
+
+/* Gate feedback driven function splitting pass.
+   We don't need to split when profiling at all, we are producing
+   lousy code anyway.  */
+
+static bool
+gate_feedback_split_functions (void)
+{
+  return (flag_partial_inlining
+         && flag_branch_probabilities);
+}
+
+/* Execute function splitting pass.  */
+
+static unsigned int
+execute_feedback_split_functions (void)
+{
+  unsigned int retval = execute_split_functions ();
+  if (retval)
+    retval |= TODO_rebuild_cgraph_edges;
+  return retval;
+}
+
+struct gimple_opt_pass pass_feedback_split_functions =
+{
+ {
+  GIMPLE_PASS,
+  "feedback_fnsplit",                  /* name */
+  gate_feedback_split_functions,       /* gate */
+  execute_feedback_split_functions,    /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_IPA_FNSPLIT,                      /* tv_id */
+  PROP_cfg,                            /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_verify_all                              /* todo_flags_finish */
  }
 };