From cf2b64cc1d6623424d770f2a9ea257eb7e58e887 Mon Sep 17 00:00:00 2001
From: Ajit Kumar Agarwal <ajitkum@xilix.com>
Date: Sat, 15 Aug 2015 18:19:14 +0200
Subject: [PATCH] [Patch,tree-optimization]: Add new path Splitting pass on
 tree ssa representation.

Added a new pass on path splitting on tree SSA representation. The path
splitting optimization does the CFG transformation of join block of the
if-then-else same as the loop latch node is moved and merged with the
predecessor blocks after preserving the SSA representation.

ChangeLog:
2015-08-15  Ajit Agarwal  <ajitkum@xilinx.com>

	* gcc/Makefile.in: Add the build of the new file
	tree-ssa-path-split.c
	* gcc/common.opt (ftree-path-split): Add the new flag.
	* gcc/opts.c (OPT_ftree_path_split) : Add an entry for
	Path splitting pass with optimization flag greater and
	equal to O2.
	* gcc/passes.def (path_split): add new path splitting pass.
	* gcc/timevar.def (TV_TREE_PATH_SPLIT): New.
	* gcc/tree-pass.h (make_pass_path_split): New declaration.
	* gcc/tree-ssa-path-split.c: New.
	* gcc/tracer.c (transform_duplicate): New.
	* gcc/testsuite/gcc.dg/tree-ssa/path-split-2.c: New.
	* gcc/testsuite/gcc.dg/path-split-1.c: New.
	* gcc/doc/invoke.texi
	(ftree-path-split): Document.
	(fdump-tree-path_split): Document.

Signed-off-by:Ajit Agarwal ajitkum@xilinx.com
---
 gcc/Makefile.in                              |   1 +
 gcc/common.opt                               |   4 +
 gcc/doc/invoke.texi                          |  16 +-
 gcc/opts.c                                   |   1 +
 gcc/passes.def                               |   1 +
 gcc/testsuite/gcc.dg/path-split-1.c          |  65 ++++++
 gcc/testsuite/gcc.dg/tree-ssa/path-split-2.c |  60 +++++
 gcc/timevar.def                              |   1 +
 gcc/tracer.c                                 |  37 +--
 gcc/tree-pass.h                              |   1 +
 gcc/tree-ssa-path-split.c                    | 330 +++++++++++++++++++++++++++
 11 files changed, 503 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/path-split-1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/path-split-2.c
 create mode 100644 gcc/tree-ssa-path-split.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c1cb4ce..f01f885 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1465,6 +1465,7 @@ OBJS = \
 	tree-ssa-loop.o \
 	tree-ssa-math-opts.o \
 	tree-ssa-operands.o \
+        tree-ssa-path-split.o \
 	tree-ssa-phiopt.o \
 	tree-ssa-phiprop.o \
 	tree-ssa-pre.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index e80eadf..1d02582 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2378,6 +2378,10 @@ ftree-vrp
 Common Report Var(flag_tree_vrp) Init(0) Optimization
 Perform Value Range Propagation on trees
 
+ftree-path-split
+Common Report Var(flag_tree_path_split) Init(0) Optimization
+Perform Path Splitting
+
 funit-at-a-time
 Common Report Var(flag_unit_at_a_time) Init(1)
 Compile whole compilation unit at a time
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c26cd87..dce31e7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -350,6 +350,7 @@ Objective-C and Objective-C++ Dialects}.
 -fdump-tree-fre@r{[}-@var{n}@r{]} @gol
 -fdump-tree-vtable-verify @gol
 -fdump-tree-vrp@r{[}-@var{n}@r{]} @gol
+-fdump-tree-path_split@r{[}-@var{n}@r{]} @gol
 -fdump-tree-storeccp@r{[}-@var{n}@r{]} @gol
 -fdump-final-insns=@var{file} @gol
 -fcompare-debug@r{[}=@var{opts}@r{]}  -fcompare-debug-second @gol
