re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / ipa-split.c
index 187dc988489b7e44d54694484a0c16a08f1cbcc3..13d9a6447e5248a03bdb2b8ea0faeafbf94dd918 100644 (file)
@@ -1,5 +1,5 @@
 /* Function splitting pass
-   Copyright (C) 2010-2014 Free Software Foundation, Inc.
+   Copyright (C) 2010-2015 Free Software Foundation, Inc.
    Contributed by Jan Hubicka  <jh@suse.cz>
 
 This file is part of GCC.
@@ -77,32 +77,52 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "alias.h"
+#include "symtab.h"
+#include "options.h"
 #include "tree.h"
+#include "fold-const.h"
+#include "predict.h"
+#include "tm.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
 #include "basic-block.h"
 #include "tree-ssa-alias.h"
 #include "internal-fn.h"
 #include "gimple-expr.h"
-#include "is-a.h"
 #include "gimple.h"
 #include "stringpool.h"
-#include "expr.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
 #include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
 #include "gimplify-me.h"
 #include "gimple-walk.h"
 #include "target.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
 #include "ipa-prop.h"
 #include "gimple-ssa.h"
 #include "tree-cfg.h"
 #include "tree-phinodes.h"
 #include "ssa-iterators.h"
-#include "stringpool.h"
 #include "tree-ssanames.h"
 #include "tree-into-ssa.h"
 #include "tree-dfa.h"
 #include "tree-pass.h"
-#include "flags.h"
 #include "diagnostic.h"
 #include "tree-dump.h"
 #include "tree-inline.h"
@@ -110,6 +130,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "ipa-inline.h"
 #include "cfgloop.h"
+#include "tree-chkp.h"
 
 /* Per basic block info.  */
 
@@ -117,9 +138,9 @@ typedef struct
 {
   unsigned int size;
   unsigned int time;
-} bb_info;
+} split_bb_info;
 
-static vec<bb_info> bb_info_vec;
+static vec<split_bb_info> bb_info_vec;
 
 /* Description of split point.  */
 
@@ -151,6 +172,7 @@ struct split_point best_split_point;
 static bitmap forbidden_dominators;
 
 static tree find_retval (basic_block return_bb);
+static tree find_retbnd (basic_block return_bb);
 
 /* Callback for walk_stmt_load_store_addr_ops.  If T is non-SSA automatic
    variable, check it if it is present in bitmap passed via DATA.  */
@@ -167,7 +189,11 @@ test_nonssa_use (gimple, tree t, tree, void *data)
       || (TREE_CODE (t) == VAR_DECL
          && auto_var_in_fn_p (t, current_function_decl))
       || TREE_CODE (t) == RESULT_DECL
