Handle casts in bound in transform_to_exit_first_loop_alt

2015-06-13  Tom de Vries  <tom@codesourcery.com>

	* tree-parloops.c (transform_to_exit_first_loop_alt): Add update_stmt
	for cond_stmt.
	(try_get_loop_niter): Declare forward.
	(try_transform_to_exit_first_loop_alt): Use try_get_loop_niter to get
	updated number of iterations.  Extract alt_bount, and instantiate it.

	* testsuite/libgomp.fortran/parloops-exit-first-loop-alt-2.f95: New test.
	* testsuite/libgomp.fortran/parloops-exit-first-loop-alt.f95: New test.

	* gfortran.dg/parloops-exit-first-loop-alt-2.f95: New test.
	* gfortran.dg/parloops-exit-first-loop-alt.f95: New test.
---
 .../gfortran.dg/parloops-exit-first-loop-alt-2.f95 | 24 +++++++++
 .../gfortran.dg/parloops-exit-first-loop-alt.f95   | 25 +++++++++
 gcc/tree-parloops.c                                | 59 +++++++++++++---------
 .../parloops-exit-first-loop-alt-2.f95             | 40 +++++++++++++++
 .../parloops-exit-first-loop-alt.f95               | 41 +++++++++++++++
 5 files changed, 164 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt-2.f95
 create mode 100644 gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt.f95
 create mode 100644 libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt-2.f95
 create mode 100644 libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt.f95

diff --git a/gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt-2.f95 b/gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt-2.f95
new file mode 100644
index 0000000..a785bf9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt-2.f95
@@ -0,0 +1,24 @@
+! { dg-additional-options "-O2" }
+! { dg-require-effective-target pthread }
+! { dg-additional-options "-ftree-parallelize-loops=2" }
+! { dg-additional-options "-fdump-tree-parloops" }
+
+! Constant bound, vector addition.
+
+subroutine foo()
+  integer, parameter         :: n = 1000
+  integer, dimension (0:n-1) :: a, b, c
+  common a, b, c
+  integer                    :: ii
+
+  do ii = 0, n - 1
+     c(ii) = a(ii) + b(ii) + 25
+  end do
+end subroutine foo
+
+! Three times plus 25:
+! - once in f._loopfn.0
+! - once in the parallel
+! - once in the low iteration count loop
+! Crucially, none for a peeled off last iteration following the parallel.
+! { dg-final { scan-tree-dump-times "(?n) \\+ 25;" 3 "parloops" } }
diff --git a/gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt.f95 b/gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt.f95
new file mode 100644
index 0000000..3873ca2a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/parloops-exit-first-loop-alt.f95
@@ -0,0 +1,25 @@
+! { dg-additional-options "-O2" }
+! { dg-require-effective-target pthread }
+! { dg-additional-options "-ftree-parallelize-loops=2" }
+! { dg-additional-options "-fdump-tree-parloops" }
+
+! Variable bound, vector addition.
+
+subroutine foo(nr)
+  integer, intent(in)       :: nr
+  integer, parameter         :: n = 1000
+  integer, dimension (0:n-1) :: a, b, c
+  common a, b, c
+  integer                    :: ii
+
+  do ii = 0, nr - 1
+     c(ii) = a(ii) + b(ii) + 25
+  end do
+end subroutine foo
+
+! Three times plus 25:
+! - once in f._loopfn.0
+! - once in the parallel
+! - once in the low iteration count loop
+! Crucially, none for a peeled off last iteration following the parallel.
+! { dg-final { scan-tree-dump-times "(?n) \\+ 25;" 3 "parloops" } }
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index 3495ac1..6e10901 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -1678,6 +1678,7 @@ transform_to_exit_first_loop_alt (struct loop *loop,
 
   /* Set the new loop bound.  */
   gimple_cond_set_rhs (cond_stmt, bound);
+  update_stmt (cond_stmt);
 
   /* Repair the ssa.  */
   vec<edge_var_map> *v = redirect_edge_var_map_vector (post_inc_edge);
@@ -1755,6 +1756,8 @@ transform_to_exit_first_loop_alt (struct loop *loop,
   calculate_dominance_info (CDI_DOMINATORS);
 }
 
+static bool try_get_loop_niter (loop_p, struct tree_niter_desc *);
+
 /* Tries to moves the exit condition of LOOP to the beginning of its header
    without duplication of the loop body.  NIT is the number of iterations of the
    loop.  REDUCTION_LIST describes the reductions in LOOP.  Return true if
@@ -1820,36 +1823,42 @@ try_transform_to_exit_first_loop_alt (struct loop *loop,
 	  else if (integer_minus_onep (op2))
 	    alt_bound = op1;
 	}
+    }
 
-      /* There is a number of test-cases for which we don't get an alt_bound
-	 here: they're listed here, with the lhs of the last stmt as the nit:
-
-	 libgomp.graphite/force-parallel-1.c:
-	 _21 = (signed long) N_6(D);
-	 _19 = _21 + -1;
-	 _7 = (unsigned long) _19;
-
-	 libgomp.graphite/force-parallel-2.c:
-	 _33 = (signed long) N_9(D);
-	 _16 = _33 + -1;
-	 _37 = (unsigned long) _16;
+  if (alt_bound == NULL_TREE)
+    {
+      struct tree_niter_desc niter;
+      if (try_get_loop_niter (loop, &niter))
+	{
+	  tree new_nit = niter.niter;
+	  STRIP_NOPS (new_nit);
+	  if (TREE_CODE (new_nit) == PLUS_EXPR)
+	    {
+	      tree op1 = TREE_OPERAND (new_nit, 0);
+	      tree op2 = TREE_OPERAND (new_nit, 1);
+	      if (integer_minus_onep (op1))
+		alt_bound = op2;
+	      else if (integer_minus_onep (op2))
+		alt_bound = op1;
+	    }
+	}
 
-	 libgomp.graphite/force-parallel-5.c:
-	 <bb 6>:
-	 # graphite_IV.5_46 = PHI <0(5), graphite_IV.5_47(11)>
-	 <bb 7>:
-	 _33 = (unsigned long) graphite_IV.5_46;
+      if (alt_bound != NULL_TREE)
+	{
+	  alt_bound = fold_convert (TREE_TYPE (niter.niter), alt_bound);
 
-	 g++.dg/tree-ssa/pr34355.C:
-	 _2 = (unsigned int) i_9;
-	 _3 = 4 - _2;
+	  gimple_seq pre = NULL, post = NULL;
+	  push_gimplify_context (true);
+	  gimplify_expr (&alt_bound, &pre, &post, is_gimple_reg,
+			 fb_rvalue);
+	  pop_gimplify_context (NULL);
 
-	 gcc.dg/pr53849.c:
-	 _5 = d.0_11 + -2;
-	 _18 = (unsigned int) _5;
+	  gimple_seq_add_seq (&pre, post);
 
-	 We will be able to handle some of these cases, if we can determine when
-	 it's safe to look past casts.  */
+	  gimple_stmt_iterator gsi
+	    = gsi_last_bb (loop_preheader_edge (loop)->src);
+	  gsi_insert_seq_after (&gsi, pre, GSI_CONTINUE_LINKING);
+	}
     }
 
   if (alt_bound == NULL_TREE)