@@ -458,7 +459,7 @@ Objective-C and Objective-C++ Dialects}.
 -ftree-parallelize-loops=@var{n} -ftree-pre -ftree-partial-pre -ftree-pta @gol
 -ftree-reassoc -ftree-sink -ftree-slsr -ftree-sra @gol
 -ftree-switch-conversion -ftree-tail-merge -ftree-ter @gol
--ftree-vectorize -ftree-vrp @gol
+-ftree-vectorize -ftree-vrp @gol -ftree-path-split @gol
 -funit-at-a-time -funroll-all-loops -funroll-loops @gol
 -funsafe-loop-optimizations -funsafe-math-optimizations -funswitch-loops @gol
 -fipa-ra -fvariable-expansion-in-unroller -fvect-cost-model -fvpt @gol
@@ -7158,6 +7159,11 @@ is made by appending @file{.slp} to the source file name.
 Dump each function after Value Range Propagation (VRP).  The file name
 is made by appending @file{.vrp} to the source file name.
 
+@item path_split 
+@opindex fdump-tree-path_split
+Dump each function after path splitting.  The file name is made by 
+appending @file{.path_split} to the source file name.
+
 @item all
 @opindex fdump-tree-all
 Enable all the available tree dumps with the flags provided in this option.
@@ -7660,6 +7666,7 @@ also turns on the following optimization flags:
 -ftree-switch-conversion -ftree-tail-merge @gol
 -ftree-pre @gol
 -ftree-vrp @gol
+-ftree-path-split @gol
 -fipa-ra}
 
 Please note the warning under @option{-fgcse} about
@@ -9068,6 +9075,13 @@ enabled by default at @option{-O2} and higher.  Null pointer check
 elimination is only done if @option{-fdelete-null-pointer-checks} is
 enabled.
 
+@item -ftree-path-split
+@opindex ftree-path-split
+Perform Path Splitting  on trees.  The join blocks of IF-THEN-ELSE same
+as loop latch node is moved to its predecessor and the loop latch node
+will be forwarding block.  This is enabled by default at @option{-O2} 
+and higher.  
+
 @item -fsplit-ivs-in-unroller
 @opindex fsplit-ivs-in-unroller
 Enables expression of values of induction variables in later iterations
diff --git a/gcc/opts.c b/gcc/opts.c
index 468a802..c92f94e 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -506,6 +506,7 @@ static const struct default_options default_options_table[] =
     { OPT_LEVELS_2_PLUS, OPT_fisolate_erroneous_paths_dereference, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_fipa_ra, NULL, 1 },
     { OPT_LEVELS_2_PLUS, OPT_flra_remat, NULL, 1 },