-      || TREE_CODE (t) == LABEL_DECL)
+        /* Normal labels are part of CFG and will be handled gratefuly.
+           Forced labels however can be used directly by statements and
+           need to stay in one partition along with their uses.  */
+      || (TREE_CODE (t) == LABEL_DECL
+         && FORCED_LABEL (t)))
     return bitmap_bit_p ((bitmap)data, DECL_UID (t));
 
   /* For DECL_BY_REFERENCE, the return value is actually a pointer.  We want
@@ -213,6 +239,7 @@ verify_non_ssa_vars (struct split_point *current, bitmap non_ssa_vars,
   edge e;
   edge_iterator ei;
   bool ok = true;
+  basic_block bb;
 
   FOR_EACH_EDGE (e, ei, current->entry_bb->preds)
     if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
@@ -224,9 +251,7 @@ verify_non_ssa_vars (struct split_point *current, bitmap non_ssa_vars,
 
   while (!worklist.is_empty ())
     {
-      gimple_stmt_iterator bsi;
-      basic_block bb = worklist.pop ();
-
+      bb = worklist.pop ();
       FOR_EACH_EDGE (e, ei, bb->preds)
        if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
            && bitmap_set_bit (seen, e->src->index))
@@ -235,7 +260,8 @@ verify_non_ssa_vars (struct split_point *current, bitmap non_ssa_vars,
                                                e->src->index));
            worklist.safe_push (e->src);
          }
-      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+      for (gimple_stmt_iterator bsi = gsi_start_bb (bb); !gsi_end_p (bsi);
+          gsi_next (&bsi))
        {
          gimple stmt = gsi_stmt (bsi);
          if (is_gimple_debug (stmt))
@@ -247,15 +273,16 @@ verify_non_ssa_vars (struct split_point *current, bitmap non_ssa_vars,
              ok = false;
              goto done;
            }
-         if (gimple_code (stmt) == GIMPLE_LABEL
-             && test_nonssa_use (stmt, gimple_label_label (stmt),
-                                 NULL_TREE, non_ssa_vars))
-         {
-           ok = false;
-           goto done;
-         }
+         if (glabel *label_stmt = dyn_cast <glabel *> (stmt))
+           if (test_nonssa_use (stmt, gimple_label_label (label_stmt),
+                                NULL_TREE, non_ssa_vars))
+             {
+               ok = false;
+               goto done;
+             }
        }
-      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+      for (gphi_iterator bsi = gsi_start_phis (bb); !gsi_end_p (bsi);
+          gsi_next (&bsi))
        {
          if (walk_stmt_load_store_addr_ops
              (gsi_stmt (bsi), non_ssa_vars, test_nonssa_use, test_nonssa_use,
@@ -269,10 +296,11 @@ verify_non_ssa_vars (struct split_point *current, bitmap non_ssa_vars,
        {
          if (e->dest != return_bb)
            continue;
-         for (bsi = gsi_start_phis (return_bb); !gsi_end_p (bsi);
+         for (gphi_iterator bsi = gsi_start_phis (return_bb);
+              !gsi_end_p (bsi);
               gsi_next (&bsi))
            {
-             gimple stmt = gsi_stmt (bsi);
+             gphi *stmt = bsi.phi ();
              tree op = gimple_phi_arg_def (stmt, e->dest_idx);
 
              if (virtual_operand_p (gimple_phi_result (stmt)))
@@ -286,6 +314,29 @@ verify_non_ssa_vars (struct split_point *current, bitmap non_ssa_vars,
            }
        }
     }
+
+  /* Verify that the rest of function does not define any label
+     used by the split part.  */
+  FOR_EACH_BB_FN (bb, cfun)
+    if (!bitmap_bit_p (current->split_bbs, bb->index)
+       && !bitmap_bit_p (seen, bb->index))
+      {
+        gimple_stmt_iterator bsi;
+        for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+         if (glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (bsi)))
+           {
+             if (test_nonssa_use (label_stmt,
+                                  gimple_label_label (label_stmt),
+                                  NULL_TREE, non_ssa_vars))
+               {
+                 ok = false;
+                 goto done;
+               }
+           }
+         else
+           break;
+      }
+    
 done:
   BITMAP_FREE (seen);
   worklist.release ();
@@ -324,9 +375,10 @@ check_forbidden_calls (gimple stmt)
       basic_block use_bb, forbidden_bb;
       enum tree_code code;
       edge true_edge, false_edge;
-      gimple use_stmt = USE_STMT (use_p);
+      gcond *use_stmt;
 
-      if (gimple_code (use_stmt) != GIMPLE_COND)
+      use_stmt = dyn_cast <gcond *> (USE_STMT (use_p));
+      if (!use_stmt)
        continue;
 
       /* Assuming canonical form for GIMPLE_COND here, with constant
@@ -370,6 +422,21 @@ dominated_by_forbidden (basic_block bb)
   return false;
 }
 
+/* For give split point CURRENT and return block RETURN_BB return 1
+   if ssa name VAL is set by split part and 0 otherwise.  */
+static bool
+split_part_set_ssa_name_p (tree val, struct split_point *current,
+                          basic_block return_bb)
+{
+  if (TREE_CODE (val) != SSA_NAME)
+    return false;
+
+  return (!SSA_NAME_IS_DEFAULT_DEF (val)
+         && (bitmap_bit_p (current->split_bbs,
+                           gimple_bb (SSA_NAME_DEF_STMT (val))->index)
+             || gimple_bb (SSA_NAME_DEF_STMT (val)) == return_bb));
+}
+
 /* 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.  */
@@ -383,10 +450,11 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
   unsigned int call_overhead;
   edge e;
   edge_iterator ei;
-  gimple_stmt_iterator bsi;
+  gphi_iterator bsi;
   unsigned int i;
   int incoming_freq = 0;
   tree retval;
