diff mbox

[gomp4] fix a reduction bug involving GOMP_MAP_FIRSTPRIVATE_POINTER variables

Message ID cf8a2275-049a-9c49-4d10-7fb0f1f9bfab@codesourcery.com
State New
Headers show

Commit Message

Cesar Philippidis Feb. 8, 2017, 2:46 p.m. UTC
This patch teaches lower_oacc_reductions how to handle reduction
variables that were transferred to the accelerator via
GOMP_MAP_FIRSTPRIVATE_POINTER, e.g. fortran dummy variables. One side
effect of this change is that the ref_to_res variable gets remapped to
the (void *) field decl that gets transferred into the accelerator with
the argument struct. This happens, in part, because firstprivate_pointer
variables are remapped after the OpenACC reduction variables have been
processed. Consequently, I had to adjust the type of the ref_to_res
variable during the oaccdevlow pass.

While working on this patch I noticed that I misnamed
convert_{to,from}_firstprivate_pointer functions. Those functions cast
'scalar' values into something that can be handled as a
GOMP_MAP_FIRSTPRIVATE_INT. Therefore, I renamed those functions as
covert_{to,from}_firstprivate_int.

This patch has been applied to gomp-4_0-branch.

Cesar
diff mbox

Patch

2017-02-08  Cesar Philippidis  <cesar@codesourcery.com>

	gcc/
	* config/nvptx/nvptx.c (nvptx_adjust_reduction_type): New function.
	(nvptx_goacc_reduction_setup): Use it to adjust the type of ref_to_res.
	(nvptx_goacc_reduction_fini): Likewise.
	(nvptx_goacc_reduction_teardown): Likewise.
	* omp-low.c (lower_oacc_reductions): Handle reduction decls mapped
	with GOMP_MAP_FIRSTPRIVATE_POINTER.
	* convert_to_firstprivate_pointer: Rename to ...
	* convert_to_firstprivate_int: ... this.
	* convert_from_firstprivate_pointer: Rename to ...
	* convert_from_firstprivate_int: ... this.
	(lower_omp_target): Update calls to convert_{to,from}_firstprivate_int.
	(default_goacc_reduction): Retype ref_to_res as necessary.

	libgomp/
	* testsuite/libgomp.oacc-fortran/reduction-9.f90: New test.


diff --git a/gcc/config/nvptx/nvptx.c b/gcc/config/nvptx/nvptx.c
index 4e6ed60..a9822e268 100644
--- a/gcc/config/nvptx/nvptx.c
+++ b/gcc/config/nvptx/nvptx.c
@@ -4794,6 +4794,23 @@  nvptx_vector_reduction (location_t loc, gimple_stmt_iterator *gsi,
   return new_var;
 }
 
+/* Dummy reduction vars that have GOMP_MAP_FIRSTPRIVATE_POINTER data
+   mappings gets retyped to (void *).  Adjust the type of VAR to TYPE
+   as appropriate.  */
+
+static tree
+nvptx_adjust_reduction_type (tree var, tree type, gimple_seq *seq)
+{
+  if (TREE_TYPE (TREE_TYPE (var)) == type)
+    return var;
+
+  tree ptype = build_pointer_type (type);
+  tree t = make_ssa_name (ptype);
+  tree expr = fold_build1 (NOP_EXPR, ptype, var);
+  gimple_seq_add_stmt (seq, gimple_build_assign (t, expr));
+  return t;
+}
+
 /* NVPTX implementation of GOACC_REDUCTION_SETUP.  */
 
 static void
@@ -4813,7 +4830,11 @@  nvptx_goacc_reduction_setup (gcall *call)
       tree ref_to_res = gimple_call_arg (call, 1);
 
       if (!integer_zerop (ref_to_res))
-	var = build_simple_mem_ref (ref_to_res);
+	{
+	  ref_to_res = nvptx_adjust_reduction_type (ref_to_res, TREE_TYPE (var),
+						    &seq);
+	  var = build_simple_mem_ref (ref_to_res);
+	}
     }
   
   if (level == GOMP_DIM_WORKER)
@@ -4954,7 +4975,11 @@  nvptx_goacc_reduction_fini (gcall *call)
       else if (integer_zerop (ref_to_res))
 	r = var;
       else
-	accum = ref_to_res;
+	{
+	  ref_to_res = nvptx_adjust_reduction_type (ref_to_res, TREE_TYPE (var),
+						    &seq);
+	  accum = ref_to_res;
+	}
 
       if (accum)
 	{
@@ -5003,7 +5028,11 @@  nvptx_goacc_reduction_teardown (gcall *call)
       tree ref_to_res = gimple_call_arg (call, 1);
 
       if (!integer_zerop (ref_to_res))
-	gimplify_assign (build_simple_mem_ref (ref_to_res), var, &seq);
+	{
+	  ref_to_res = nvptx_adjust_reduction_type (ref_to_res, TREE_TYPE (var),
+						    &seq);
+	  gimplify_assign (build_simple_mem_ref (ref_to_res), var, &seq);
+	}
     }
 
   if (lhs)
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 450d76e..bb2d1fa 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -5818,6 +5818,7 @@  lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner,
 	tree ref_to_res = NULL_TREE;
 	tree incoming, outgoing, v1, v2, v3;
 	bool is_private = false;
+	bool is_fpp = false;
 
 	enum tree_code rcode = OMP_CLAUSE_REDUCTION_CODE (c);
 	if (rcode == MINUS_EXPR)
@@ -5876,19 +5877,37 @@  lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner,
 		      is_private = true;
 		      goto do_lookup;
 		    }