+    { OPT_LEVELS_2_PLUS, OPT_ftree_path_split, NULL, 1 },
 
     /* -O3 optimizations.  */
     { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
diff --git a/gcc/passes.def b/gcc/passes.def
index 6b66f8f..20ddf3d 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -82,6 +82,7 @@ along with GCC; see the file COPYING3.  If not see
 	  NEXT_PASS (pass_ccp);
 	  /* After CCP we rewrite no longer addressed locals into SSA
 	     form if possible.  */
+          NEXT_PASS (pass_path_split);
 	  NEXT_PASS (pass_forwprop);
 	  NEXT_PASS (pass_sra_early);
 	  /* pass_build_ealias is a dummy pass that ensures that we
diff --git a/gcc/testsuite/gcc.dg/path-split-1.c b/gcc/testsuite/gcc.dg/path-split-1.c
new file mode 100644
index 0000000..075dc87
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/path-split-1.c
@@ -0,0 +1,65 @@
+/* { dg-do run } */
+/* { dg-options "-O2 " } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define RGBMAX 255
+
+int
+test()
+{
+  int i, Pels;
+  unsigned char sum = 0;
+  unsigned char xr, xg, xb;
+  unsigned char xc, xm, xy, xk;
+  unsigned char *ReadPtr, *EritePtr;
+
+  ReadPtr = ( unsigned char *) malloc (sizeof (unsigned char) * 100);
+  EritePtr = ( unsigned char *) malloc (sizeof (unsigned char) * 100);
+
+  for (i = 0; i < 100;i++)
+     {
+       ReadPtr[i] = 100 - i;
+     }
+
+  for (i = 0; i < 100; i++)
+     {
+       xr = *ReadPtr++;
+       xg = *ReadPtr++;
+       xb = *ReadPtr++;
+
+       xc = (unsigned char) (RGBMAX - xr);
+       xm = (unsigned char) (RGBMAX - xg);
+       xy = (unsigned char) (RGBMAX - xb);
+
+       if (xc < xm)
+         {
+           xk = (unsigned char) (xc < xy ? xc : xy);
+         }
+       else
+        {
+          xk = (unsigned char) (xm < xy ? xm : xy);
+        }
+
+       xc = (unsigned char) (xc - xk);
+       xm = (unsigned char) (xm - xk);
+       xy = (unsigned char) (xy - xk);
+
+       *EritePtr++ = xc;
+       *EritePtr++ = xm;
+       *EritePtr++ = xy;
+       *EritePtr++ = xk;
+       sum += *EritePtr;
+    }
+  return sum;
+}
+
+int
+main()
+{
+  if (test() != 33)
+    abort();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/path-split-2.c b/gcc/testsuite/gcc.dg/tree-ssa/path-split-2.c
new file mode 100644
index 0000000..172570f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/path-split-2.c
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-path_split" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define RGBMAX 255
+
+int
+test()
+{
+  int i, Pels;
+  unsigned char sum = 0;
+  unsigned char xr, xg, xb;
+  unsigned char xc, xm, xy, xk;
+  unsigned char *ReadPtr, *EritePtr;
+
+  ReadPtr = (unsigned char *) malloc (sizeof (unsigned char) * 100);
+  EritePtr = ( unsigned char *) malloc (sizeof (unsigned char) * 100);
+
+  for (i = 0; i < 100;i++)
+     {
+       ReadPtr[i] = 100 - i;
+     }
+
+  for (i = 0; i < 100; i++)
+     {
+       xr = *ReadPtr++;
+       xg = *ReadPtr++;
+       xb = *ReadPtr++;
+
+       xc = ( unsigned char) (RGBMAX - xr);
+       xm = ( unsigned char) (RGBMAX - xg);
+       xy = ( unsigned char) (RGBMAX - xb);
+
+       if (xc < xm)
+         {
+           xk = ( unsigned char) (xc < xy ? xc : xy);
+         }
+       else
+         {
+           xk = ( unsigned char) (xm < xy ? xm : xy);
+         }
+
+       xc = (unsigned char) (xc - xk);
+       xm = (unsigned char) (xm - xk);
+       xy = (unsigned char) (xy - xk);
+
+       *EritePtr++ = xc;
+       *EritePtr++ = xm;
+       *EritePtr++ = xy;
+       *EritePtr++ = xk;
+       sum += *EritePtr;
+    }
+  return sum;
+}
+
+/* { dg-final { scan-tree-dump "xc_\[0-9\]\[0-9\]* -> { xc_\[0-9\]\[0-9\]* }" "path_split"} } */
+/* { dg-final { scan-tree-dump "xm_\[0-9\]\[0-9\]* -> { xm_\[0-9\]\[0-9\]* }" "path_split"} } */
+/* { dg-final { scan-tree-dump "xy_\[0-9\]\[0-9\]* -> { xy_\[0-9\]\[0-9\]* }" "path_split"} } */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index ac41075..f2c145e 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -298,3 +298,4 @@ DEFTIMEVAR (TV_LINK		     , "link JIT code")
 DEFTIMEVAR (TV_LOAD		     , "load JIT result")
 DEFTIMEVAR (TV_JIT_ACQUIRING_MUTEX   , "acquiring JIT mutex")
 DEFTIMEVAR (TV_JIT_CLIENT_CODE   , "JIT client code")
+DEFTIMEVAR (TV_TREE_PATH_SPLIT  , "tree path_split")
diff --git a/gcc/tracer.c b/gcc/tracer.c
index cad7ab1..206692f 100644
--- a/gcc/tracer.c
+++ b/gcc/tracer.c
@@ -58,11 +58,13 @@
 #include "fibonacci_heap.h"
 
 static int count_insns (basic_block);
-static bool ignore_bb_p (const_basic_block);
+bool ignore_bb_p (const_basic_block);
 static bool better_p (const_edge, const_edge);
 static edge find_best_successor (basic_block);
 static edge find_best_predecessor (basic_block);
 static int find_trace (basic_block, basic_block *);
+basic_block transform_duplicate(basic_block bb,
+                                basic_block  bb2);
 
 /* Minimal outgoing edge probability considered for superblock formation.  */
 static int probability_cutoff;
@@ -90,7 +92,7 @@ bb_seen_p (basic_block bb)
 }
 
 /* Return true if we should ignore the basic block for purposes of tracing.  */