+  tree retbnd;
   bool back_edge = false;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -440,7 +508,7 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
      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);
+      gphi *stmt = bsi.phi ();
       tree val = NULL;
 
       if (virtual_operand_p (gimple_phi_result (stmt)))
@@ -488,13 +556,14 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
                               SSA_NAME_VERSION (ddef)))
            {
              if (!VOID_TYPE_P (TREE_TYPE (parm)))
-               call_overhead += estimate_move_cost (TREE_TYPE (parm));
+               call_overhead += estimate_move_cost (TREE_TYPE (parm), false);
              num_args++;
            }
        }
     }
   if (!VOID_TYPE_P (TREE_TYPE (current_function_decl)))
-    call_overhead += estimate_move_cost (TREE_TYPE (current_function_decl));
+    call_overhead += estimate_move_cost (TREE_TYPE (current_function_decl),
+                                        false);
 
   if (current->split_size <= call_overhead)
     {
@@ -514,6 +583,31 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
       return;
     }
 
+  /* Splitting functions brings the target out of comdat group; this will
+     lead to code duplication if the function is reused by other unit.
+     Limit this duplication.  This is consistent with limit in tree-sra.c  
+     FIXME: with LTO we ought to be able to do better!  */
+  if (DECL_ONE_ONLY (current_function_decl)
+      && current->split_size >= (unsigned int) MAX_INLINE_INSNS_AUTO)
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file,
+                "  Refused: function is COMDAT and tail is too large\n");
+      return;
+    }
+  /* For comdat functions also reject very small tails; those will likely get
+     inlined back and we do not want to risk the duplication overhead.
+     FIXME: with LTO we ought to be able to do better!  */
+  if (DECL_ONE_ONLY (current_function_decl)
+      && current->split_size
+        <= (unsigned int) PARAM_VALUE (PARAM_EARLY_INLINING_INSNS) / 2)
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file,
+                "  Refused: function is COMDAT and tail is too small\n");
+      return;
+    }
+
   /* FIXME: we currently can pass only SSA function parameters to the split
      arguments.  Once parm_adjustment infrastructure is supported by cloning,
      we can pass more than that.  */
@@ -574,10 +668,7 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
        = bitmap_bit_p (non_ssa_vars, DECL_UID (SSA_NAME_VAR (retval)));
   else if (TREE_CODE (retval) == SSA_NAME)
     current->split_part_set_retval
-      = (!SSA_NAME_IS_DEFAULT_DEF (retval)
-        && (bitmap_bit_p (current->split_bbs,
-                         gimple_bb (SSA_NAME_DEF_STMT (retval))->index)
-            || gimple_bb (SSA_NAME_DEF_STMT (retval)) == return_bb));
+      = split_part_set_ssa_name_p (retval, current, return_bb);
   else if (TREE_CODE (retval) == PARM_DECL)
     current->split_part_set_retval = false;
   else if (TREE_CODE (retval) == VAR_DECL
@@ -587,19 +678,42 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
   else
     current->split_part_set_retval = true;
 
+  /* See if retbnd used by return bb is computed by header or split part.  */
+  retbnd = find_retbnd (return_bb);
+  if (retbnd)
+    {
+      bool split_part_set_retbnd
+       = split_part_set_ssa_name_p (retbnd, current, return_bb);
+
+      /* If we have both return value and bounds then keep their definitions
+        in a single function.  We use SSA names to link returned bounds and
+        value and therefore do not handle cases when result is passed by
+        reference (which should not be our case anyway since bounds are
+        returned for pointers only).  */
+      if ((DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))
+          && current->split_part_set_retval)
+         || split_part_set_retbnd != current->split_part_set_retval)
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file,
+                    "  Refused: split point splits return value and bounds\n");
+         return;
+       }
+    }
+
   /* 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_FOR_FN (cfun))
     {
-      gimple_stmt_iterator psi;
+      gphi_iterator psi;
 
       for (psi = gsi_start_phis (return_bb); !gsi_end_p (psi); gsi_next (&psi))
-       if (!virtual_operand_p (gimple_phi_result (gsi_stmt (psi)))
+       if (!virtual_operand_p (gimple_phi_result (psi.phi ()))
            && !(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)))
+                && SSA_NAME_DEF_STMT (retval) == psi.phi ()))
          {
            if (dump_file && (dump_flags & TDF_DETAILS))
              fprintf (dump_file,
@@ -640,7 +754,8 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
    of the form:
    <retval> = tmp_var;
    return <retval>
-   but return_bb can not be more complex than this.
+   but return_bb can not be more complex than this (except for
+   -fsanitize=thread we allow TSAN_FUNC_EXIT () internal call in there).
    If nothing is found, return the exit block.
 
    When there are multiple RETURN statement, chose one with return value,
@@ -680,11 +795,18 @@ find_return_bb (void)
                   || is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
               && retval == gimple_assign_lhs (stmt))
        ;
-      else if (gimple_code (stmt) == GIMPLE_RETURN)
+      else if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
        {
          found_return = true;
-         retval = gimple_return_retval (stmt);
+         retval = gimple_return_retval (return_stmt);
        }
+      /* For -fsanitize=thread, allow also TSAN_FUNC_EXIT () in the return
+        bb.  */
+      else if ((flag_sanitize & SANITIZE_THREAD)
+              && is_gimple_call (stmt)
+              && gimple_call_internal_p (stmt)
+              && gimple_call_internal_fn (stmt) == IFN_TSAN_FUNC_EXIT)
+       ;
       else
        break;
     }
