Add param parloops-schedule

2015-09-10  Tom de Vries  <tom@codesourcery.com>

	PR tree-optimization/67476
	* doc/invoke.texi (@item parloops-schedule): New item.
	* omp-low.c (expand_omp_for_generic): Handle simple latch.  Add missing
	phis.  Handle original loop.
	* params.def (PARAM_PARLOOPS_SCHEDULE): New DEFPARAMENUM.
	* tree-parloops.c (create_parallel_loop): Handle
	PARAM_PARLOOPS_SCHEDULE.

	* testsuite/libgomp.c/autopar-3.c: New test.
	* testsuite/libgomp.c/autopar-4.c: New test.
	* testsuite/libgomp.c/autopar-5.c: New test.
	* testsuite/libgomp.c/autopar-6.c: New test.
	* testsuite/libgomp.c/autopar-7.c: New test.
	* testsuite/libgomp.c/autopar-8.c: New test.
---
 gcc/doc/invoke.texi                     |  4 +++
 gcc/omp-low.c                           | 57 +++++++++++++++++++++++++++++++--
 gcc/params.def                          |  6 ++++
 gcc/tree-parloops.c                     | 24 +++++++++++++-
 libgomp/testsuite/libgomp.c/autopar-3.c |  4 +++
 libgomp/testsuite/libgomp.c/autopar-4.c |  4 +++
 libgomp/testsuite/libgomp.c/autopar-5.c |  4 +++
 libgomp/testsuite/libgomp.c/autopar-6.c |  4 +++
 libgomp/testsuite/libgomp.c/autopar-7.c |  4 +++
 libgomp/testsuite/libgomp.c/autopar-8.c |  4 +++
 10 files changed, 111 insertions(+), 4 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.c/autopar-3.c
 create mode 100644 libgomp/testsuite/libgomp.c/autopar-4.c
 create mode 100644 libgomp/testsuite/libgomp.c/autopar-5.c
 create mode 100644 libgomp/testsuite/libgomp.c/autopar-6.c
 create mode 100644 libgomp/testsuite/libgomp.c/autopar-7.c
 create mode 100644 libgomp/testsuite/libgomp.c/autopar-8.c

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 76e5e29..2221795 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -11005,6 +11005,10 @@ automaton.  The default is 50.
 Chunk size of omp schedule for loops parallelized by parloops.  The default
 is 0.
 
+@item parloops-schedule
+Schedule type of omp schedule for loops parallelized by parloops (static,
+dynamic, guided, auto, runtime).  The default is static.
+
 @end table
 @end table
 
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 88a5149..4f0498b 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -239,6 +239,7 @@ static vec<omp_context *> taskreg_contexts;
 
 static void scan_omp (gimple_seq *, omp_context *);
 static tree scan_omp_1_op (tree *, int *, void *);
+static gphi *find_phi_with_arg_on_edge (tree, edge);
 
 #define WALK_SUBSTMTS  \
     case GIMPLE_BIND: \