diff --git a/libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt-2.f95 b/libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt-2.f95
new file mode 100644
index 0000000..0bae6ba
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt-2.f95
@@ -0,0 +1,40 @@
+! { dg-do run }
+! { dg-additional-options "-O2" }
+! { dg-additional-options "-ftree-parallelize-loops=2" }
+
+! Constant bound, vector addition.
+
+subroutine foo()
+  integer, parameter         :: n = 1000
+  integer, dimension (0:n-1) :: a, b, c
+  common a, b, c
+  integer                    :: ii
+
+  do ii = 0, n - 1
+     c(ii) = a(ii) + b(ii)
+  end do
+end subroutine foo
+
+program main 
+  integer, parameter         :: n = 1000
+  integer, parameter         :: distrib = 10
+  integer, dimension (0:n-1) :: a, b, c
+  common a, b, c
+  integer :: i, j, k
+
+  do j = 0, ((n / distrib) -1)
+     do i = 0, distrib - 1
+	k = i + (distrib * j)
+	a(k) = k
+	b(k) = MODULO ((k * 3), 7)
+        c(k) = k * 2;
+     end do
+  end do
+
+  call foo ()
+
+  do i = 0, n - 1
+     if (c(i) .ne. (i + MODULO ((i * 3), 7))) call abort
+  end do
+  
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt.f95 b/libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt.f95
new file mode 100644
index 0000000..edb6581
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/parloops-exit-first-loop-alt.f95
@@ -0,0 +1,41 @@
+! { dg-do run }
+! { dg-additional-options "-O2" }
+! { dg-additional-options "-ftree-parallelize-loops=2" }
+
+! Variable bound, vector addition.
+
+subroutine foo(nr)
+  integer, intent(in)       :: nr
+  integer, parameter         :: n = 1000
+  integer, dimension (0:n-1) :: a, b, c
+  common a, b, c
+  integer                    :: ii
+
+  do ii = 0, nr - 1
+     c(ii) = a(ii) + b(ii)
+  end do
+end subroutine foo
+
+program main 
+  integer, parameter         :: n = 1000
+  integer, parameter         :: distrib = 10
+  integer, dimension (0:n-1) :: a, b, c
+  common a, b, c
+  integer :: i, j, k
+
+  do j = 0, ((n / distrib) -1)
+     do i = 0, distrib - 1
+	k = i + (distrib * j)
+	a(k) = k
+	b(k) = MODULO ((k * 3), 7)
+        c(k) = k * 2;
+     end do
+  end do
+
+  call foo (n)
+
+  do i = 0, n - 1
+     if (c(i) .ne. (i + MODULO ((i * 3), 7))) call abort
+  end do
+  
+end program
-- 
1.9.1