-static bool
+bool
 ignore_bb_p (const_basic_block bb)
 {
   gimple g;
@@ -224,6 +226,24 @@ find_trace (basic_block bb, basic_block *trace)
   return i;
 }
 
+/* Transform the block that needs to be duplicated.  */
+
+basic_block
+transform_duplicate(basic_block bb,
+                    basic_block  bb2)
+{
+  edge e;
+  basic_block copy;
+
+  e = find_edge (bb, bb2);
+
+  copy = duplicate_block (bb2, e, bb);
+  flush_pending_stmts (e);
+
+  add_phi_args_after_copy (&copy, 1, NULL);
+
+  return (copy);
+}
 /* Look for basic blocks in frequency order, construct traces and tail duplicate
    if profitable.  */
 
@@ -319,17 +339,8 @@ tail_duplicate (void)
 		 entries or at least rotate the loop.  */
 	      && bb2->loop_father->header != bb2)
 	    {
-	      edge e;
-	      basic_block copy;
-
-	      nduplicated += counts [bb2->index];
-
-	      e = find_edge (bb, bb2);
-
-	      copy = duplicate_block (bb2, e, bb);
-	      flush_pending_stmts (e);
-
-	      add_phi_args_after_copy (&copy, 1, NULL);
+              nduplicated += counts [bb2->index];
+              basic_block copy = transform_duplicate (bb,bb2);
 
 	      /* Reconsider the original copy of block we've duplicated.
 	         Removing the most common predecessor may make it to be
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 7b66a1c..6af7f0d 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -383,6 +383,7 @@ extern gimple_opt_pass *make_pass_tree_loop_done (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_ch (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_ch_vect (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_ccp (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_path_split (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_phi_only_cprop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_build_ssa (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_build_alias (gcc::context *ctxt);
diff --git a/gcc/tree-ssa-path-split.c b/gcc/tree-ssa-path-split.c
new file mode 100644
index 0000000..5ce4b86
--- /dev/null
+++ b/gcc/tree-ssa-path-split.c
@@ -0,0 +1,330 @@
+/* Support routines for Path Splitting.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Ajit Kumar Agarwal <ajitkum@xilinx.com>.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "cfghooks.h"
+#include "tree.h"
+#include "gimple.h"
+#include "rtl.h"
+#include "ssa.h"
+#include "flags.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "cfganal.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "tree-cfg.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-ssa-loop.h"
+#include "tree-into-ssa.h"
+#include "tree-ssa.h"
+#include "tree-pass.h"
+#include "tree-dump.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "intl.h"
+#include "cfgloop.h"
+#include "tree-scalar-evolution.h"
+#include "tree-ssa-propagate.h"
+#include "tree-chrec.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "insn-codes.h"
+#include "optabs.h"
+#include "fibonacci_heap.h"
+
+extern basic_block transform_duplicate(basic_block bb, basic_block  bb2);
+extern bool ignore_bb_p (const_basic_block bb);
+
+/* This function gets the join blocks same as the source
+   node of the loop latch nodes and form the trace with
+   the join block and its predecessor.  */
+
+static int
+find_trace_loop_latch_same_as_join_blk (basic_block bb,
+                                        basic_block *trace)
+{
+  vec<basic_block> bbs;
+  basic_block bb1;
+  unsigned int i;
+  edge_iterator ei;
+  edge e1;
+  bool found = false;
+  int n = 0;
+
+  bbs = get_all_dominated_blocks (CDI_DOMINATORS,
+                                  bb );
+  FOR_EACH_VEC_ELT (bbs, i, bb1)
+  {
+    FOR_EACH_EDGE (e1, ei, bb->succs)
+    {
+      if ( bb1 == e1->dest)
+        {
+          found = true;
+        }
+    }
+
+    if (!found && bb1 != bb)
+      {
+        found = false;
+        FOR_EACH_EDGE (e1, ei, bb1->succs)
+        {
+          if (e1->flags & (EDGE_DFS_BACK))
+            {
+              trace[1] = e1->src;
+              n++;
+              found = true;
+            }  
+        }
+
+        if (found && EDGE_COUNT(bb1->preds) == 2)
+          {
+            FOR_EACH_EDGE (e1, ei, bb1->preds)
+            {
+              if (single_succ_p(e1->src) &&
+                  single_succ_edge (e1->src)->flags & EDGE_FALLTHRU)
+                {
+                   trace[0] = e1->src;
+                   n++;
+                   break;
+                }
+            }
+            return n;
+          }
+       }
+   }
+   return n;
+}
+
+/* This function performs the feasibility tests for path splitting
+   to perform. Return false if the feasibility for path splitting
+   is not done and returns true if the feasbility for path splitting
+   is done. Following feasibility tests are performed.
+
+   1. Return false if the join block has rhs casting for assign
+      gimple statements.
+   2. If the number of phis is greater than 1 or the phi node in
+      the join block has virtual operand return false.
+   3. Return true if the number of sequential statements is
+      greater than 2.
+   4. If the phi result in the phi node of the join block is not
+      used inside the same join block return false.
+   7. Otherwise returns true.  */
+
+static bool
+is_feasible_trace (basic_block *trace)
+{
+  int num_stmt = 0, num_phis = 0;
+  gimple_stmt_iterator psi, gsi;
+
+  for (gsi = gsi_start_bb (trace[1]); !gsi_end_p (gsi); gsi_next (&gsi))
+     {
+       gimple stmt = gsi_stmt (gsi);
+       if (gimple_assign_cast_p (stmt))
+         return false;
+
+       if (!is_gimple_debug (stmt))
+         num_stmt++;
+    }
+
+   if ((num_stmt > 1))
+     {
+       bool found_virtual_result = false;
+
+       for (psi = gsi_start_phis (trace[1]); !gsi_end_p (psi); )
+          {
+            use_operand_p use_p;
+            imm_use_iterator iter;
+            gimple stmt = gsi_stmt(psi);
+
+            if (!virtual_operand_p (gimple_phi_result (stmt)))
+              num_phis++;
+            else
+              found_virtual_result = true;
+
+             FOR_EACH_IMM_USE_FAST (use_p, iter, gimple_phi_result (stmt))
+             {
+               gimple use_stmt = USE_STMT (use_p);
+
+               if (gimple_bb (use_stmt) != trace[1])
+                 return false;
+             }
+             gsi_next(&psi);
+          }
+
+        if ((num_phis >1) || found_virtual_result)
+          return false;
+
+       return true;
+    }
+
+  return false;
+}
+
+/* This is the core function to perform path splitting. The join
+   same as the source of the loop latch node is identified along
+   with their predecessors. Based on the feasibility tests for
+   path splitting the path splitting is performed by adding the
+   join blocks into the predecessors after propagating the phi
+   result with the corresponding phi arguments for the predecessors.
+   The  tree-cfg-cleanup will merge the blocks in the predecessors
+   path and the update-ssa will update the ssa representation after
+   the path splitting is performed.  */
+
+static bool
+perform_path_splitting ()
+{
+  bool changed = false;
+  basic_block trace[2] = {NULL,NULL};
+  basic_block bb;
+  auto_vec<fibonacci_node<long, basic_block_def>*> blocks;
+  blocks.safe_grow_cleared (last_basic_block_for_fn (cfun));
+  fibonacci_heap<long, basic_block_def> heap (LONG_MIN);
+ 
+  initialize_original_copy_tables();
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  FOR_EACH_BB_FN (bb, cfun)
+  {
+    if (!ignore_bb_p (bb))
+      blocks[bb->index] = heap.insert (-bb->frequency, bb);
+  }
+ 
+  while (!heap.empty())
+  {
+    basic_block bb = heap.extract_min ();
+
+    if (!bb)
+      break;
+
+    blocks[bb->index] = NULL;
+    if (ignore_bb_p (bb))
+        continue;
+
+    gimple last = gsi_stmt (gsi_last_bb (bb));
+
+    if (last && gimple_code (last) != GIMPLE_COND)
+      continue;
+
+    int n = find_trace_loop_latch_same_as_join_blk (bb, trace);
+
+    if (n >= 2 && is_feasible_trace (trace))
+      {
+        if (blocks[trace[0]->index])
+          {
+            heap.delete_node (blocks[trace[0]->index]);
+            blocks[trace[0]->index] = NULL;
+          }
+        if (blocks[trace[1]->index])
+          {
+            heap.delete_node (blocks[trace[1]->index]);
+            blocks[trace[0]->index] = NULL;
+          }
+
+        transform_duplicate (trace[0],trace[1]);
+        printf("path splitting successful \n");
+        changed = true;
+     }
+  }
+ 
+  free_original_copy_tables ();
+  return changed;
+}
+
+static unsigned int
+execute_path_split (void)
+{
+  bool changed;
+
+  if (n_basic_blocks_for_fn (cfun) <= NUM_FIXED_BLOCKS + 1)
+      return 0;
+
+  mark_dfs_back_edges ();
+
+  changed = perform_path_splitting();
+
+  if (changed)
+    {
+       free_dominance_info (CDI_DOMINATORS);
+       /* If we changed the CFG schedule loops for fixup by cleanup_cfg.  */
+       if (current_loops)
+         loops_state_set (LOOPS_NEED_FIXUP);
+    }
+ 
+  return changed ? TODO_cleanup_cfg : 0;
+
+}
+
+static bool
+gate_path_split(void)
+{
+  return flag_tree_path_split != 0;
+}
+
+namespace {
+
+const pass_data pass_data_path_split =
+{
+  GIMPLE_PASS, /* type */
+  "path_split", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_PATH_SPLIT, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_path_split : public gimple_opt_pass
+{
+   public:
+    pass_path_split (gcc::context *ctxt)
+      : gimple_opt_pass (pass_data_path_split, ctxt)
+    {}
+   /* opt_pass methods: */
+   opt_pass * clone () { return new pass_path_split (m_ctxt); }
+   virtual bool gate (function *) { return gate_path_split (); }
+   virtual unsigned int execute (function *) { return execute_path_split (); }
+ 
+}; // class pass_path_split
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_path_split (gcc::context *ctxt)
+{
+  return new pass_path_split (ctxt);
+}
-- 
1.8.2.1

