diff mbox series

[committed] Fix up reference handling on simd constructs

Message ID 20190605080154.GY19695@tucnak
State New
Headers show
Series [committed] Fix up reference handling on simd constructs | expand

Commit Message

Jakub Jelinek June 5, 2019, 8:01 a.m. UTC
Hi!

To be able to properly vectorize code that uses private, lastprivate or linear
clauses with reference arguments, we should be using "omp simd array" types
holding what those references bind to.  The following patch in addition
disables "omp simd array" vectorization in loops where those reference
arguments refer to variable length types.

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.

2019-06-05  Jakub Jelinek  <jakub@redhat.com>

	* omp-low.c (lower_rec_input_clauses): Force max_vf if is_simd and
	on privatization clauses OMP_CLAUSE_DECL is privatized by reference
	and references a VLA.  Handle references to non-VLAs if is_simd
	all privatization clauses like reductions.
	(lower_rec_input_clauses) <case do_private, case do_firstprivate>:
	If omp_is_reference, use always omp simd arrays and set
	DECL_VALUE_EXPR in that case, if lower_rec_simd_input_clauses
	fails, emit reference initialization.

	* g++.dg/vect/simd-1.cc: New test.


	Jakub
diff mbox series

Patch

--- gcc/omp-low.c.jj	2019-06-03 17:57:42.060631242 +0200
+++ gcc/omp-low.c	2019-06-04 14:23:02.860608537 +0200
@@ -3831,12 +3831,24 @@  lower_rec_input_clauses (tree clauses, g
 	case OMP_CLAUSE_LASTPRIVATE:
 	  if (is_variable_sized (OMP_CLAUSE_DECL (c)))
 	    sctx.max_vf = 1;
+	  else if (omp_is_reference (OMP_CLAUSE_DECL (c)))
+	    {
+	      tree rtype = TREE_TYPE (TREE_TYPE (OMP_CLAUSE_DECL (c)));
+	      if (!TREE_CONSTANT (TYPE_SIZE_UNIT (rtype)))
+		sctx.max_vf = 1;
+	    }
 	  break;
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_IN_REDUCTION:
 	  if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF
 	      || is_variable_sized (OMP_CLAUSE_DECL (c)))
 	    sctx.max_vf = 1;
+	  else if (omp_is_reference (OMP_CLAUSE_DECL (c)))
+	    {
+	      tree rtype = TREE_TYPE (TREE_TYPE (OMP_CLAUSE_DECL (c)));
+	      if (!TREE_CONSTANT (TYPE_SIZE_UNIT (rtype)))
+		sctx.max_vf = 1;
+	    }
 	  break;
 	case OMP_CLAUSE_IF:
 	  if (integer_zerop (OMP_CLAUSE_IF_EXPR (c)))