@@ -6155,7 +6156,9 @@ expand_omp_for_generic (struct omp_region *region,
   if (!broken_loop)
     {
       l2_bb = create_empty_bb (cont_bb);
-      gcc_assert (BRANCH_EDGE (cont_bb)->dest == l1_bb);
+      gcc_assert (BRANCH_EDGE (cont_bb)->dest == l1_bb
+		  || (single_succ_edge (BRANCH_EDGE (cont_bb)->dest)->dest
+		      == l1_bb));
       gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
     }
   else
@@ -6429,8 +6432,12 @@ expand_omp_for_generic (struct omp_region *region,
       remove_edge (e);
 
       make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
-      add_bb_to_loop (l2_bb, cont_bb->loop_father);
       e = find_edge (cont_bb, l1_bb);
+      if (e == NULL)
+	{
+	  e = BRANCH_EDGE (cont_bb);
+	  gcc_assert (single_succ (e->dest) == l1_bb);
+	}
       if (gimple_omp_for_combined_p (fd->for_stmt))
 	{
 	  remove_edge (e);
@@ -6454,7 +6461,45 @@ expand_omp_for_generic (struct omp_region *region,
 	  e->flags = EDGE_FALLTHRU;
 	}
       make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
+    }
+
+
+  if (gimple_in_ssa_p (cfun))
+    {
+      gphi_iterator psi;
+
+      for (psi = gsi_start_phis (l3_bb); !gsi_end_p (psi); gsi_next (&psi))
+	{
+	  source_location locus;
+	  gphi *nphi;
+	  gphi *exit_phi = psi.phi ();
+
+	  edge l2_to_l3 = find_edge (l2_bb, l3_bb);
+	  tree exit_res = PHI_ARG_DEF_FROM_EDGE (exit_phi, l2_to_l3);
 
+	  basic_block latch = BRANCH_EDGE (cont_bb)->dest;
+	  edge latch_to_l1 = find_edge (latch, l1_bb);
+	  gphi *inner_phi = find_phi_with_arg_on_edge (exit_res, latch_to_l1);
+
+	  tree t = gimple_phi_result (exit_phi);
+	  tree new_res = copy_ssa_name (t, NULL);
+	  nphi = create_phi_node (new_res, l0_bb);
+
+	  edge l0_to_l1 = find_edge (l0_bb, l1_bb);
+	  t = PHI_ARG_DEF_FROM_EDGE (inner_phi, l0_to_l1);
+	  locus = gimple_phi_arg_location_from_edge (inner_phi, l0_to_l1);
+	  edge entry_to_l0 = find_edge (entry_bb, l0_bb);
+	  add_phi_arg (nphi, t, entry_to_l0, locus);
+
+	  edge l2_to_l0 = find_edge (l2_bb, l0_bb);
+	  add_phi_arg (nphi, exit_res, l2_to_l0, UNKNOWN_LOCATION);
+
+	  add_phi_arg (inner_phi, new_res, l0_to_l1, UNKNOWN_LOCATION);
+	};
+    }
+
+  if (!broken_loop)
+    {
       set_immediate_dominator (CDI_DOMINATORS, l2_bb,
 			       recompute_dominator (CDI_DOMINATORS, l2_bb));
       set_immediate_dominator (CDI_DOMINATORS, l3_bb,
@@ -6464,14 +6509,20 @@ expand_omp_for_generic (struct omp_region *region,
       set_immediate_dominator (CDI_DOMINATORS, l1_bb,
 			       recompute_dominator (CDI_DOMINATORS, l1_bb));
 
+      struct loop *loop = l1_bb->loop_father;
+      add_bb_to_loop (l2_bb, entry_bb->loop_father);
+
       struct loop *outer_loop = alloc_loop ();
       outer_loop->header = l0_bb;
       outer_loop->latch = l2_bb;
       add_loop (outer_loop, l0_bb->loop_father);
 
+      if (loop != entry_bb->loop_father)
+	return;
+
       if (!gimple_omp_for_combined_p (fd->for_stmt))
 	{
-	  struct loop *loop = alloc_loop ();
+	  loop = alloc_loop ();
 	  loop->header = l1_bb;
 	  /* The loop may have multiple latches.  */
 	  add_loop (loop, outer_loop);
diff --git a/gcc/params.def b/gcc/params.def
index 34e2025..72afff1 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1145,6 +1145,12 @@ DEFPARAM (PARAM_PARLOOPS_CHUNK_SIZE,
 	  "parloops-chunk-size",
 	  "Chunk size of omp schedule for loops parallelized by parloops",
 	  0, 0, 0)
+
+DEFPARAMENUM (PARAM_PARLOOPS_SCHEDULE,
+	      "parloops-schedule",
+	      "Schedule type of omp schedule for loops parallelized by "
+	      "parloops (static, dynamic, guided, auto, runtime)",
+	      0, 0, 4, "static", "dynamic", "guided", "auto", "runtime")
 /*
 
 Local variables:
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index c164121..a9c9c44 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -2092,8 +2092,30 @@ create_parallel_loop (struct loop *loop, tree loop_fn, tree data,
   gimple_cond_set_lhs (cond_stmt, cvar_base);
   type = TREE_TYPE (cvar);
   t = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE);
-  OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_STATIC;
   int chunk_size = PARAM_VALUE (PARAM_PARLOOPS_CHUNK_SIZE);
+  int schedule_type = PARAM_VALUE (PARAM_PARLOOPS_SCHEDULE);
+  switch (schedule_type)
+    {
+    case 0:
+      OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_STATIC;
+      break;
+    case 1:
+      OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
+      break;
+    case 2:
+      OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_GUIDED;
+      break;
+    case 3:
+      OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_AUTO;
+      chunk_size = 0;
+      break;
+    case 4:
+      OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_RUNTIME;
+      chunk_size = 0;
+      break;
+    default:
+      gcc_unreachable ();
+    }
   if (chunk_size != 0)
     OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t)
       = build_int_cst (integer_type_node, chunk_size);
diff --git a/libgomp/testsuite/libgomp.c/autopar-3.c b/libgomp/testsuite/libgomp.c/autopar-3.c
new file mode 100644
index 0000000..1c25a44
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/autopar-3.c
@@ -0,0 +1,4 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-parallelize-loops=4 -ffast-math --param parloops-schedule=dynamic" } */
+
+#include "autopar-1.c"
diff --git a/libgomp/testsuite/libgomp.c/autopar-4.c b/libgomp/testsuite/libgomp.c/autopar-4.c
new file mode 100644
index 0000000..78c77d9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/autopar-4.c
@@ -0,0 +1,4 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-parallelize-loops=4 -ffast-math --param parloops-schedule=dynamic --param parloops-chunk-size=100" } */
+
+#include "autopar-1.c"
diff --git a/libgomp/testsuite/libgomp.c/autopar-5.c b/libgomp/testsuite/libgomp.c/autopar-5.c
new file mode 100644
index 0000000..f0acb20
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/autopar-5.c
@@ -0,0 +1,4 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-parallelize-loops=4 -ffast-math --param parloops-schedule=guided" } */
+
+#include "autopar-1.c"
diff --git a/libgomp/testsuite/libgomp.c/autopar-6.c b/libgomp/testsuite/libgomp.c/autopar-6.c
new file mode 100644
index 0000000..f6e723e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/autopar-6.c
@@ -0,0 +1,4 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-parallelize-loops=4 -ffast-math --param parloops-schedule=guided --param parloops-chunk-size=100" } */
+
+#include "autopar-1.c"
diff --git a/libgomp/testsuite/libgomp.c/autopar-7.c b/libgomp/testsuite/libgomp.c/autopar-7.c
new file mode 100644
index 0000000..5f15508f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/autopar-7.c
@@ -0,0 +1,4 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-parallelize-loops=4 -ffast-math --param parloops-schedule=auto" } */
+
+#include "autopar-1.c"
diff --git a/libgomp/testsuite/libgomp.c/autopar-8.c b/libgomp/testsuite/libgomp.c/autopar-8.c
new file mode 100644
index 0000000..6099e9f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/autopar-8.c
@@ -0,0 +1,4 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-parallelize-loops=4 -ffast-math --param parloops-schedule=runtime" } */
+
+#include "autopar-1.c"
-- 
1.9.1