+		  else if (OMP_CLAUSE_CODE (cls) == OMP_CLAUSE_MAP
+			   && (OMP_CLAUSE_MAP_KIND (cls)
+			       == GOMP_MAP_FIRSTPRIVATE_POINTER)
+			   && orig == OMP_CLAUSE_DECL (cls))
+		    {
+		      is_fpp = true;
+		      goto do_lookup;
+		    }
 	      }
 
 	  do_lookup:
 	    /* This is the outermost construct with this reduction,
 	       see if there's a mapping for it.  */
 	    if (gimple_code (outer->stmt) == GIMPLE_OMP_TARGET
-		&& maybe_lookup_field (orig, outer) && !is_private)
+		&& (maybe_lookup_field (orig, outer) || is_fpp) && !is_private)
 	      {
-		ref_to_res = build_receiver_ref (orig, false, outer);
-		if (is_reference (orig))
-		  ref_to_res = build_simple_mem_ref (ref_to_res);
-
 		tree type = TREE_TYPE (var);
+
+		if (is_fpp)
+		  {
+		    tree x = create_tmp_var (type);
+		    gimplify_assign (x, lookup_decl (orig, outer), fork_seq);
+		    ref_to_res = x;
+		  }
+		else
+		  {
+		    ref_to_res = build_receiver_ref (orig, false, outer);
+		    if (is_reference (orig))
+		      ref_to_res = build_simple_mem_ref (ref_to_res);
+		  }
+
 		if (POINTER_TYPE_P (type))
 		  type = TREE_TYPE (type);
 
@@ -16460,7 +16479,7 @@  lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
    mappings. */
 
 static tree
-convert_to_firstprivate_pointer (tree var, gimple_seq *gs)
+convert_to_firstprivate_int (tree var, gimple_seq *gs)
 {
   tree type = TREE_TYPE (var), new_type = NULL_TREE;
   tree tmp = NULL_TREE;
@@ -16504,10 +16523,10 @@  convert_to_firstprivate_pointer (tree var, gimple_seq *gs)
   return var;
 }
 
-/* Like convert_to_firstprivate_pointer, but restore the original type.  */
+/* Like convert_to_firstprivate_int, but restore the original type.  */
 
 static tree
-convert_from_firstprivate_pointer (tree var, bool is_ref, gimple_seq *gs)
+convert_from_firstprivate_int (tree var, bool is_ref, gimple_seq *gs)
 {
   tree type = TREE_TYPE (var);
   tree new_type = NULL_TREE;
@@ -16747,8 +16766,8 @@  lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	      {
 		gcc_assert (is_gimple_omp_oacc (ctx->stmt));
 		if (oacc_firstprivate_int)
-		  x = convert_from_firstprivate_pointer (x, is_reference (var),
-							 &fplist);
+		  x = convert_from_firstprivate_int (x, is_reference (var),
+						     &fplist);
 		else if (is_reference (new_var)
 		    && TREE_CODE (var_type) != POINTER_TYPE)
 		  {
@@ -17020,7 +17039,7 @@  lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 			if (is_gimple_reg (var)
 			    && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c))
 			  TREE_NO_WARNING (var) = 1;
-			var = convert_to_firstprivate_pointer (var, &ilist);
+			var = convert_to_firstprivate_int (var, &ilist);
 		      }
 		    else if (!is_reference (var))
 		      {
@@ -20939,6 +20958,17 @@  default_goacc_reduction (gcall *call)
       
       if (!integer_zerop (ref_to_res))
 	{
+	  /* Dummy reduction vars that have GOMP_MAP_FIRSTPRIVATE_POINTER data
+	     mappings gets retyped to (void *).  Adjust the type of ref_to_res
+	     as appropriate.  */
+	  if (TREE_TYPE (TREE_TYPE (ref_to_res)) != TREE_TYPE (var))
+	    {
+	      tree ptype = build_pointer_type (TREE_TYPE (var));
+	      tree t = make_ssa_name (ptype);
+	      tree expr = fold_build1 (NOP_EXPR, ptype, ref_to_res);
+	      gimple_seq_add_stmt (&seq, gimple_build_assign (t, expr));
+	      ref_to_res = t;
+	    }
 	  tree dst = build_simple_mem_ref (ref_to_res);
 	  tree src = var;
 	  
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/reduction-9.f90 b/libgomp/testsuite/libgomp.oacc-fortran/reduction-9.f90
new file mode 100644
index 0000000..fd64d88
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/reduction-9.f90
@@ -0,0 +1,54 @@ 
+! Test gang reductions on dummy variables.
+
+! { dg-do run }
+
+program main
+  implicit none
+
+  integer g, w, v, c
+
+  g = 0
+  w = 0
+  v = 0
+  c = 0
+
+  call reduction (g, w, v, c)
+
+  if (g /= 10) call abort
+  if (w /= 10) call abort
+  if (v /= 10) call abort
+  if (c /= 100) call abort
+end program main
+
+subroutine reduction (g, w, v, c)
+  implicit none
+
+  integer g, w, v, c, i
+
+  !$acc parallel
+  !$acc loop reduction(+:g) gang
+  do i = 1, 10
+     g = g + 1
+  end do
+  !$acc end parallel
+
+  !$acc parallel
+  !$acc loop reduction(+:w) worker
+  do i = 1, 10
+     w = w + 1
+  end do
+  !$acc end parallel
+
+  !$acc parallel
+  !$acc loop reduction(+:v) vector
+  do i = 1, 10
+     v = v + 1
+  end do
+  !$acc end parallel
+
+  !$acc parallel loop reduction(+:c) gang worker vector
+  do i = 1, 100
+     c = c + 1
+  end do
+  !$acc end parallel loop
+end subroutine reduction