@@ -4665,8 +4677,8 @@  lower_rec_input_clauses (tree clauses, g
 		  /* For reduction in SIMD loop, defer adding the
 		     initialization of the reference, because if we decide
 		     to use SIMD array for it, the initilization could cause
-		     expansion ICE.  */
-		  if (c_kind == OMP_CLAUSE_REDUCTION && is_simd)
+		     expansion ICE.  Ditto for other privatization clauses.  */
+		  if (is_simd)
 		    x = NULL_TREE;
 		  else
 		    {
@@ -4777,10 +4789,21 @@  lower_rec_input_clauses (tree clauses, g
 		  tree y = lang_hooks.decls.omp_clause_dtor (c, new_var);
 		  if ((TREE_ADDRESSABLE (new_var) || nx || y
 		       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
-		       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE__CONDTEMP_)
+		       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE__CONDTEMP_
+		       || omp_is_reference (var))
 		      && lower_rec_simd_input_clauses (new_var, ctx, &sctx,
 						       ivar, lvar))
 		    {
+		      if (omp_is_reference (var))
+			{
+			  gcc_assert (TREE_CODE (new_var) == MEM_REF);
+			  tree new_vard = TREE_OPERAND (new_var, 0);
+			  gcc_assert (DECL_P (new_vard));
+			  SET_DECL_VALUE_EXPR (new_vard,
+					       build_fold_addr_expr (lvar));
+			  DECL_HAS_VALUE_EXPR_P (new_vard) = 1;
+			}
+
 		      if (nx)
 			x = lang_hooks.decls.omp_clause_default_ctor
 						(c, unshare_expr (ivar), x);
@@ -4844,6 +4867,24 @@  lower_rec_input_clauses (tree clauses, g
 			}
 		      break;
 		    }
+		  if (omp_is_reference (var))
+		    {
+		      gcc_assert (TREE_CODE (new_var) == MEM_REF);
+		      tree new_vard = TREE_OPERAND (new_var, 0);
+		      gcc_assert (DECL_P (new_vard));
+		      tree type = TREE_TYPE (TREE_TYPE (new_vard));
+		      x = TYPE_SIZE_UNIT (type);
+		      if (TREE_CONSTANT (x))
+			{
+			  x = create_tmp_var_raw (type, get_name (var));
+			  gimple_add_tmp_var (x);
+			  TREE_ADDRESSABLE (x) = 1;
+			  x = build_fold_addr_expr_loc (clause_loc, x);
+			  x = fold_convert_loc (clause_loc,
+						TREE_TYPE (new_vard), x);
+			  gimplify_assign (new_vard, x, ilist);
+			}
+		    }
 		}
 	      if (nx)
 		gimplify_and_add (nx, ilist);
@@ -4931,6 +4972,28 @@  lower_rec_input_clauses (tree clauses, g
 
 		      if (OMP_CLAUSE_LINEAR_ARRAY (c))
 			{
+			  if (omp_is_reference (var))
+			    {
+			      gcc_assert (TREE_CODE (new_var) == MEM_REF);
+			      tree new_vard = TREE_OPERAND (new_var, 0);
+			      gcc_assert (DECL_P (new_vard));
+			      tree type = TREE_TYPE (TREE_TYPE (new_vard));
+			      nx = TYPE_SIZE_UNIT (type);
+			      if (TREE_CONSTANT (nx))
+				{
+				  nx = create_tmp_var_raw (type,
+							   get_name (var));
+				  gimple_add_tmp_var (nx);
+				  TREE_ADDRESSABLE (nx) = 1;
+				  nx = build_fold_addr_expr_loc (clause_loc,
+								 nx);
+				  nx = fold_convert_loc (clause_loc,
+							 TREE_TYPE (new_vard),
+							 nx);
+				  gimplify_assign (new_vard, nx, ilist);
+				}
+			    }
+
 			  x = lang_hooks.decls.omp_clause_linear_ctor
 							(c, new_var, x, t);
 			  gimplify_and_add (x, ilist);
@@ -4945,10 +5008,20 @@  lower_rec_input_clauses (tree clauses, g
 		    }
 
 		  if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR
-		       || TREE_ADDRESSABLE (new_var))
+		       || TREE_ADDRESSABLE (new_var)
+		       || omp_is_reference (var))
 		      && lower_rec_simd_input_clauses (new_var, ctx, &sctx,
 						       ivar, lvar))
 		    {
+		      if (omp_is_reference (var))
+			{
+			  gcc_assert (TREE_CODE (new_var) == MEM_REF);
+			  tree new_vard = TREE_OPERAND (new_var, 0);
+			  gcc_assert (DECL_P (new_vard));
+			  SET_DECL_VALUE_EXPR (new_vard,
+					       build_fold_addr_expr (lvar));
+			  DECL_HAS_VALUE_EXPR_P (new_vard) = 1;
+			}
 		      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR)
 			{
 			  tree iv = create_tmp_var (TREE_TYPE (new_var));
@@ -4983,6 +5056,24 @@  lower_rec_input_clauses (tree clauses, g
 			}
 		      break;
 		    }
+		  if (omp_is_reference (var))
+		    {
+		      gcc_assert (TREE_CODE (new_var) == MEM_REF);
+		      tree new_vard = TREE_OPERAND (new_var, 0);
+		      gcc_assert (DECL_P (new_vard));
+		      tree type = TREE_TYPE (TREE_TYPE (new_vard));
+		      nx = TYPE_SIZE_UNIT (type);
+		      if (TREE_CONSTANT (nx))
+			{
+			  nx = create_tmp_var_raw (type, get_name (var));
+			  gimple_add_tmp_var (nx);
+			  TREE_ADDRESSABLE (nx) = 1;
+			  nx = build_fold_addr_expr_loc (clause_loc, nx);
+			  nx = fold_convert_loc (clause_loc,
+						 TREE_TYPE (new_vard), nx);
+			  gimplify_assign (new_vard, nx, ilist);
+			}
+		    }
 		}
 	      x = lang_hooks.decls.omp_clause_copy_ctor
 						(c, unshare_expr (new_var), x);