@@ -701,14 +823,26 @@ find_retval (basic_block return_bb)
 {
   gimple_stmt_iterator bsi;
   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));
+    if (greturn *return_stmt = dyn_cast <greturn *> (gsi_stmt (bsi)))
+      return gimple_return_retval (return_stmt);
     else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN
             && !gimple_clobber_p (gsi_stmt (bsi)))
       return gimple_assign_rhs1 (gsi_stmt (bsi));
   return NULL;
 }
 
+/* Given return basic block RETURN_BB, see where return bounds are really
+   stored.  */
+static tree
+find_retbnd (basic_block return_bb)
+{
+  gimple_stmt_iterator bsi;
+  for (bsi = gsi_last_bb (return_bb); !gsi_end_p (bsi); gsi_prev (&bsi))
+    if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
+      return gimple_return_retbnd (gsi_stmt (bsi));
+  return NULL;
+}
+
 /* Callback for walk_stmt_load_store_addr_ops.  If T is non-SSA automatic
    variable, mark it as used in bitmap passed via DATA.
    Return true when access to T prevents splitting the function.  */
@@ -734,7 +868,8 @@ mark_nonssa_use (gimple, tree t, tree, void *data)
   if ((TREE_CODE (t) == VAR_DECL
        && auto_var_in_fn_p (t, current_function_decl))
       || TREE_CODE (t) == RESULT_DECL
-      || TREE_CODE (t) == LABEL_DECL)
+      || (TREE_CODE (t) == LABEL_DECL
+         && FORCED_LABEL (t)))
     bitmap_set_bit ((bitmap)data, DECL_UID (t));
 
   /* For DECL_BY_REFERENCE, the return value is actually a pointer.  We want
@@ -766,12 +901,12 @@ visit_bb (basic_block bb, basic_block return_bb,
          bitmap set_ssa_names, bitmap used_ssa_names,
          bitmap non_ssa_vars)
 {
-  gimple_stmt_iterator bsi;
   edge e;
   edge_iterator ei;
   bool can_split = true;
 
-  for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+  for (gimple_stmt_iterator bsi = gsi_start_bb (bb); !gsi_end_p (bsi);
+       gsi_next (&bsi))
     {
       gimple stmt = gsi_stmt (bsi);
       tree op;
@@ -840,9 +975,10 @@ visit_bb (basic_block bb, basic_block return_bb,
                                                   mark_nonssa_use,
                                                   mark_nonssa_use);
     }
-  for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+  for (gphi_iterator bsi = gsi_start_phis (bb); !gsi_end_p (bsi);
+       gsi_next (&bsi))
     {
-      gimple stmt = gsi_stmt (bsi);
+      gphi *stmt = bsi.phi ();
       unsigned int i;
 
       if (virtual_operand_p (gimple_phi_result (stmt)))
@@ -864,9 +1000,11 @@ visit_bb (basic_block bb, basic_block return_bb,
   FOR_EACH_EDGE (e, ei, bb->succs)
     if (e->dest == return_bb)
       {
-       for (bsi = gsi_start_phis (return_bb); !gsi_end_p (bsi); gsi_next (&bsi))
+       for (gphi_iterator bsi = gsi_start_phis (return_bb);
+            !gsi_end_p (bsi);
+            gsi_next (&bsi))
          {
-           gimple stmt = gsi_stmt (bsi);
+           gphi *stmt = bsi.phi ();
            tree op = gimple_phi_arg_def (stmt, e->dest_idx);
 
            if (virtual_operand_p (gimple_phi_result (stmt)))
@@ -929,12 +1067,11 @@ typedef struct
    the component used by consider_split.  */
 
 static void