--- gcc/testsuite/g++.dg/vect/simd-1.cc.jj	2019-06-04 15:17:42.046292355 +0200
+++ gcc/testsuite/g++.dg/vect/simd-1.cc	2019-06-04 15:20:29.397722531 +0200
@@ -0,0 +1,114 @@ 
+// { dg-require-effective-target vect_simd_clones }
+// { dg-additional-options "-fopenmp-simd" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+
+#include "../../gcc.dg/vect/tree-vect.h"
+
+int w;
+struct S {
+  int s, &t;
+  int *p;
+  S (int *x) : s (0), t (w), p (x) {};
+  void foo (short &, int &);
+  void bar (short &, int &);
+  void baz (short &, int &);
+  void qux (short &, int &);
+};
+
+__attribute__((noipa)) void
+S::foo (short &x, int &y)
+{
+  int *q = this->p;
+  #pragma omp simd lastprivate (x, s, t) private (y)
+  for (int i = 0; i < 1025; ++i)
+    {
+      y = q[i];
+      x = y;
+      q[i] = y * 2;
+      s = q[i] + 3;
+      t = q[i] + 6;
+    }
+}
+
+__attribute__((noipa)) void
+S::bar (short &x, int &y)
+{
+  #pragma omp simd linear (x) linear (s, t: 2) private (y)
+  for (int i = 0; i < 1025; ++i)
+    {
+      y = p[i];
+      x += y - 2 * i + 1;
+      p[i] = y * 2;
+      s += 2 * y - 4 * i + 2;
+      t += 2 * y - 4 * i + 2;
+    }
+}
+
+__attribute__((noipa)) void
+S::baz (short &x, int &y)
+{
+  int *q = this->p;
+  #pragma omp simd lastprivate (x, s, t) private (y) if (simd: 0)
+  for (int i = 0; i < 1025; ++i)
+    {
+      y = q[i];
+      x = y;
+      q[i] = y * 2;
+      s = q[i] + 3;
+      t = q[i] + 6;
+    }
+}
+
+__attribute__((noipa)) void
+S::qux (short &x, int &y)
+{
+  #pragma omp simd linear (x) linear (s, t: 2) private (y) simdlen (1)
+  for (int i = 0; i < 1025; ++i)
+    {
+      y = p[i];
+      x += y - 2 * i + 1;
+      p[i] = y * 2;
+      s += 2 * y - 4 * i + 2;
+      t += 2 * y - 4 * i + 2;
+    }
+}
+
+int
+main ()
+{
+  short x;
+  int a[1025], y;
+  check_vect ();
+  S s = a;
+  for (int i = 0; i < 1025; ++i)
+    {
+      a[i] = i;
+      asm volatile ("" : "+g" (i));
+    }
+  s.foo (x, y);
+  if (x != 1024 || s.s != 2051 || s.t != 2054)
+    abort ();
+  for (int i = 0; i < 1025; ++i)
+    if (a[i] != 2 * i)
+      abort ();
+  s.bar (x, y);
+  if (x != 2049 || s.s != 4101 || s.t != 4104)
+    abort ();
+  for (int i = 0; i < 1025; ++i)
+    if (a[i] != 4 * i)
+      abort ();
+    else
+      a[i] = i;
+  s.baz (x, y);
+  if (x != 1024 || s.s != 2051 || s.t != 2054)
+    abort ();
+  for (int i = 0; i < 1025; ++i)
+    if (a[i] != 2 * i)
+      abort ();
+  s.qux (x, y);
+  if (x != 2049 || s.s != 4101 || s.t != 4104)
+    abort ();
+  for (int i = 0; i < 1025; ++i)
+    if (a[i] != 4 * i)
+      abort ();
+}