-find_split_points (int overall_time, int overall_size)
+find_split_points (basic_block return_bb, int overall_time, int overall_size)
 {
   stack_entry first;
   vec<stack_entry> stack = vNULL;
   basic_block bb;
-  basic_block return_bb = find_return_bb ();
   struct split_point current;
 
   current.header_time = overall_time;
@@ -1081,21 +1218,21 @@ find_split_points (int overall_time, int overall_size)
 /* Split function at SPLIT_POINT.  */
 
 static void
-split_function (struct split_point *split_point)
+split_function (basic_block return_bb, struct split_point *split_point,
+               bool add_tsan_func_exit)
 {
   vec<tree> args_to_pass = vNULL;
   bitmap args_to_skip;
   tree parm;
   int num = 0;
-  struct cgraph_node *node, *cur_node = cgraph_get_node (current_function_decl);
-  basic_block return_bb = find_return_bb ();
+  cgraph_node *node, *cur_node = cgraph_node::get (current_function_decl);
   basic_block call_bb;
-  gimple_stmt_iterator gsi;
-  gimple call;
+  gcall *call, *tsan_func_exit_call = NULL;
   edge e;
   edge_iterator ei;
-  tree retval = NULL, real_retval = NULL;
+  tree retval = NULL, real_retval = NULL, retbnd = NULL;
   bool split_part_return_p = false;
+  bool with_bounds = chkp_function_instrumented_p (current_function_decl);
   gimple last_stmt = NULL;
   unsigned int i;
   tree arg, ddef;
@@ -1177,8 +1314,7 @@ split_function (struct split_point *split_point)
       e = make_edge (new_return_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
       e->probability = REG_BR_PROB_BASE;
       e->count = new_return_bb->count;
-      if (current_loops)
-       add_bb_to_loop (new_return_bb, current_loops->tree_root);
+      add_bb_to_loop (new_return_bb, current_loops->tree_root);
       bitmap_set_bit (split_point->split_bbs, new_return_bb->index);
     }
   /* When we pass around the value, use existing return block.  */
@@ -1194,9 +1330,10 @@ split_function (struct split_point *split_point)
   if (return_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
     {
       bool phi_p = false;
-      for (gsi = gsi_start_phis (return_bb); !gsi_end_p (gsi);)
+      for (gphi_iterator gsi = gsi_start_phis (return_bb);
+          !gsi_end_p (gsi);)
        {
-         gimple stmt = gsi_stmt (gsi);
+         gphi *stmt = gsi.phi ();
          if (!virtual_operand_p (gimple_phi_result (stmt)))
            {
              gsi_next (&gsi);
@@ -1215,7 +1352,9 @@ split_function (struct split_point *split_point)
          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))
+       for (gimple_stmt_iterator gsi = gsi_start_bb (return_bb);
+            !gsi_end_p (gsi);
+            gsi_next (&gsi))
          {
            gimple stmt = gsi_stmt (gsi);
            if (gimple_vuse (stmt))
@@ -1229,13 +1368,12 @@ split_function (struct split_point *split_point)
     }
 
   /* Now create the actual clone.  */
-  rebuild_cgraph_edges ();
-  node = cgraph_function_versioning (cur_node, vNULL,
-                                    NULL,
-                                    args_to_skip,
-                                    !split_part_return_p,
-                                    split_point->split_bbs,
-                                    split_point->entry_bb, "part");
+  cgraph_edge::rebuild_edges ();
+  node = cur_node->create_version_clone_with_body
+    (vNULL, NULL, args_to_skip, !split_part_return_p, split_point->split_bbs,
+     split_point->entry_bb, "part");
+
+  node->split_part = true;
 
   /* Let's take a time profile for splitted function.  */
   node->tp_first_run = cur_node->tp_first_run + 1;
@@ -1248,11 +1386,17 @@ 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;
     }
+
+  /* If the original function is instrumented then it's
+     part is also instrumented.  */
+  if (with_bounds)
+    chkp_function_mark_instrumented (node->decl);
+
   /* If the original function is declared inline, there is no point in issuing
      a warning for the non-inlinable part.  */
   DECL_NO_INLINE_WARNING_P (node->decl) = 1;
-  cgraph_node_remove_callees (cur_node);
-  ipa_remove_all_references (&cur_node->ref_list);
+  cur_node->remove_callees ();
+  cur_node->remove_all_references ();
   if (!split_part_return_p)
     TREE_THIS_VOLATILE (node->decl) = 1;
   if (dump_file)
@@ -1261,7 +1405,7 @@ split_function (struct split_point *split_point)
   /* Create the basic block we place call into.  It is the entry basic block
      split after last label.  */
   call_bb = split_point->entry_bb;
-  for (gsi = gsi_start_bb (call_bb); !gsi_end_p (gsi);)
+  for (gimple_stmt_iterator gsi = gsi_start_bb (call_bb); !gsi_end_p (gsi);)
     if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
       {
        last_stmt = gsi_stmt (gsi);
@@ -1273,7 +1417,7 @@ split_function (struct split_point *split_point)
   remove_edge (e);
 
   /* Produce the call statement.  */
-  gsi = gsi_last_bb (call_bb);
+  gimple_stmt_iterator gsi = gsi_last_bb (call_bb);
   FOR_EACH_VEC_ELT (args_to_pass, i, arg)
     if (!is_gimple_val (arg))
       {
@@ -1282,6 +1426,7 @@ split_function (struct split_point *split_point)
        args_to_pass[i] = arg;
       }
   call = gimple_build_call_vec (node->decl, args_to_pass);
+  gimple_call_set_with_bounds (call, with_bounds);
   gimple_set_block (call, DECL_INITIAL (current_function_decl));
   args_to_pass.release ();
 
@@ -1370,11 +1515,18 @@ split_function (struct split_point *split_point)
          || DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))))
     gimple_call_set_return_slot_opt (call, true);
 
+  if (add_tsan_func_exit)
+    tsan_func_exit_call = gimple_build_call_internal (IFN_TSAN_FUNC_EXIT, 0);
+
   /* Update return value.  This is bit tricky.  When we do not return,
      do nothing.  When we return we might need to update return_bb
      or produce a new return statement.  */
   if (!split_part_return_p)
-    gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+    {
+      gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+      if (tsan_func_exit_call)
+       gsi_insert_after (&gsi, tsan_func_exit_call, GSI_NEW_STMT);
+    }
   else
     {
       e = make_edge (call_bb, return_bb,
@@ -1388,10 +1540,11 @@ split_function (struct split_point *split_point)
       if (return_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
        {
          real_retval = retval = find_retval (return_bb);
+         retbnd = find_retbnd (return_bb);
 
          if (real_retval && split_point->split_part_set_retval)
            {
-             gimple_stmt_iterator psi;
+             gphi_iterator psi;
 
              /* See if we need new SSA_NAME for the result.
                 When DECL_BY_REFERENCE is true, retval is actually pointer to
@@ -1404,13 +1557,13 @@ split_function (struct split_point *split_point)
                  /* See if there is PHI defining return value.  */
                  for (psi = gsi_start_phis (return_bb);
                       !gsi_end_p (psi); gsi_next (&psi))
-                   if (!virtual_operand_p (gimple_phi_result (gsi_stmt (psi))))
+                   if (!virtual_operand_p (gimple_phi_result (psi.phi ())))
                      break;
 
                  /* When there is PHI, just update its value.  */
                  if (TREE_CODE (retval) == SSA_NAME
                      && !gsi_end_p (psi))
-                   add_phi_arg (gsi_stmt (psi), retval, e, UNKNOWN_LOCATION);
+                   add_phi_arg (psi.phi (), retval, e, UNKNOWN_LOCATION);
                  /* Otherwise update the return BB itself.
                     find_return_bb allows at most one assignment to return value,
                     so update first statement.  */
@@ -1419,9 +1572,10 @@ split_function (struct split_point *split_point)
                      gimple_stmt_iterator bsi;
                      for (bsi = gsi_start_bb (return_bb); !gsi_end_p (bsi);
                           gsi_next (&bsi))
-                       if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
+                       if (greturn *return_stmt
+                             = dyn_cast <greturn *> (gsi_stmt (bsi)))
                          {
-                           gimple_return_set_retval (gsi_stmt (bsi), retval);
+                           gimple_return_set_retval (return_stmt, retval);
                            break;
                          }
                        else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN
@@ -1432,6 +1586,21 @@ split_function (struct split_point *split_point)
                          }
                      update_stmt (gsi_stmt (bsi));
                    }
+
+                 /* Replace retbnd with new one.  */
+                 if (retbnd)
+                   {
+                     gimple_stmt_iterator bsi;
+                     for (bsi = gsi_last_bb (return_bb); !gsi_end_p (bsi);
+                          gsi_prev (&bsi))
+                       if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
+                         {
+                           retbnd = copy_ssa_name (retbnd, call);
+                           gimple_return_set_retbnd (gsi_stmt (bsi), retbnd);
+                           update_stmt (gsi_stmt (bsi));
+                           break;
+                         }
+                   }
                }
              if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
                {
@@ -1446,37 +1615,45 @@ split_function (struct split_point *split_point)
                  if (!useless_type_conversion_p (TREE_TYPE (retval), restype))
                    {
                      gimple cpy;
-                     tree tem = create_tmp_reg (restype, NULL);
+                     tree tem = create_tmp_reg (restype);
                      tem = make_ssa_name (tem, call);
-                     cpy = gimple_build_assign_with_ops (NOP_EXPR, retval,
-                                                         tem, NULL_TREE);
+                     cpy = gimple_build_assign (retval, NOP_EXPR, tem);
                      gsi_insert_after (&gsi, cpy, GSI_NEW_STMT);
                      retval = tem;
                    }
+                 /* Build bndret call to obtain returned bounds.  */
+                 if (retbnd)
+                   chkp_insert_retbnd_call (retbnd, retval, &gsi);
                  gimple_call_set_lhs (call, retval);
                  update_stmt (call);
                }
            }
          else
            gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+         if (tsan_func_exit_call)
+           gsi_insert_after (&gsi, tsan_func_exit_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.
         */
       else
        {
-         gimple ret;
+         greturn *ret;
          if (split_point->split_part_set_retval
              && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
            {
              retval = DECL_RESULT (current_function_decl);
 
+             if (chkp_function_instrumented_p (current_function_decl)
+                 && BOUNDED_P (retval))
+               retbnd = create_tmp_reg (pointer_bounds_type_node);
+
              /* We use temporary register to hold value when aggregate_value_p
                 is false.  Similarly for DECL_BY_REFERENCE we must avoid extra
                 copy.  */
              if (!aggregate_value_p (retval, TREE_TYPE (current_function_decl))
                  && !DECL_BY_REFERENCE (retval))
-               retval = create_tmp_reg (TREE_TYPE (retval), NULL);
+               retval = create_tmp_reg (TREE_TYPE (retval));
              if (is_gimple_reg (retval))
                {
                  /* When returning by reference, there is only one SSA name
@@ -1494,6 +1671,11 @@ split_function (struct split_point *split_point)
                gimple_call_set_lhs (call, retval);
            }
           gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+         /* Build bndret call to obtain returned bounds.  */
+         if (retbnd)
+           chkp_insert_retbnd_call (retbnd, retval, &gsi);
+         if (tsan_func_exit_call)
+           gsi_insert_after (&gsi, tsan_func_exit_call, GSI_NEW_STMT);
          ret = gimple_build_return (retval);
          gsi_insert_after (&gsi, ret, GSI_NEW_STMT);
        }
@@ -1512,7 +1694,7 @@ execute_split_functions (void)
   basic_block bb;
   int overall_time = 0, overall_size = 0;
   int todo = 0;
-  struct cgraph_node *node = cgraph_get_node (current_function_decl);
+  struct cgraph_node *node = cgraph_node::get (current_function_decl);
 
   if (flags_from_decl_or_type (current_function_decl)
       & (ECF_NORETURN|ECF_MALLOC))
@@ -1530,7 +1712,7 @@ execute_split_functions (void)
   /* This can be relaxed; function might become inlinable after splitting
      away the uninlinable part.  */
   if (inline_edge_summary_vec.exists ()
-      && !inline_summary (node)->inlinable)
+      && !inline_summaries->get (node)->inlinable)
     {
       if (dump_file)
        fprintf (dump_file, "Not splitting: not inlinable.\n");
@@ -1571,6 +1753,7 @@ execute_split_functions (void)
        /* Local functions called once will be completely inlined most of time.  */
        || (!node->callers->next_caller && node->local.local))
       && !node->address_taken
+      && !node->has_aliases_p ()
       && (!flag_lto || !node->externally_visible))
     {
       if (dump_file)
@@ -1601,6 +1784,8 @@ execute_split_functions (void)
   /* Compute local info about basic blocks and determine function size/time.  */
   bb_info_vec.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
   memset (&best_split_point, 0, sizeof (best_split_point));
+  basic_block return_bb = find_return_bb ();
+  int tsan_exit_found = -1;
   FOR_EACH_BB_FN (bb, cfun)
     {
       int time = 0;
@@ -1627,16 +1812,37 @@ execute_split_functions (void)
                       freq, this_size, this_time);
              print_gimple_stmt (dump_file, stmt, 0, 0);
            }
+
+         if ((flag_sanitize & SANITIZE_THREAD)
+             && is_gimple_call (stmt)
+             && gimple_call_internal_p (stmt)
+             && gimple_call_internal_fn (stmt) == IFN_TSAN_FUNC_EXIT)
+           {
+             /* We handle TSAN_FUNC_EXIT for splitting either in the
+                return_bb, or in its immediate predecessors.  */
+             if ((bb != return_bb && !find_edge (bb, return_bb))
+                 || (tsan_exit_found != -1
+                     && tsan_exit_found != (bb != return_bb)))
+               {
+                 if (dump_file)
+                   fprintf (dump_file, "Not splitting: TSAN_FUNC_EXIT"
+                            " in unexpected basic block.\n");
+                 BITMAP_FREE (forbidden_dominators);
+                 bb_info_vec.release ();
+                 return 0;
+               }
+             tsan_exit_found = bb != return_bb;
+           }
        }
       overall_time += time;
       overall_size += size;
       bb_info_vec[bb->index].time = time;
       bb_info_vec[bb->index].size = size;
     }
-  find_split_points (overall_time, overall_size);
+  find_split_points (return_bb, overall_time, overall_size);
   if (best_split_point.split_bbs)
     {
-      split_function (&best_split_point);
+      split_function (return_bb, &best_split_point, tsan_exit_found == 1);
       BITMAP_FREE (best_split_point.ssa_names_to_pass);
       BITMAP_FREE (best_split_point.split_bbs);
       todo = TODO_update_ssa | TODO_cleanup_cfg;
@@ -1653,13 +1859,12 @@ const pass_data pass_data_split_functions =
   GIMPLE_PASS, /* type */
   "fnsplit", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   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 */
+  0, /* todo_flags_finish */
 };
 
 class pass_split_functions : public gimple_opt_pass
@@ -1671,7 +1876,10 @@ public:
 
   /* opt_pass methods: */
   virtual bool gate (function *);
-  unsigned int execute () { return execute_split_functions (); }
+  virtual unsigned int execute (function *)
+    {
+      return execute_split_functions ();
+    }
 
 }; // class pass_split_functions
 
@@ -1710,13 +1918,12 @@ const pass_data pass_data_feedback_split_functions =
   GIMPLE_PASS, /* type */
   "feedback_fnsplit", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_execute */
   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 */
+  0, /* todo_flags_finish */
 };
 
 class pass_feedback_split_functions : public gimple_opt_pass
@@ -1728,7 +1935,10 @@ public:
 
   /* opt_pass methods: */
   virtual bool gate (function *);
-  unsigned int execute () { return execute_feedback_split_functions (); }
+  virtual unsigned int execute (function *)
+    {
+      return execute_feedback_split_functions ();
+    }
 
 }; // class pass_feedback_split_functions