public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
* [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax
@ 2022-07-04 14:10 Tobias Burnus
  2022-07-04 14:53 ` Jakub Jelinek
  0 siblings, 1 reply; 6+ messages in thread
From: Tobias Burnus @ 2022-07-04 14:10 UTC (permalink / raw)
  To: gcc-patches, fortran, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 824 bytes --]

This patch adds support for the OpenMP 5.2 syntax for the linear clause,
following the C/C++ patch. The testcases are modified versions from the
C/C++ ones, plus one added one for duplicated modifiers.

At least to me it is not quite clear when
   linear ( var : ref)
refers to a variable 'ref' and when to the linear-modifier 'ref'; the
spec does not seem to be very clear about it. I made an attempt, based
on the C/C++ code – but I am not positive I handle it correctly.

Tested on x86-64-gnu-linux.
OK? Or are there comments?

Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: linear.diff --]
[-- Type: text/x-patch, Size: 25826 bytes --]

OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax

Fortran part to C/C++
commit r13-1002-g03b71406323ddc065b1d7837d8b43b17e4b048b5

gcc/fortran/ChangeLog:

	* gfortran.h (gfc_omp_namelist): Update by creating 'linear' struct,
	move 'linear_op' as 'op' to id and add 'old_modifier' to it.
	* dump-parse-tree.cc (show_omp_namelist): Update accordingly.
	* module.cc (mio_omp_declare_simd): Likewise.
	* trans-openmp.cc (gfc_trans_omp_clauses): Likewise.
	* openmp.cc (resolve_omp_clauses): Likewise; accept new-style
	'val' modifier with do/simd.
	(gfc_match_omp_clauses): Handle OpenMP 5.2 linear clause syntax.

libgomp/ChangeLog:

	* libgomp.texi (OpenMP 5.2): Mark linear-clause change as 'Y'.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/linear-2.f90: New test.
	* gfortran.dg/gomp/linear-3.f90: New test.
	* gfortran.dg/gomp/linear-4.f90: New test.
	* gfortran.dg/gomp/linear-5.f90: New test.
	* gfortran.dg/gomp/linear-6.f90: New test.
	* gfortran.dg/gomp/linear-7.f90: New test.

 gcc/fortran/dump-parse-tree.cc              |   6 +-
 gcc/fortran/gfortran.h                      |   6 +-
 gcc/fortran/module.cc                       |   6 +-
 gcc/fortran/openmp.cc                       | 232 +++++++++++++++++++++++++---
 gcc/fortran/trans-openmp.cc                 |   5 +-
 gcc/testsuite/gfortran.dg/gomp/linear-2.f90 | 112 ++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-3.f90 |  39 +++++
 gcc/testsuite/gfortran.dg/gomp/linear-4.f90 | 102 ++++++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-5.f90 |  43 ++++++
 gcc/testsuite/gfortran.dg/gomp/linear-6.f90 |  54 +++++++
 gcc/testsuite/gfortran.dg/gomp/linear-7.f90 |  27 ++++
 libgomp/libgomp.texi                        |   2 +-
 12 files changed, 604 insertions(+), 30 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 85c0b98f615..5352008a63d 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1421,8 +1421,8 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  case OMP_MAP_RELEASE: fputs ("release:", dumpfile); break;
 	  default: break;
 	  }
-      else if (list_type == OMP_LIST_LINEAR)
-	switch (n->u.linear_op)
+      else if (list_type == OMP_LIST_LINEAR && n->u.linear.old_modifier)
+	switch (n->u.linear.op)
 	  {
 	  case OMP_LINEAR_REF: fputs ("ref(", dumpfile); break;
 	  case OMP_LINEAR_VAL: fputs ("val(", dumpfile); break;
@@ -1430,7 +1430,7 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  default: break;
 	  }
       fprintf (dumpfile, "%s", n->sym ? n->sym->name : "omp_all_memory");
-      if (list_type == OMP_LIST_LINEAR && n->u.linear_op != OMP_LINEAR_DEFAULT)
+      if (list_type == OMP_LIST_LINEAR && n->u.linear.op != OMP_LINEAR_DEFAULT)
 	fputc (')', dumpfile);
       if (n->expr)
 	{
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 463d9692236..696aadd7db6 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1345,7 +1345,11 @@ typedef struct gfc_omp_namelist
       gfc_omp_reduction_op reduction_op;
       gfc_omp_depend_op depend_op;
       gfc_omp_map_op map_op;
-      gfc_omp_linear_op linear_op;
+      struct
+	{
+	  ENUM_BITFIELD (gfc_omp_linear_op) op:4;
+	  bool old_modifier;
+	} linear;
       struct gfc_common_head *common;
       bool lastprivate_conditional;
     } u;
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index 85aa153bd77..5ddabdcff4d 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -4383,10 +4383,10 @@ mio_omp_declare_simd (gfc_namespace *ns, gfc_omp_declare_simd **odsp)
 	    }
 	  for (n = ods->clauses->lists[OMP_LIST_LINEAR]; n; n = n->next)
 	    {
-	      if (n->u.linear_op == OMP_LINEAR_DEFAULT)
+	      if (n->u.linear.op == OMP_LINEAR_DEFAULT)
 		mio_name (4, omp_declare_simd_clauses);
 	      else
-		mio_name (32 + n->u.linear_op, omp_declare_simd_clauses);
+		mio_name (32 + n->u.linear.op, omp_declare_simd_clauses);
 	      mio_symbol_ref (&n->sym);
 	      mio_expr (&n->expr);
 	    }
@@ -4438,7 +4438,7 @@ mio_omp_declare_simd (gfc_namespace *ns, gfc_omp_declare_simd **odsp)
 	    case 34:
 	    case 35:
 	      *ptrs[1] = n = gfc_get_omp_namelist ();
-	      n->u.linear_op = (enum gfc_omp_linear_op) (t - 32);
+	      n->u.linear.op = (enum gfc_omp_linear_op) (t - 32);
 	      t = 4;
 	      goto finish_namelist;
 	    }
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 51b429a597c..d3940cc51d0 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -2324,6 +2324,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	  if ((mask & OMP_CLAUSE_LINEAR)
 	      && gfc_match ("linear (") == MATCH_YES)
 	    {
+	      bool old_linear_modifier = false;
 	      gfc_omp_linear_op linear_op = OMP_LINEAR_DEFAULT;
 	      gfc_expr *step = NULL;
 
@@ -2331,17 +2332,26 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 					       &c->lists[OMP_LIST_LINEAR],
 					       false, NULL, &head)
 		  == MATCH_YES)
-		linear_op = OMP_LINEAR_REF;
+		{
+		  linear_op = OMP_LINEAR_REF;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list (" val (",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, NULL, &head)
 		       == MATCH_YES)
-		linear_op = OMP_LINEAR_VAL;
+		{
+		  linear_op = OMP_LINEAR_VAL;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list (" uval (",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, NULL, &head)
 		       == MATCH_YES)
-		linear_op = OMP_LINEAR_UVAL;
+		{
+		  linear_op = OMP_LINEAR_UVAL;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list ("",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, &end_colon, &head)
@@ -2364,14 +2374,183 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		      break;
 		    }
 		}
-	      if (end_colon && gfc_match (" %e )", &step) != MATCH_YES)
+	      gfc_gobble_whitespace ();
+	      if (old_linear_modifier && end_colon)
 		{
-		  gfc_free_omp_namelist (*head, false);
-		  gfc_current_locus = old_loc;
-		  *head = NULL;
-		  break;
+		  if (gfc_match (" %e )", &step) != MATCH_YES)
+		    {
+		      gfc_free_omp_namelist (*head, false);
+		      gfc_current_locus = old_loc;
+		      *head = NULL;
+		      goto error;
+		    }
+		}
+	      else if (end_colon)
+		{
+		  gfc_symtree *st;
+		  bool has_modifiers = false;
+		  bool duplicate_step = false;
+		  bool duplicate_mod = false;
+		  while (true)
+		    {
+		      old_loc = gfc_current_locus;
+		      if (gfc_match ("val )") == MATCH_YES)
+			{
+			  if (!has_modifiers)
+			    {
+			      gfc_find_sym_tree ("val", NULL, true, &st);
+			      bool has_val = (st
+					      && !st->n.sym->attr.function
+					      && !st->n.sym->attr.dimension);
+			      locus loc = gfc_current_locus;
+			      gfc_current_locus = old_loc;
+			      if (has_val
+				  && gfc_match (" %e ) ", &step) == MATCH_YES)
+				break;
+			      gfc_current_locus = loc;
+			    }
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_VAL;
+			  has_modifiers = true;
+			  break;
+			}
+		      else if (gfc_match ("val , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_VAL;
+			  has_modifiers = true;
+			  continue;
+			}
+		      else if (gfc_match ("uval )") == MATCH_YES)
+			{
+			  if (!has_modifiers)
+			    {
+			      gfc_find_sym_tree ("uval", NULL, true, &st);
+			      bool has_uval = (st
+					       && !st->n.sym->attr.function
+					       && !st->n.sym->attr.dimension);
+			      locus loc = gfc_current_locus;
+			      gfc_current_locus = old_loc;
+			      if (has_uval
+				  && gfc_match (" %e ) ", &step) == MATCH_YES)
+				break;
+			      gfc_current_locus = loc;
+			    }
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_UVAL;
+			  has_modifiers = true;
+			  break;
+			}
+		      else if (gfc_match ("uval , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_UVAL;
+			  has_modifiers = true;
+			  continue;
+			}
+		      else if (gfc_match ("ref )") == MATCH_YES)
+			{
+			  if (!has_modifiers)
+			    {
+			      gfc_find_sym_tree ("ref", NULL, true, &st);
+			      bool has_ref = (st
+					      && !st->n.sym->attr.function
+					      && !st->n.sym->attr.dimension);
+			      locus loc = gfc_current_locus;
+			      gfc_current_locus = old_loc;
+			      if (has_ref
+				  && gfc_match (" %e ) ", &step) == MATCH_YES)
+				break;
+			      gfc_current_locus = loc;
+			    }
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_REF;
+			  has_modifiers = true;
+			  break;
+			}
+		      else if (gfc_match ("ref , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_REF;
+			  has_modifiers = true;
+			  continue;
+			}
+		      else if (gfc_match ("step ( ") == MATCH_YES)
+			{
+			  if (!has_modifiers)
+			    {
+			      gfc_find_sym_tree ("step", NULL, true, &st);
+			      bool has_step
+				= (st && (st->n.sym->attr.function
+					  || st->n.sym->attr.dimension));
+			      locus loc = gfc_current_locus;
+			      gfc_current_locus = old_loc;
+			      if (has_step
+				  && gfc_match ("%e ) ", &step) == MATCH_YES)
+				break;
+			      gfc_current_locus = loc;
+			    }
+			  if (step)
+			    {
+			      duplicate_step = true;
+			      break;
+			    }
+			  has_modifiers = true;
+			  if (gfc_match ("%e ) ", &step) == MATCH_YES)
+			    {
+			      if (gfc_match (", ") == MATCH_YES)
+				continue;
+			      if (gfc_match (")") == MATCH_YES)
+				break;
+			    }
+			  gfc_free_omp_namelist (*head, false);
+			  *head = NULL;
+			  goto error;
+			}
+		      else if (!has_modifiers
+			       && gfc_match ("%e )", &step) == MATCH_YES)
+			break;
+		      else
+			{
+			  gfc_free_omp_namelist (*head, false);
+			  *head = NULL;
+			  goto error;
+			}
+		    }
+		  if (duplicate_mod || duplicate_step)
+		    {
+		      gfc_error ("Multiple %qs modifiers specified at %C",
+				 duplicate_mod ? "linear" : "step");
+		      gfc_free_omp_namelist (*head, false);
+		      *head = NULL;
+		      goto error;
+		    }
 		}
-	      else if (!end_colon)
+	      else
 		{
 		  step = gfc_get_constant_expr (BT_INTEGER,
 						gfc_default_integer_kind,
@@ -2379,9 +2558,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		  mpz_set_si (step->value.integer, 1);
 		}
 	      (*head)->expr = step;
-	      if (linear_op != OMP_LINEAR_DEFAULT)
+	      if (linear_op != OMP_LINEAR_DEFAULT || old_linear_modifier)
 		for (gfc_omp_namelist *n = *head; n; n = n->next)
-		  n->u.linear_op = linear_op;
+		  {
+		    n->u.linear.op = linear_op;
+		    n->u.linear.old_modifier = old_linear_modifier;
+		  }
 	      continue;
 	    }
 	  if ((mask & OMP_CLAUSE_LINK)
@@ -7439,28 +7621,38 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 		    break;
 		  case OMP_LIST_LINEAR:
 		    if (code
-			&& n->u.linear_op != OMP_LINEAR_DEFAULT
-			&& n->u.linear_op != linear_op)
+			&& n->u.linear.op != OMP_LINEAR_DEFAULT
+			&& n->u.linear.op != linear_op)
 		      {
-			gfc_error ("LINEAR clause modifier used on DO or SIMD"
-				   " construct at %L", &n->where);
-			linear_op = n->u.linear_op;
+			if (n->u.linear.old_modifier)
+			  {
+			    gfc_error ("LINEAR clause modifier used on DO or "
+				       "SIMD construct at %L", &n->where);
+			    linear_op = n->u.linear.op;
+			  }
+			else if (n->u.linear.op != OMP_LINEAR_VAL)
+			  {
+			    gfc_error ("LINEAR clause modifier other than VAL "
+				       "used on DO or SIMD construct at %L",
+				       &n->where);
+			    linear_op = n->u.linear.op;
+			  }
 		      }
 		    else if (omp_clauses->orderedc)
 		      gfc_error ("LINEAR clause specified together with "
 				 "ORDERED clause with argument at %L",
 				 &n->where);
-		    else if (n->u.linear_op != OMP_LINEAR_REF
+		    else if (n->u.linear.op != OMP_LINEAR_REF
 			     && n->sym->ts.type != BT_INTEGER)
 		      gfc_error ("LINEAR variable %qs must be INTEGER "
 				 "at %L", n->sym->name, &n->where);
-		    else if ((n->u.linear_op == OMP_LINEAR_REF
-			      || n->u.linear_op == OMP_LINEAR_UVAL)
+		    else if ((n->u.linear.op == OMP_LINEAR_REF
+			      || n->u.linear.op == OMP_LINEAR_UVAL)
 			     && n->sym->attr.value)
 		      gfc_error ("LINEAR dummy argument %qs with VALUE "
 				 "attribute with %s modifier at %L",
 				 n->sym->name,
-				 n->u.linear_op == OMP_LINEAR_REF
+				 n->u.linear.op == OMP_LINEAR_REF
 				 ? "REF" : "UVAL", &n->where);
 		    else if (n->expr)
 		      {
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index c6a584d36f2..de27ed52c02 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -2751,7 +2751,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 						      OMP_CLAUSE_LINEAR);
 			OMP_CLAUSE_DECL (node) = t;
 			omp_clause_linear_kind kind;
-			switch (n->u.linear_op)
+			switch (n->u.linear.op)
 			  {
 			  case OMP_LINEAR_DEFAULT:
 			    kind = OMP_CLAUSE_LINEAR_DEFAULT;
@@ -2769,7 +2769,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			    gcc_unreachable ();
 			  }
 			OMP_CLAUSE_LINEAR_KIND (node) = kind;
-			OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (node) = 1;
+			OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (node)
+			  = n->u.linear.old_modifier;
 			if (last_step_expr && last_step == NULL_TREE)
 			  {
 			    if (!declare_simd)
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-2.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-2.f90
new file mode 100644
index 00000000000..925d922ecfb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-2.f90
@@ -0,0 +1,112 @@
+! { dg-do compile }
+! { dg-options "-fopenmp -fdump-tree-original" }
+
+module m
+  implicit none (type, external)
+
+  integer i
+
+  interface
+    integer function bar (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1)) linear (y : step (2))
+    end
+
+    integer function baz (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : step (1), val)
+    end
+
+    integer function qux (x, val)
+      integer, value :: x, val
+      !$omp declare simd linear (val (x) : val) uniform (val)
+    end
+
+    integer function corge (x, val)
+      integer, value :: x, val
+      !$omp declare simd linear (x : val, step (val)) uniform (val)
+    end
+
+    integer function grault (x)
+      integer, value :: x
+      !$omp declare simd linear (x : val)
+    end
+
+    integer function step (x)
+      integer, value :: x
+    end
+  end interface
+
+contains
+
+subroutine foo (x,y)
+  integer :: x, y
+  integer :: val
+
+  val = 1
+
+  !$omp simd linear (i: step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp simd linear (i: val, step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: step (y + 1), val)
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (i: step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp parallel do simd linear (i: step (3), val)
+  do i = 0, 32, 3
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (i: val + 0)
+  do i = 0, 9
+  end do
+
+  !$omp parallel do simd linear (i: step (1) * 1)
+  do i = 0, 9
+  end do
+end
+end module
+
+! { dg-final { scan-tree-dump-times "#pragma omp parallel" 8 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for nowait" 6 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for linear\\(x:D\\.\[0-9\]+\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for linear\\(x:val,step\\(D\\.\[0-9\]+\\)\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(count.\[0-9\]:1\\) linear\\(i:D\\.\[0-9\]+\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(count.\[0-9\]:1\\) linear\\(i:val,step\\(3\\)\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) linear\\(x:D\\.\[0-9\]+\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) linear\\(x:val,step\\(D\\.\[0-9\]+\\)\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:D\\.\[0-9\]+\\)" 2 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-3.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-3.f90
new file mode 100644
index 00000000000..dee87b1a899
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-3.f90
@@ -0,0 +1,39 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m2
+  implicit none (type, external)
+
+  integer :: val
+
+contains
+integer function step (x)
+  integer, value :: x
+end
+subroutine foo(x)
+  integer, value :: x
+  !$omp declare simd linear (val (x) : step (1))	! { dg-error "requires a constant integer linear-step expression or dummy argument" }
+end
+end module m2
+
+
+module m
+  implicit none (type, external)
+
+  integer :: val
+
+contains
+integer function step (x)
+  integer, value :: x
+  !$omp declare simd linear (val (x) : step (1))	! { dg-error "Failed to match clause" }
+end
+
+integer function bar (x, y, z)
+  integer, value :: x, y, z
+  !$omp declare simd linear (val (x) : val)		! { dg-error "requires a constant integer linear-step expression or dummy argument" }
+end
+
+integer function baz (x, y, z)
+  integer, value :: x, y, z
+end
+end module m
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-4.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-4.f90
new file mode 100644
index 00000000000..f041bce7e35
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-4.f90
@@ -0,0 +1,102 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+
+integer :: i
+
+interface
+  integer function bar (x,  y, z)
+    integer :: x, y
+    integer, value :: z
+    !!$omp declare simd linear (x : ref, step (1)) linear (y : step (2), uval)
+  end
+
+  integer function baz (x, y, z)
+    integer :: x
+    integer, value :: y, z
+    !!$omp declare simd linear (x : step (1), uval)
+  end
+
+  integer function qux (x, ref)
+    integer :: x
+    integer, value :: ref
+    !!$omp declare simd linear (ref (x) : ref) uniform (ref)
+  end
+
+  integer function corge (x, ref)
+    integer :: x
+    integer, value :: ref
+    !!$omp declare simd linear (x : ref, step (ref)) uniform (ref)
+  end
+
+  integer function grault (x)
+    integer :: x
+    !$omp declare simd linear (x : ref)
+  end
+
+  integer function waldo (x)
+    integer :: x
+    !$omp declare simd linear (x : uval)
+  end
+end interface
+
+contains
+
+integer function step (x)
+  integer, value :: x
+  step = x
+end
+
+subroutine foo (x, y)
+  integer :: x, y
+  !$omp simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1), val)
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: step (1) + 0)
+  do i = 0, 9
+    x = x + step (1) + 0
+  end do
+
+  block
+    integer, parameter :: ref = 1, uval = 2
+    !$omp parallel do simd linear (x: ref + 0)
+    do i = 0, 9
+      x = x + ref + 0
+    end do
+
+    !$omp parallel do simd linear (x: uval * 1)
+    do i = 0, 9
+      x = x + uval
+    end do
+  end block
+end
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-5.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-5.f90
new file mode 100644
index 00000000000..b00492d4b58
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-5.f90
@@ -0,0 +1,43 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+integer :: i
+
+contains
+
+subroutine foo (x, y)
+  integer :: x, y
+
+  !$omp simd linear (x: step (y + 1), ref)		! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: uval, step (y + 1))		! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: ref, step (y + 1))	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1), uval)	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1), ref)	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: uval, step (y + 1))	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+end
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-6.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-6.f90
new file mode 100644
index 00000000000..57693ba6de1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-6.f90
@@ -0,0 +1,54 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+integer, parameter :: val = 1
+integer, parameter :: ref = 2
+integer, parameter :: uval = 3
+
+interface
+  integer function foo (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : step (1)) linear (ref (y) : step (2)) linear (uval (z) : step (3))
+
+! STEP is a function - thus:
+! { dg-error "'x' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-3 }
+! { dg-error "'y' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-4 }
+! { dg-error "'z' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-5 }
+
+  end
+
+  integer function bar (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : val) linear (ref (y) : ref) linear (uval (z) : uval)
+  end
+
+  integer function baz (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : ref) linear (ref (y) : uval) linear (uval (z) : val)
+  end
+
+  integer function qux (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : uval) linear (ref (y) : val) linear (uval (z) : ref)
+  end
+end interface
+contains
+  integer function step (x)
+    integer, value :: x
+     step = x
+  end
+end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-7.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-7.f90
new file mode 100644
index 00000000000..5e763a92ca6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-7.f90
@@ -0,0 +1,27 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+  implicit none (type, external)
+
+  integer i
+
+  interface
+    integer function s1 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1), val)  ! { dg-error "Multiple 'linear' modifiers specified" }
+    end
+
+    integer function s2 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1), step(2))  ! { dg-error "Multiple 'step' modifiers specified" }
+    end
+
+    integer function s3 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, ref, step(2))  ! { dg-error "Multiple 'linear' modifiers specified" }
+    end
+
+  end interface
+
+end module
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 39426ff7fbf..e88fe89a5b1 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -363,7 +363,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
 @item Clauses on @code{end} directive can be on directive @tab N @tab
 @item Deprecation of no-argument @code{destroy} clause on @code{depobj}
       @tab N @tab
-@item @code{linear} clause syntax changes and @code{step} modifier @tab P @tab only C/C++
+@item @code{linear} clause syntax changes and @code{step} modifier @tab Y @tab
 @item Deprecation of minus operator for reductions @tab N @tab
 @item Deprecation of separating @code{map} modifiers without comma @tab N @tab
 @item @code{declare mapper} with iterator and @code{present} modifiers

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax
  2022-07-04 14:10 [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax Tobias Burnus
@ 2022-07-04 14:53 ` Jakub Jelinek
  2022-07-04 16:09   ` Tobias Burnus
  0 siblings, 1 reply; 6+ messages in thread
From: Jakub Jelinek @ 2022-07-04 14:53 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran

On Mon, Jul 04, 2022 at 04:10:03PM +0200, Tobias Burnus wrote:
> This patch adds support for the OpenMP 5.2 syntax for the linear clause,
> following the C/C++ patch. The testcases are modified versions from the
> C/C++ ones, plus one added one for duplicated modifiers.
> 
> At least to me it is not quite clear when
>   linear ( var : ref)
> refers to a variable 'ref' and when to the linear-modifier 'ref'; the
> spec does not seem to be very clear about it. I made an attempt, based

See OpenMP 5.2 [59:31-34]:
A modifier that is an expression must neither lexically match the name of a simple modifier
defined for the clause that is an OpenMP keyword nor modifier-name parenthesized-tokens,
where modifier-name is the modifier-name of a complex modifier defined for the clause and
parenthesized-tokens is a token sequence that starts with ( and ends with ).

So, ref can't be step expression because it lexically matches the name of a
simple modifier, so linear (var : ref) is equivalent to old style linear (ref (var):1)
while e.g. linear (var : ref + 0) is equivalent to linear (var : step (ref + 0))

> +	      else if (end_colon)
> +		{
> +		  gfc_symtree *st;
> +		  bool has_modifiers = false;
> +		  bool duplicate_step = false;
> +		  bool duplicate_mod = false;
> +		  while (true)
> +		    {
> +		      old_loc = gfc_current_locus;
> +		      if (gfc_match ("val )") == MATCH_YES)
> +			{

So, if you see val ) even right after colon (when !old_linear_modifiers), it is
always linear modifier, so the if (!has_modifiers) looks wrong.

> +			  if (!has_modifiers)
> +			    {
> +			      gfc_find_sym_tree ("val", NULL, true, &st);
> +			      bool has_val = (st
> +					      && !st->n.sym->attr.function
> +					      && !st->n.sym->attr.dimension);
> +			      locus loc = gfc_current_locus;
> +			      gfc_current_locus = old_loc;
> +			      if (has_val
> +				  && gfc_match (" %e ) ", &step) == MATCH_YES)
> +				break;
> +			      gfc_current_locus = loc;
> +			    }
> +			  if (linear_op != OMP_LINEAR_DEFAULT)
> +			    {
> +			      duplicate_mod = true;
> +			      break;
> +			    }
> +			  linear_op = OMP_LINEAR_VAL;
> +			  has_modifiers = true;
> +			  break;
> +			}
> +		      else if (gfc_match ("uval )") == MATCH_YES)
> +			{

Likewise.

> +			  if (!has_modifiers)

> +		      else if (gfc_match ("ref )") == MATCH_YES)
> +			{

And again.

> +			  if (!has_modifiers)

> +		      else if (gfc_match ("step ( ") == MATCH_YES)
> +			{

step ( could start both valid step expression and be a valid modifier.

But that decision shouldn't be based on whether there is a step symtree or
not, but whether it is step ( whatever ) ) or step ( whatever ) ,
(in that case it should be parsed as the complex modifier with expression
in it), otherwise it is parsed as step expression.

The whatever above means some tokens with balanced parentheses.

I doubt the Fortran FE has something like that right now.

You can certainly try to match "step ( %e ) )" or "step ( %e ) , " first,
those would handle the case of valid complex modifier.
But, I think if there is
  interface
    integer function step (x, y, z)
      integer :: x, y, z
    end function step
  end interface
then
  linear (v : step (x, y, z))
should be rejected, not accepted as valid
  linear (v : step (step (x, y, z)))

I think I should add:
int step (int x, int y, int z) { return x + y + z; }

int
foo (int x)
{
  int i;
  #pragma omp parallel for linear (x : step (step (1, 2, 3)))
  for (i = 0; i < 64; i++)
    x += 6;
  return x;
}

int
bar (int x)
{
  int i;
  #pragma omp parallel for linear (x : step (1, 2, 3))	/* { dg-error "expected" } */
  for (i = 0; i < 64; i++)
    x += 6;
  return x;
}
as another testcase (where foo used to be invalid before and bar used to be
valid).

	Jakub


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax
  2022-07-04 14:53 ` Jakub Jelinek
@ 2022-07-04 16:09   ` Tobias Burnus
  2022-07-04 17:20     ` Jakub Jelinek
  0 siblings, 1 reply; 6+ messages in thread
From: Tobias Burnus @ 2022-07-04 16:09 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, fortran

[-- Attachment #1: Type: text/plain, Size: 2194 bytes --]

Hi Jakub,

thanks for the comment & spec referral. I have now updated the patch –
and included the new C/Fortran testcase.

On 04.07.22 16:53, Jakub Jelinek via Fortran wrote:
> See OpenMP 5.2 [59:31-34]:
> A modifier that is an expression must neither lexically match the name of a simple modifier
> defined for the clause that is an OpenMP keyword nor modifier-name parenthesized-tokens,
> where modifier-name is the modifier-name of a complex modifier defined for the clause and
> parenthesized-tokens is a token sequence that starts with ( and ends with ).
>
> So, ref can't be step expression because it lexically matches the name of a
> simple modifier, so linear (var : ref) is equivalent to old style linear (ref (var):1)
> while e.g. linear (var : ref + 0) is equivalent to linear (var : step (ref + 0))
I see.
> You can certainly try to match "step ( %e ) )" or "step ( %e ) , " first,
> those would handle the case of valid complex modifier.
Done so + plus some more massage in order to support the following,
added as C/Fortran testcase:
> But, I think if there is
>    interface
>      integer function step (x, y, z)
>        integer :: x, y, z
>      end function step
>    end interface
> then
>    linear (v : step (x, y, z))
> should be rejected, not accepted as valid
>    linear (v : step (step (x, y, z)))
>
> I think I should add:
> int step (int x, int y, int z) { return x + y + z; }
>
> int
> foo (int x)
> {
>    int i;
>    #pragma omp parallel for linear (x : step (step (1, 2, 3)))
>    for (i = 0; i < 64; i++)
>      x += 6;
>    return x;
> }
>
> int
> bar (int x)
> {
>    int i;
>    #pragma omp parallel for linear (x : step (1, 2, 3))       /* { dg-error "expected" } */
>    for (i = 0; i < 64; i++)
>      x += 6;
>    return x;
> }
> as another testcase (where foo used to be invalid before and bar used to be
> valid).
Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: linear-v2.diff --]
[-- Type: text/x-patch, Size: 26288 bytes --]

OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax

Fortran part to C/C++
commit r13-1002-g03b71406323ddc065b1d7837d8b43b17e4b048b5

gcc/fortran/ChangeLog:

	* gfortran.h (gfc_omp_namelist): Update by creating 'linear' struct,
	move 'linear_op' as 'op' to id and add 'old_modifier' to it.
	* dump-parse-tree.cc (show_omp_namelist): Update accordingly.
	* module.cc (mio_omp_declare_simd): Likewise.
	* trans-openmp.cc (gfc_trans_omp_clauses): Likewise.
	* openmp.cc (resolve_omp_clauses): Likewise; accept new-style
	'val' modifier with do/simd.
	(gfc_match_omp_clauses): Handle OpenMP 5.2 linear clause syntax.

libgomp/ChangeLog:

	* libgomp.texi (OpenMP 5.2): Mark linear-clause change as 'Y'.

gcc/testsuite/ChangeLog:

	* c-c++-common/gomp/linear-4.c: New test.
	* gfortran.dg/gomp/linear-2.f90: New test.
	* gfortran.dg/gomp/linear-3.f90: New test.
	* gfortran.dg/gomp/linear-4.f90: New test.
	* gfortran.dg/gomp/linear-5.f90: New test.
	* gfortran.dg/gomp/linear-6.f90: New test.
	* gfortran.dg/gomp/linear-7.f90: New test.
	* gfortran.dg/gomp/linear-8.f90: New test.

Co-authored-by: Jakub Jelinek <jakub@redhat.com>

 gcc/fortran/dump-parse-tree.cc              |   6 +-
 gcc/fortran/gfortran.h                      |   6 +-
 gcc/fortran/module.cc                       |   6 +-
 gcc/fortran/openmp.cc                       | 192 +++++++++++++++++++++++++---
 gcc/fortran/trans-openmp.cc                 |   5 +-
 gcc/testsuite/c-c++-common/gomp/linear-4.c  |  24 ++++
 gcc/testsuite/gfortran.dg/gomp/linear-2.f90 | 112 ++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-3.f90 |  39 ++++++
 gcc/testsuite/gfortran.dg/gomp/linear-4.f90 | 102 +++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-5.f90 |  43 +++++++
 gcc/testsuite/gfortran.dg/gomp/linear-6.f90 |  54 ++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-7.f90 |  27 ++++
 gcc/testsuite/gfortran.dg/gomp/linear-8.f90 |  34 +++++
 libgomp/libgomp.texi                        |   2 +-
 14 files changed, 622 insertions(+), 30 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 85c0b98f615..5352008a63d 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1421,8 +1421,8 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  case OMP_MAP_RELEASE: fputs ("release:", dumpfile); break;
 	  default: break;
 	  }
-      else if (list_type == OMP_LIST_LINEAR)
-	switch (n->u.linear_op)
+      else if (list_type == OMP_LIST_LINEAR && n->u.linear.old_modifier)
+	switch (n->u.linear.op)
 	  {
 	  case OMP_LINEAR_REF: fputs ("ref(", dumpfile); break;
 	  case OMP_LINEAR_VAL: fputs ("val(", dumpfile); break;
@@ -1430,7 +1430,7 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  default: break;
 	  }
       fprintf (dumpfile, "%s", n->sym ? n->sym->name : "omp_all_memory");
-      if (list_type == OMP_LIST_LINEAR && n->u.linear_op != OMP_LINEAR_DEFAULT)
+      if (list_type == OMP_LIST_LINEAR && n->u.linear.op != OMP_LINEAR_DEFAULT)
 	fputc (')', dumpfile);
       if (n->expr)
 	{
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 463d9692236..696aadd7db6 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1345,7 +1345,11 @@ typedef struct gfc_omp_namelist
       gfc_omp_reduction_op reduction_op;
       gfc_omp_depend_op depend_op;
       gfc_omp_map_op map_op;
-      gfc_omp_linear_op linear_op;
+      struct
+	{
+	  ENUM_BITFIELD (gfc_omp_linear_op) op:4;
+	  bool old_modifier;
+	} linear;
       struct gfc_common_head *common;
       bool lastprivate_conditional;
     } u;
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index 85aa153bd77..5ddabdcff4d 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -4383,10 +4383,10 @@ mio_omp_declare_simd (gfc_namespace *ns, gfc_omp_declare_simd **odsp)
 	    }
 	  for (n = ods->clauses->lists[OMP_LIST_LINEAR]; n; n = n->next)
 	    {
-	      if (n->u.linear_op == OMP_LINEAR_DEFAULT)
+	      if (n->u.linear.op == OMP_LINEAR_DEFAULT)
 		mio_name (4, omp_declare_simd_clauses);
 	      else
-		mio_name (32 + n->u.linear_op, omp_declare_simd_clauses);
+		mio_name (32 + n->u.linear.op, omp_declare_simd_clauses);
 	      mio_symbol_ref (&n->sym);
 	      mio_expr (&n->expr);
 	    }
@@ -4438,7 +4438,7 @@ mio_omp_declare_simd (gfc_namespace *ns, gfc_omp_declare_simd **odsp)
 	    case 34:
 	    case 35:
 	      *ptrs[1] = n = gfc_get_omp_namelist ();
-	      n->u.linear_op = (enum gfc_omp_linear_op) (t - 32);
+	      n->u.linear.op = (enum gfc_omp_linear_op) (t - 32);
 	      t = 4;
 	      goto finish_namelist;
 	    }
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 51b429a597c..f2c0202e440 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -2324,6 +2324,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	  if ((mask & OMP_CLAUSE_LINEAR)
 	      && gfc_match ("linear (") == MATCH_YES)
 	    {
+	      bool old_linear_modifier = false;
 	      gfc_omp_linear_op linear_op = OMP_LINEAR_DEFAULT;
 	      gfc_expr *step = NULL;
 
@@ -2331,17 +2332,26 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 					       &c->lists[OMP_LIST_LINEAR],
 					       false, NULL, &head)
 		  == MATCH_YES)
-		linear_op = OMP_LINEAR_REF;
+		{
+		  linear_op = OMP_LINEAR_REF;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list (" val (",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, NULL, &head)
 		       == MATCH_YES)
-		linear_op = OMP_LINEAR_VAL;
+		{
+		  linear_op = OMP_LINEAR_VAL;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list (" uval (",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, NULL, &head)
 		       == MATCH_YES)
-		linear_op = OMP_LINEAR_UVAL;
+		{
+		  linear_op = OMP_LINEAR_UVAL;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list ("",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, &end_colon, &head)
@@ -2364,14 +2374,143 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		      break;
 		    }
 		}
-	      if (end_colon && gfc_match (" %e )", &step) != MATCH_YES)
+	      gfc_gobble_whitespace ();
+	      if (old_linear_modifier && end_colon)
 		{
-		  gfc_free_omp_namelist (*head, false);
-		  gfc_current_locus = old_loc;
-		  *head = NULL;
-		  break;
+		  if (gfc_match (" %e )", &step) != MATCH_YES)
+		    {
+		      gfc_free_omp_namelist (*head, false);
+		      gfc_current_locus = old_loc;
+		      *head = NULL;
+		      goto error;
+		    }
 		}
-	      else if (!end_colon)
+	      else if (end_colon)
+		{
+		  bool has_error = false;
+		  bool has_modifiers = false;
+		  bool has_step = false;
+		  bool duplicate_step = false;
+		  bool duplicate_mod = false;
+		  while (true)
+		    {
+		      old_loc = gfc_current_locus;
+		      if (gfc_match ("val )") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_VAL;
+			  has_modifiers = true;
+			  break;
+			}
+		      else if (gfc_match ("val , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_VAL;
+			  has_modifiers = true;
+			  continue;
+			}
+		      else if (gfc_match ("uval )") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_UVAL;
+			  has_modifiers = true;
+			  break;
+			}
+		      else if (gfc_match ("uval , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_UVAL;
+			  has_modifiers = true;
+			  continue;
+			}
+		      else if (gfc_match ("ref )") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_REF;
+			  has_modifiers = true;
+			  break;
+			}
+		      else if (gfc_match ("ref , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_REF;
+			  has_modifiers = true;
+			  continue;
+			}
+		      else if (gfc_match ("step ( %e ) )", &step) == MATCH_YES)
+			{
+			  if (has_step)
+			    {
+			      duplicate_step = true;
+			      break;
+			    }
+			  has_modifiers = has_step = true;
+			  break;
+			}
+		      else if (gfc_match ("step ( %e ) , ", &step) == MATCH_YES)
+			{
+			  if (has_step)
+			    {
+			      duplicate_step = true;
+			      break;
+			    }
+			  has_modifiers = has_step = true;
+			  continue;
+			}
+		      else if (!has_modifiers
+			       && gfc_match ("%e )", &step) == MATCH_YES)
+			{
+			  if ((step->expr_type == EXPR_FUNCTION
+				|| step->expr_type == EXPR_VARIABLE)
+			      && strcmp (step->symtree->name, "step") == 0)
+			    {
+			      gfc_current_locus = old_loc;
+			      gfc_match ("step (");
+			      has_error = true;
+			    }
+			  break;
+			}
+		      has_error = true;
+		      break;
+		    }
+		  if (duplicate_mod || duplicate_step)
+		    {
+		      gfc_error ("Multiple %qs modifiers specified at %C",
+				 duplicate_mod ? "linear" : "step");
+		      has_error = true;
+		    }
+		  if (has_error)
+		    {
+		      gfc_free_omp_namelist (*head, false);
+		      *head = NULL;
+		      goto error;
+		    }
+		}
+	      else
 		{
 		  step = gfc_get_constant_expr (BT_INTEGER,
 						gfc_default_integer_kind,
@@ -2379,9 +2518,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		  mpz_set_si (step->value.integer, 1);
 		}
 	      (*head)->expr = step;
-	      if (linear_op != OMP_LINEAR_DEFAULT)
+	      if (linear_op != OMP_LINEAR_DEFAULT || old_linear_modifier)
 		for (gfc_omp_namelist *n = *head; n; n = n->next)
-		  n->u.linear_op = linear_op;
+		  {
+		    n->u.linear.op = linear_op;
+		    n->u.linear.old_modifier = old_linear_modifier;
+		  }
 	      continue;
 	    }
 	  if ((mask & OMP_CLAUSE_LINK)
@@ -7439,28 +7581,38 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 		    break;
 		  case OMP_LIST_LINEAR:
 		    if (code
-			&& n->u.linear_op != OMP_LINEAR_DEFAULT
-			&& n->u.linear_op != linear_op)
+			&& n->u.linear.op != OMP_LINEAR_DEFAULT
+			&& n->u.linear.op != linear_op)
 		      {
-			gfc_error ("LINEAR clause modifier used on DO or SIMD"
-				   " construct at %L", &n->where);
-			linear_op = n->u.linear_op;
+			if (n->u.linear.old_modifier)
+			  {
+			    gfc_error ("LINEAR clause modifier used on DO or "
+				       "SIMD construct at %L", &n->where);
+			    linear_op = n->u.linear.op;
+			  }
+			else if (n->u.linear.op != OMP_LINEAR_VAL)
+			  {
+			    gfc_error ("LINEAR clause modifier other than VAL "
+				       "used on DO or SIMD construct at %L",
+				       &n->where);
+			    linear_op = n->u.linear.op;
+			  }
 		      }
 		    else if (omp_clauses->orderedc)
 		      gfc_error ("LINEAR clause specified together with "
 				 "ORDERED clause with argument at %L",
 				 &n->where);
-		    else if (n->u.linear_op != OMP_LINEAR_REF
+		    else if (n->u.linear.op != OMP_LINEAR_REF
 			     && n->sym->ts.type != BT_INTEGER)
 		      gfc_error ("LINEAR variable %qs must be INTEGER "
 				 "at %L", n->sym->name, &n->where);
-		    else if ((n->u.linear_op == OMP_LINEAR_REF
-			      || n->u.linear_op == OMP_LINEAR_UVAL)
+		    else if ((n->u.linear.op == OMP_LINEAR_REF
+			      || n->u.linear.op == OMP_LINEAR_UVAL)
 			     && n->sym->attr.value)
 		      gfc_error ("LINEAR dummy argument %qs with VALUE "
 				 "attribute with %s modifier at %L",
 				 n->sym->name,
-				 n->u.linear_op == OMP_LINEAR_REF
+				 n->u.linear.op == OMP_LINEAR_REF
 				 ? "REF" : "UVAL", &n->where);
 		    else if (n->expr)
 		      {
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index c6a584d36f2..de27ed52c02 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -2751,7 +2751,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 						      OMP_CLAUSE_LINEAR);
 			OMP_CLAUSE_DECL (node) = t;
 			omp_clause_linear_kind kind;
-			switch (n->u.linear_op)
+			switch (n->u.linear.op)
 			  {
 			  case OMP_LINEAR_DEFAULT:
 			    kind = OMP_CLAUSE_LINEAR_DEFAULT;
@@ -2769,7 +2769,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			    gcc_unreachable ();
 			  }
 			OMP_CLAUSE_LINEAR_KIND (node) = kind;
-			OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (node) = 1;
+			OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (node)
+			  = n->u.linear.old_modifier;
 			if (last_step_expr && last_step == NULL_TREE)
 			  {
 			    if (!declare_simd)
diff --git a/gcc/testsuite/c-c++-common/gomp/linear-4.c b/gcc/testsuite/c-c++-common/gomp/linear-4.c
new file mode 100644
index 00000000000..1e595213c38
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/linear-4.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int step (int x, int y, int z) { return x + y + z; }
+
+int
+foo (int x)
+{
+  int i;
+  #pragma omp parallel for linear (x : step (step (1, 2, 3)))
+  for (i = 0; i < 64; i++)
+    x += 6;
+  return x;
+}
+
+int
+bar (int x)
+{
+  int i;
+  #pragma omp parallel for linear (x : step (1, 2, 3))	/* { dg-error "expected" } */
+  for (i = 0; i < 64; i++)
+    x += 6;
+  return x;
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-2.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-2.f90
new file mode 100644
index 00000000000..05f007fd5c2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-2.f90
@@ -0,0 +1,112 @@
+! { dg-do compile }
+! { dg-options "-fopenmp -fdump-tree-original" }
+
+module m
+  implicit none (type, external)
+
+  integer i
+
+  interface
+    integer function bar (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1)) linear (y : step (2))
+    end
+
+    integer function baz (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : step (1), val)
+    end
+
+    integer function qux (x, val)
+      integer, value :: x, val
+      !$omp declare simd linear (val (x) : val) uniform (val)
+    end
+
+    integer function corge (x, val)
+      integer, value :: x, val
+      !$omp declare simd linear (x : val, step (val)) uniform (val)
+    end
+
+    integer function grault (x)
+      integer, value :: x
+      !$omp declare simd linear (x : val)
+    end
+
+    integer function step (x)
+      integer, value :: x
+    end
+  end interface
+
+contains
+
+subroutine foo (x,y)
+  integer :: x, y
+  integer :: val
+
+  val = 1
+
+  !$omp simd linear (i: step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp simd linear (i: val, step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: step (y + 1), val)
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (i: step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp parallel do simd linear (i: step (3), val)
+  do i = 0, 32, 3
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (i: val + 0)
+  do i = 0, 9
+  end do
+
+  !$omp parallel do simd linear (i: step (1) * 1)
+  do i = 0, 9
+  end do
+end
+end module
+
+! { dg-final { scan-tree-dump-times "#pragma omp parallel" 8 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for nowait" 6 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for linear\\(x:D\\.\[0-9\]+\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for linear\\(x:val,step\\(D\\.\[0-9\]+\\)\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(count\\.\[0-9\]:1\\) linear\\(i:3\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(count\\.\[0-9\]:1\\) linear\\(i:val,step\\(3\\)\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) linear\\(x:D\\.\[0-9\]+\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) linear\\(x:val,step\\(D\\.\[0-9\]+\\)\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:D\\.\[0-9\]+\\)" 2 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-3.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-3.f90
new file mode 100644
index 00000000000..dee87b1a899
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-3.f90
@@ -0,0 +1,39 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m2
+  implicit none (type, external)
+
+  integer :: val
+
+contains
+integer function step (x)
+  integer, value :: x
+end
+subroutine foo(x)
+  integer, value :: x
+  !$omp declare simd linear (val (x) : step (1))	! { dg-error "requires a constant integer linear-step expression or dummy argument" }
+end
+end module m2
+
+
+module m
+  implicit none (type, external)
+
+  integer :: val
+
+contains
+integer function step (x)
+  integer, value :: x
+  !$omp declare simd linear (val (x) : step (1))	! { dg-error "Failed to match clause" }
+end
+
+integer function bar (x, y, z)
+  integer, value :: x, y, z
+  !$omp declare simd linear (val (x) : val)		! { dg-error "requires a constant integer linear-step expression or dummy argument" }
+end
+
+integer function baz (x, y, z)
+  integer, value :: x, y, z
+end
+end module m
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-4.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-4.f90
new file mode 100644
index 00000000000..51c41b3aad9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-4.f90
@@ -0,0 +1,102 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+
+integer :: i
+
+interface
+  integer function bar (x,  y, z)
+    integer :: x, y
+    integer, value :: z
+    !!$omp declare simd linear (x : ref, step (1)) linear (y : step (2), uval)
+  end
+
+  integer function baz (x, y, z)
+    integer :: x
+    integer, value :: y, z
+    !!$omp declare simd linear (x : step (1), uval)
+  end
+
+  integer function qux (x, ref)
+    integer :: x
+    integer, value :: ref
+    !!$omp declare simd linear (ref (x) : ref) uniform (ref)
+  end
+
+  integer function corge (x, ref)
+    integer :: x
+    integer, value :: ref
+    !!$omp declare simd linear (x : ref, step (ref)) uniform (ref)
+  end
+
+  integer function grault (x)
+    integer :: x
+    !!$omp declare simd linear (x : ref)
+  end
+
+  integer function waldo (x)
+    integer :: x
+    !!$omp declare simd linear (x : uval)
+  end
+end interface
+
+contains
+
+integer function step (x)
+  integer, value :: x
+  step = x
+end
+
+subroutine foo (x, y)
+  integer :: x, y
+  !!$omp simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !!$omp simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !!$omp parallel do linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !!$omp parallel do linear (x: step (y + 1), val)
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !!$omp parallel do simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !!$omp parallel do simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !!$omp parallel do simd linear (x: step (1) + 0)
+  do i = 0, 9
+    x = x + step (1) + 0
+  end do
+
+  block
+    integer, parameter :: ref = 1, uval = 2
+    !!$omp parallel do simd linear (x: ref + 0)
+    do i = 0, 9
+      x = x + ref + 0
+    end do
+
+    !$omp parallel do simd linear (x: uval * 1)
+    do i = 0, 9
+      x = x + uval
+    end do
+  end block
+end
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-5.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-5.f90
new file mode 100644
index 00000000000..b00492d4b58
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-5.f90
@@ -0,0 +1,43 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+integer :: i
+
+contains
+
+subroutine foo (x, y)
+  integer :: x, y
+
+  !$omp simd linear (x: step (y + 1), ref)		! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: uval, step (y + 1))		! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: ref, step (y + 1))	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1), uval)	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1), ref)	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: uval, step (y + 1))	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+end
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-6.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-6.f90
new file mode 100644
index 00000000000..57693ba6de1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-6.f90
@@ -0,0 +1,54 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+integer, parameter :: val = 1
+integer, parameter :: ref = 2
+integer, parameter :: uval = 3
+
+interface
+  integer function foo (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : step (1)) linear (ref (y) : step (2)) linear (uval (z) : step (3))
+
+! STEP is a function - thus:
+! { dg-error "'x' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-3 }
+! { dg-error "'y' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-4 }
+! { dg-error "'z' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-5 }
+
+  end
+
+  integer function bar (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : val) linear (ref (y) : ref) linear (uval (z) : uval)
+  end
+
+  integer function baz (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : ref) linear (ref (y) : uval) linear (uval (z) : val)
+  end
+
+  integer function qux (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : uval) linear (ref (y) : val) linear (uval (z) : ref)
+  end
+end interface
+contains
+  integer function step (x)
+    integer, value :: x
+     step = x
+  end
+end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-7.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-7.f90
new file mode 100644
index 00000000000..5e763a92ca6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-7.f90
@@ -0,0 +1,27 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+  implicit none (type, external)
+
+  integer i
+
+  interface
+    integer function s1 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1), val)  ! { dg-error "Multiple 'linear' modifiers specified" }
+    end
+
+    integer function s2 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1), step(2))  ! { dg-error "Multiple 'step' modifiers specified" }
+    end
+
+    integer function s3 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, ref, step(2))  ! { dg-error "Multiple 'linear' modifiers specified" }
+    end
+
+  end interface
+
+end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-8.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-8.f90
new file mode 100644
index 00000000000..3274a5bd1e4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-8.f90
@@ -0,0 +1,34 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+  implicit none (type, external)
+
+  interface
+    integer function step (x, y, z)
+      integer :: x, y, z
+    end function step
+  end interface
+
+contains
+
+integer function foo (x)
+  integer, value :: x
+  integer :: i
+  !$omp parallel do linear (x : step (step (1, 2, 3)))
+  do i = 0, 63
+    x = x + 6
+  end do
+  foo = x
+end
+
+integer function bar (x)
+  integer, value :: x
+  integer :: i
+  !$omp parallel do linear (x : step (1, 2, 3))	! { dg-error "40: Invalid character in name" }
+  do i = 0, 63
+    x = x + 6
+  end do
+  bar = x
+end
+end module
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 39426ff7fbf..e88fe89a5b1 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -363,7 +363,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
 @item Clauses on @code{end} directive can be on directive @tab N @tab
 @item Deprecation of no-argument @code{destroy} clause on @code{depobj}
       @tab N @tab
-@item @code{linear} clause syntax changes and @code{step} modifier @tab P @tab only C/C++
+@item @code{linear} clause syntax changes and @code{step} modifier @tab Y @tab
 @item Deprecation of minus operator for reductions @tab N @tab
 @item Deprecation of separating @code{map} modifiers without comma @tab N @tab
 @item @code{declare mapper} with iterator and @code{present} modifiers

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax
  2022-07-04 16:09   ` Tobias Burnus
@ 2022-07-04 17:20     ` Jakub Jelinek
  2022-07-04 18:29       ` Tobias Burnus
  0 siblings, 1 reply; 6+ messages in thread
From: Jakub Jelinek @ 2022-07-04 17:20 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran

On Mon, Jul 04, 2022 at 06:09:31PM +0200, Tobias Burnus wrote:
> thanks for the comment & spec referral. I have now updated the patch –
> and included the new C/Fortran testcase.

Thanks.

> +		  while (true)
> +		    {
> +		      old_loc = gfc_current_locus;
> +		      if (gfc_match ("val )") == MATCH_YES)
> +			{
> +			  if (linear_op != OMP_LINEAR_DEFAULT)
> +			    {
> +			      duplicate_mod = true;
> +			      break;
> +			    }
> +			  linear_op = OMP_LINEAR_VAL;
> +			  has_modifiers = true;
> +			  break;
> +			}
> +		      else if (gfc_match ("val , ") == MATCH_YES)
> +			{
> +			  if (linear_op != OMP_LINEAR_DEFAULT)
> +			    {
> +			      duplicate_mod = true;
> +			      break;
> +			    }
> +			  linear_op = OMP_LINEAR_VAL;
> +			  has_modifiers = true;
> +			  continue;
> +			}

Perhaps you could avoid some code duplication by doing it like:
		      bool close_paren = gfc_match ("val )") == MATCH_YES;
		      if (close_paren || gfc_match ("val , ") == MATCH_YES)
			{
			  if (linear_op != OMP_LINEAR_DEFAULT)
			    {
			      duplicate_mod = true;
			      break;
			    }
			  linear_op = OMP_LINEAR_VAL;
			  has_modifiers = true;
			  if (close_paren)
			    break;
			  else
			    continue;
			}
and similarly for uval and ref.

> +		      else if (!has_modifiers
> +			       && gfc_match ("%e )", &step) == MATCH_YES)
> +			{
> +			  if ((step->expr_type == EXPR_FUNCTION
> +				|| step->expr_type == EXPR_VARIABLE)
> +			      && strcmp (step->symtree->name, "step") == 0)
> +			    {
> +			      gfc_current_locus = old_loc;
> +			      gfc_match ("step (");
> +			      has_error = true;
> +			    }

I think the above should accept even
linear (v : step (1) + 0) or linear (v : step (1, 2, 3) * 1)
which is desirable, because step then will be some other operation (hope
folding isn't performed yet).

> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/gomp/linear-4.f90
> @@ -0,0 +1,102 @@
> +! { dg-do compile }
> +! { dg-options "-fopenmp" }
> +
> +module m
> +implicit none
> +
> +integer :: i
> +
> +interface
> +  integer function bar (x,  y, z)
> +    integer :: x, y
> +    integer, value :: z
> +    !!$omp declare simd linear (x : ref, step (1)) linear (y : step (2), uval)

Are all these !! intentional?
The test then doesn't test much.

Or is that a FIXME?

	Jakub


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax
  2022-07-04 17:20     ` Jakub Jelinek
@ 2022-07-04 18:29       ` Tobias Burnus
  2022-07-04 19:08         ` Jakub Jelinek
  0 siblings, 1 reply; 6+ messages in thread
From: Tobias Burnus @ 2022-07-04 18:29 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, fortran

[-- Attachment #1: Type: text/plain, Size: 1834 bytes --]


On 04.07.22 19:20, Jakub Jelinek wrote:
> Perhaps you could avoid some code duplication by doing it like:
>                     bool close_paren = gfc_match ("val )") == MATCH_YES;
>                     if (close_paren || gfc_match ("val , ") == MATCH_YES)

Done!

Good idea! I was thinking of things like ...peek_char() but that takes
the next char and not the last one; but your method works.

>> +                  else if (!has_modifiers
>> +                           && gfc_match ("%e )", &step) == MATCH_YES)
>> +                    {
>> +                      if ((step->expr_type == EXPR_FUNCTION
>> +                            || step->expr_type == EXPR_VARIABLE)
>> +                          && strcmp (step->symtree->name, "step") == 0)
>> +                        {
>> +                          gfc_current_locus = old_loc;
>> +                          gfc_match ("step (");
>> +                          has_error = true;
>> +                        }
> I think the above should accept even
> linear (v : step (1) + 0) or linear (v : step (1, 2, 3) * 1)
> which is desirable, because step then will be some other operation (hope
> folding isn't performed yet).
Well, it does. In that case expr_type == EXPR_OP. I added the latter to
the C/C++ and the Fortran testcase.
>> +    !!$omp declare simd linear (x : ref, step (1)) linear (y : step (2), uval)
> Are all these !! intentional?
No – just a missed undo after debugging. It worked/works after changing
it back to '!'.

Revised version attached.

Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: linear-v3.diff --]
[-- Type: text/x-patch, Size: 26096 bytes --]

OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax

Fortran part to C/C++
commit r13-1002-g03b71406323ddc065b1d7837d8b43b17e4b048b5

gcc/fortran/ChangeLog:

	* gfortran.h (gfc_omp_namelist): Update by creating 'linear' struct,
	move 'linear_op' as 'op' to id and add 'old_modifier' to it.
	* dump-parse-tree.cc (show_omp_namelist): Update accordingly.
	* module.cc (mio_omp_declare_simd): Likewise.
	* trans-openmp.cc (gfc_trans_omp_clauses): Likewise.
	* openmp.cc (resolve_omp_clauses): Likewise; accept new-style
	'val' modifier with do/simd.
	(gfc_match_omp_clauses): Handle OpenMP 5.2 linear clause syntax.

libgomp/ChangeLog:

	* libgomp.texi (OpenMP 5.2): Mark linear-clause change as 'Y'.

gcc/testsuite/ChangeLog:

	* c-c++-common/gomp/linear-4.c: New test.
	* gfortran.dg/gomp/linear-2.f90: New test.
	* gfortran.dg/gomp/linear-3.f90: New test.
	* gfortran.dg/gomp/linear-4.f90: New test.
	* gfortran.dg/gomp/linear-5.f90: New test.
	* gfortran.dg/gomp/linear-6.f90: New test.
	* gfortran.dg/gomp/linear-7.f90: New test.
	* gfortran.dg/gomp/linear-8.f90: New test.

Co-authored-by: Jakub Jelinek <jakub@redhat.com>

 gcc/fortran/dump-parse-tree.cc              |   6 +-
 gcc/fortran/gfortran.h                      |   6 +-
 gcc/fortran/module.cc                       |   6 +-
 gcc/fortran/openmp.cc                       | 163 ++++++++++++++++++++++++----
 gcc/fortran/trans-openmp.cc                 |   5 +-
 gcc/testsuite/c-c++-common/gomp/linear-4.c  |  34 ++++++
 gcc/testsuite/gfortran.dg/gomp/linear-2.f90 | 112 +++++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-3.f90 |  39 +++++++
 gcc/testsuite/gfortran.dg/gomp/linear-4.f90 | 102 +++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-5.f90 |  43 ++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-6.f90 |  54 +++++++++
 gcc/testsuite/gfortran.dg/gomp/linear-7.f90 |  27 +++++
 gcc/testsuite/gfortran.dg/gomp/linear-8.f90 |  44 ++++++++
 libgomp/libgomp.texi                        |   2 +-
 14 files changed, 613 insertions(+), 30 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 85c0b98f615..5352008a63d 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1421,8 +1421,8 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  case OMP_MAP_RELEASE: fputs ("release:", dumpfile); break;
 	  default: break;
 	  }
-      else if (list_type == OMP_LIST_LINEAR)
-	switch (n->u.linear_op)
+      else if (list_type == OMP_LIST_LINEAR && n->u.linear.old_modifier)
+	switch (n->u.linear.op)
 	  {
 	  case OMP_LINEAR_REF: fputs ("ref(", dumpfile); break;
 	  case OMP_LINEAR_VAL: fputs ("val(", dumpfile); break;
@@ -1430,7 +1430,7 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  default: break;
 	  }
       fprintf (dumpfile, "%s", n->sym ? n->sym->name : "omp_all_memory");
-      if (list_type == OMP_LIST_LINEAR && n->u.linear_op != OMP_LINEAR_DEFAULT)
+      if (list_type == OMP_LIST_LINEAR && n->u.linear.op != OMP_LINEAR_DEFAULT)
 	fputc (')', dumpfile);
       if (n->expr)
 	{
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 463d9692236..696aadd7db6 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1345,7 +1345,11 @@ typedef struct gfc_omp_namelist
       gfc_omp_reduction_op reduction_op;
       gfc_omp_depend_op depend_op;
       gfc_omp_map_op map_op;
-      gfc_omp_linear_op linear_op;
+      struct
+	{
+	  ENUM_BITFIELD (gfc_omp_linear_op) op:4;
+	  bool old_modifier;
+	} linear;
       struct gfc_common_head *common;
       bool lastprivate_conditional;
     } u;
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index 85aa153bd77..5ddabdcff4d 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -4383,10 +4383,10 @@ mio_omp_declare_simd (gfc_namespace *ns, gfc_omp_declare_simd **odsp)
 	    }
 	  for (n = ods->clauses->lists[OMP_LIST_LINEAR]; n; n = n->next)
 	    {
-	      if (n->u.linear_op == OMP_LINEAR_DEFAULT)
+	      if (n->u.linear.op == OMP_LINEAR_DEFAULT)
 		mio_name (4, omp_declare_simd_clauses);
 	      else
-		mio_name (32 + n->u.linear_op, omp_declare_simd_clauses);
+		mio_name (32 + n->u.linear.op, omp_declare_simd_clauses);
 	      mio_symbol_ref (&n->sym);
 	      mio_expr (&n->expr);
 	    }
@@ -4438,7 +4438,7 @@ mio_omp_declare_simd (gfc_namespace *ns, gfc_omp_declare_simd **odsp)
 	    case 34:
 	    case 35:
 	      *ptrs[1] = n = gfc_get_omp_namelist ();
-	      n->u.linear_op = (enum gfc_omp_linear_op) (t - 32);
+	      n->u.linear.op = (enum gfc_omp_linear_op) (t - 32);
 	      t = 4;
 	      goto finish_namelist;
 	    }
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 51b429a597c..bd4ff259fe0 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -2324,6 +2324,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	  if ((mask & OMP_CLAUSE_LINEAR)
 	      && gfc_match ("linear (") == MATCH_YES)
 	    {
+	      bool old_linear_modifier = false;
 	      gfc_omp_linear_op linear_op = OMP_LINEAR_DEFAULT;
 	      gfc_expr *step = NULL;
 
@@ -2331,17 +2332,26 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 					       &c->lists[OMP_LIST_LINEAR],
 					       false, NULL, &head)
 		  == MATCH_YES)
-		linear_op = OMP_LINEAR_REF;
+		{
+		  linear_op = OMP_LINEAR_REF;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list (" val (",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, NULL, &head)
 		       == MATCH_YES)
-		linear_op = OMP_LINEAR_VAL;
+		{
+		  linear_op = OMP_LINEAR_VAL;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list (" uval (",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, NULL, &head)
 		       == MATCH_YES)
-		linear_op = OMP_LINEAR_UVAL;
+		{
+		  linear_op = OMP_LINEAR_UVAL;
+		  old_linear_modifier = true;
+		}
 	      else if (gfc_match_omp_variable_list ("",
 						    &c->lists[OMP_LIST_LINEAR],
 						    false, &end_colon, &head)
@@ -2364,14 +2374,114 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		      break;
 		    }
 		}
-	      if (end_colon && gfc_match (" %e )", &step) != MATCH_YES)
+	      gfc_gobble_whitespace ();
+	      if (old_linear_modifier && end_colon)
 		{
-		  gfc_free_omp_namelist (*head, false);
-		  gfc_current_locus = old_loc;
-		  *head = NULL;
-		  break;
+		  if (gfc_match (" %e )", &step) != MATCH_YES)
+		    {
+		      gfc_free_omp_namelist (*head, false);
+		      gfc_current_locus = old_loc;
+		      *head = NULL;
+		      goto error;
+		    }
 		}
-	      else if (!end_colon)
+	      else if (end_colon)
+		{
+		  bool has_error = false;
+		  bool has_modifiers = false;
+		  bool has_step = false;
+		  bool duplicate_step = false;
+		  bool duplicate_mod = false;
+		  while (true)
+		    {
+		      old_loc = gfc_current_locus;
+		      bool close_paren = gfc_match ("val )") == MATCH_YES;
+		      if (close_paren || gfc_match ("val , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_VAL;
+			  has_modifiers = true;
+			  if (close_paren)
+			    break;
+			  continue;
+			}
+		      close_paren = gfc_match ("uval )") == MATCH_YES;
+		      if (close_paren || gfc_match ("uval , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_UVAL;
+			  has_modifiers = true;
+			  if (close_paren)
+			    break;
+			  continue;
+			}
+		      close_paren = gfc_match ("ref )") == MATCH_YES;
+		      if (close_paren || gfc_match ("ref , ") == MATCH_YES)
+			{
+			  if (linear_op != OMP_LINEAR_DEFAULT)
+			    {
+			      duplicate_mod = true;
+			      break;
+			    }
+			  linear_op = OMP_LINEAR_REF;
+			  has_modifiers = true;
+			  if (close_paren)
+			    break;
+			  continue;
+			}
+		      close_paren = (gfc_match ("step ( %e ) )", &step)
+				     == MATCH_YES);
+		      if (close_paren
+			  || gfc_match ("step ( %e ) , ", &step) == MATCH_YES)
+			{
+			  if (has_step)
+			    {
+			      duplicate_step = true;
+			      break;
+			    }
+			  has_modifiers = has_step = true;
+			  if (close_paren)
+			    break;
+			  continue;
+			}
+		      if (!has_modifiers
+			  && gfc_match ("%e )", &step) == MATCH_YES)
+			{
+			  if ((step->expr_type == EXPR_FUNCTION
+				|| step->expr_type == EXPR_VARIABLE)
+			      && strcmp (step->symtree->name, "step") == 0)
+			    {
+			      gfc_current_locus = old_loc;
+			      gfc_match ("step (");
+			      has_error = true;
+			    }
+			  break;
+			}
+		      has_error = true;
+		      break;
+		    }
+		  if (duplicate_mod || duplicate_step)
+		    {
+		      gfc_error ("Multiple %qs modifiers specified at %C",
+				 duplicate_mod ? "linear" : "step");
+		      has_error = true;
+		    }
+		  if (has_error)
+		    {
+		      gfc_free_omp_namelist (*head, false);
+		      *head = NULL;
+		      goto error;
+		    }
+		}
+	      else
 		{
 		  step = gfc_get_constant_expr (BT_INTEGER,
 						gfc_default_integer_kind,
@@ -2379,9 +2489,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		  mpz_set_si (step->value.integer, 1);
 		}
 	      (*head)->expr = step;
-	      if (linear_op != OMP_LINEAR_DEFAULT)
+	      if (linear_op != OMP_LINEAR_DEFAULT || old_linear_modifier)
 		for (gfc_omp_namelist *n = *head; n; n = n->next)
-		  n->u.linear_op = linear_op;
+		  {
+		    n->u.linear.op = linear_op;
+		    n->u.linear.old_modifier = old_linear_modifier;
+		  }
 	      continue;
 	    }
 	  if ((mask & OMP_CLAUSE_LINK)
@@ -7439,28 +7552,38 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 		    break;
 		  case OMP_LIST_LINEAR:
 		    if (code
-			&& n->u.linear_op != OMP_LINEAR_DEFAULT
-			&& n->u.linear_op != linear_op)
+			&& n->u.linear.op != OMP_LINEAR_DEFAULT
+			&& n->u.linear.op != linear_op)
 		      {
-			gfc_error ("LINEAR clause modifier used on DO or SIMD"
-				   " construct at %L", &n->where);
-			linear_op = n->u.linear_op;
+			if (n->u.linear.old_modifier)
+			  {
+			    gfc_error ("LINEAR clause modifier used on DO or "
+				       "SIMD construct at %L", &n->where);
+			    linear_op = n->u.linear.op;
+			  }
+			else if (n->u.linear.op != OMP_LINEAR_VAL)
+			  {
+			    gfc_error ("LINEAR clause modifier other than VAL "
+				       "used on DO or SIMD construct at %L",
+				       &n->where);
+			    linear_op = n->u.linear.op;
+			  }
 		      }
 		    else if (omp_clauses->orderedc)
 		      gfc_error ("LINEAR clause specified together with "
 				 "ORDERED clause with argument at %L",
 				 &n->where);
-		    else if (n->u.linear_op != OMP_LINEAR_REF
+		    else if (n->u.linear.op != OMP_LINEAR_REF
 			     && n->sym->ts.type != BT_INTEGER)
 		      gfc_error ("LINEAR variable %qs must be INTEGER "
 				 "at %L", n->sym->name, &n->where);
-		    else if ((n->u.linear_op == OMP_LINEAR_REF
-			      || n->u.linear_op == OMP_LINEAR_UVAL)
+		    else if ((n->u.linear.op == OMP_LINEAR_REF
+			      || n->u.linear.op == OMP_LINEAR_UVAL)
 			     && n->sym->attr.value)
 		      gfc_error ("LINEAR dummy argument %qs with VALUE "
 				 "attribute with %s modifier at %L",
 				 n->sym->name,
-				 n->u.linear_op == OMP_LINEAR_REF
+				 n->u.linear.op == OMP_LINEAR_REF
 				 ? "REF" : "UVAL", &n->where);
 		    else if (n->expr)
 		      {
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index c6a584d36f2..de27ed52c02 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -2751,7 +2751,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 						      OMP_CLAUSE_LINEAR);
 			OMP_CLAUSE_DECL (node) = t;
 			omp_clause_linear_kind kind;
-			switch (n->u.linear_op)
+			switch (n->u.linear.op)
 			  {
 			  case OMP_LINEAR_DEFAULT:
 			    kind = OMP_CLAUSE_LINEAR_DEFAULT;
@@ -2769,7 +2769,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			    gcc_unreachable ();
 			  }
 			OMP_CLAUSE_LINEAR_KIND (node) = kind;
-			OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (node) = 1;
+			OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (node)
+			  = n->u.linear.old_modifier;
 			if (last_step_expr && last_step == NULL_TREE)
 			  {
 			    if (!declare_simd)
diff --git a/gcc/testsuite/c-c++-common/gomp/linear-4.c b/gcc/testsuite/c-c++-common/gomp/linear-4.c
new file mode 100644
index 00000000000..59c22b8f86b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/linear-4.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int step (int x, int y, int z) { return x + y + z; }
+
+int
+foo (int x)
+{
+  int i;
+  #pragma omp parallel for linear (x : step (step (1, 2, 3)))
+  for (i = 0; i < 64; i++)
+    x += 6;
+  return x;
+}
+
+int
+bar (int x)
+{
+  int i;
+  #pragma omp parallel for linear (x : step (1, 2, 3))	/* { dg-error "expected" } */
+  for (i = 0; i < 64; i++)
+    x += 6;
+  return x;
+}
+
+int
+bar2 (int x)
+{
+  int i;
+  #pragma omp parallel for linear (x : step (1, 2, 3) * 1)
+  for (i = 0; i < 64; i++)
+    x += 6;
+  return x;
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-2.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-2.f90
new file mode 100644
index 00000000000..05f007fd5c2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-2.f90
@@ -0,0 +1,112 @@
+! { dg-do compile }
+! { dg-options "-fopenmp -fdump-tree-original" }
+
+module m
+  implicit none (type, external)
+
+  integer i
+
+  interface
+    integer function bar (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1)) linear (y : step (2))
+    end
+
+    integer function baz (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : step (1), val)
+    end
+
+    integer function qux (x, val)
+      integer, value :: x, val
+      !$omp declare simd linear (val (x) : val) uniform (val)
+    end
+
+    integer function corge (x, val)
+      integer, value :: x, val
+      !$omp declare simd linear (x : val, step (val)) uniform (val)
+    end
+
+    integer function grault (x)
+      integer, value :: x
+      !$omp declare simd linear (x : val)
+    end
+
+    integer function step (x)
+      integer, value :: x
+    end
+  end interface
+
+contains
+
+subroutine foo (x,y)
+  integer :: x, y
+  integer :: val
+
+  val = 1
+
+  !$omp simd linear (i: step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp simd linear (i: val, step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: step (y + 1), val)
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (i: step (3))
+  do i = 0, 32, 3
+  end do
+
+  !$omp parallel do simd linear (i: step (3), val)
+  do i = 0, 32, 3
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (i: val + 0)
+  do i = 0, 9
+  end do
+
+  !$omp parallel do simd linear (i: step (1) * 1)
+  do i = 0, 9
+  end do
+end
+end module
+
+! { dg-final { scan-tree-dump-times "#pragma omp parallel" 8 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for nowait" 6 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for linear\\(x:D\\.\[0-9\]+\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for linear\\(x:val,step\\(D\\.\[0-9\]+\\)\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(count\\.\[0-9\]:1\\) linear\\(i:3\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(count\\.\[0-9\]:1\\) linear\\(i:val,step\\(3\\)\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) linear\\(x:D\\.\[0-9\]+\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) linear\\(x:val,step\\(D\\.\[0-9\]+\\)\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:D\\.\[0-9\]+\\)" 2 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-3.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-3.f90
new file mode 100644
index 00000000000..dee87b1a899
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-3.f90
@@ -0,0 +1,39 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m2
+  implicit none (type, external)
+
+  integer :: val
+
+contains
+integer function step (x)
+  integer, value :: x
+end
+subroutine foo(x)
+  integer, value :: x
+  !$omp declare simd linear (val (x) : step (1))	! { dg-error "requires a constant integer linear-step expression or dummy argument" }
+end
+end module m2
+
+
+module m
+  implicit none (type, external)
+
+  integer :: val
+
+contains
+integer function step (x)
+  integer, value :: x
+  !$omp declare simd linear (val (x) : step (1))	! { dg-error "Failed to match clause" }
+end
+
+integer function bar (x, y, z)
+  integer, value :: x, y, z
+  !$omp declare simd linear (val (x) : val)		! { dg-error "requires a constant integer linear-step expression or dummy argument" }
+end
+
+integer function baz (x, y, z)
+  integer, value :: x, y, z
+end
+end module m
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-4.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-4.f90
new file mode 100644
index 00000000000..ac532f81000
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-4.f90
@@ -0,0 +1,102 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+
+integer :: i
+
+interface
+  integer function bar (x,  y, z)
+    integer :: x, y
+    integer, value :: z
+    !$omp declare simd linear (x : ref, step (1)) linear (y : step (2), uval)
+  end
+
+  integer function baz (x, y, z)
+    integer :: x
+    integer, value :: y, z
+    !$omp declare simd linear (x : step (1), uval)
+  end
+
+  integer function qux (x, ref)
+    integer :: x
+    integer, value :: ref
+    !$omp declare simd linear (ref (x) : ref) uniform (ref)
+  end
+
+  integer function corge (x, ref)
+    integer :: x
+    integer, value :: ref
+    !$omp declare simd linear (x : ref, step (ref)) uniform (ref)
+  end
+
+  integer function grault (x)
+    integer :: x
+    !$omp declare simd linear (x : ref)
+  end
+
+  integer function waldo (x)
+    integer :: x
+    !$omp declare simd linear (x : uval)
+  end
+end interface
+
+contains
+
+integer function step (x)
+  integer, value :: x
+  step = x
+end
+
+subroutine foo (x, y)
+  integer :: x, y
+  !$omp simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1), val)
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: val, step (y + 1))
+  do i = 0, 9
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: step (1) + 0)
+  do i = 0, 9
+    x = x + step (1) + 0
+  end do
+
+  block
+    integer, parameter :: ref = 1, uval = 2
+    !$omp parallel do simd linear (x: ref + 0)
+    do i = 0, 9
+      x = x + ref + 0
+    end do
+
+    !$omp parallel do simd linear (x: uval * 1)
+    do i = 0, 9
+      x = x + uval
+    end do
+  end block
+end
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-5.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-5.f90
new file mode 100644
index 00000000000..b00492d4b58
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-5.f90
@@ -0,0 +1,43 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+integer :: i
+
+contains
+
+subroutine foo (x, y)
+  integer :: x, y
+
+  !$omp simd linear (x: step (y + 1), ref)		! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp simd linear (x: uval, step (y + 1))		! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: ref, step (y + 1))	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do linear (x: step (y + 1), uval)	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: step (y + 1), ref)	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+
+  !$omp parallel do simd linear (x: uval, step (y + 1))	! { dg-error "LINEAR clause modifier other than VAL used on DO or SIMD construct" }
+  do i = 0, 10
+    x = x + y + 1
+  end do
+end
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-6.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-6.f90
new file mode 100644
index 00000000000..57693ba6de1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-6.f90
@@ -0,0 +1,54 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+implicit none
+integer, parameter :: val = 1
+integer, parameter :: ref = 2
+integer, parameter :: uval = 3
+
+interface
+  integer function foo (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : step (1)) linear (ref (y) : step (2)) linear (uval (z) : step (3))
+
+! STEP is a function - thus:
+! { dg-error "'x' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-3 }
+! { dg-error "'y' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-4 }
+! { dg-error "'z' in LINEAR clause at .1. requires a constant integer linear-step expression or dummy argument specified in UNIFORM clause" "" { target *-*-* } .-5 }
+
+  end
+
+  integer function bar (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : val) linear (ref (y) : ref) linear (uval (z) : uval)
+  end
+
+  integer function baz (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : ref) linear (ref (y) : uval) linear (uval (z) : val)
+  end
+
+  integer function qux (x, y, z)
+    import
+    implicit none
+    integer, value :: x
+    integer :: y, z
+    !$omp declare simd linear (val (x) : uval) linear (ref (y) : val) linear (uval (z) : ref)
+  end
+end interface
+contains
+  integer function step (x)
+    integer, value :: x
+     step = x
+  end
+end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-7.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-7.f90
new file mode 100644
index 00000000000..5e763a92ca6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-7.f90
@@ -0,0 +1,27 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+  implicit none (type, external)
+
+  integer i
+
+  interface
+    integer function s1 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1), val)  ! { dg-error "Multiple 'linear' modifiers specified" }
+    end
+
+    integer function s2 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, step (1), step(2))  ! { dg-error "Multiple 'step' modifiers specified" }
+    end
+
+    integer function s3 (x, y, z)
+      integer, value :: x, y, z
+      !$omp declare simd linear (x : val, ref, step(2))  ! { dg-error "Multiple 'linear' modifiers specified" }
+    end
+
+  end interface
+
+end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/linear-8.f90 b/gcc/testsuite/gfortran.dg/gomp/linear-8.f90
new file mode 100644
index 00000000000..d23dd84b3ed
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/linear-8.f90
@@ -0,0 +1,44 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+module m
+  implicit none (type, external)
+
+  interface
+    integer function step (x, y, z)
+      integer :: x, y, z
+    end function step
+  end interface
+
+contains
+
+integer function foo (x)
+  integer, value :: x
+  integer :: i
+  !$omp parallel do linear (x : step (step (1, 2, 3)))
+  do i = 0, 63
+    x = x + 6
+  end do
+  foo = x
+end
+
+integer function bar (x)
+  integer, value :: x
+  integer :: i
+  !$omp parallel do linear (x : step (1, 2, 3))	! { dg-error "40: Invalid character in name" }
+  do i = 0, 63
+    x = x + 6
+  end do
+  bar = x
+end
+
+integer function bar2 (x)
+  integer, value :: x
+  integer :: i
+  !$omp parallel do linear (x : step (1, 2, 3) * 1)
+  do i = 0, 63
+    x = x + 6
+  end do
+  bar2 = x
+end
+end module
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 39426ff7fbf..e88fe89a5b1 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -363,7 +363,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
 @item Clauses on @code{end} directive can be on directive @tab N @tab
 @item Deprecation of no-argument @code{destroy} clause on @code{depobj}
       @tab N @tab
-@item @code{linear} clause syntax changes and @code{step} modifier @tab P @tab only C/C++
+@item @code{linear} clause syntax changes and @code{step} modifier @tab Y @tab
 @item Deprecation of minus operator for reductions @tab N @tab
 @item Deprecation of separating @code{map} modifiers without comma @tab N @tab
 @item @code{declare mapper} with iterator and @code{present} modifiers

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax
  2022-07-04 18:29       ` Tobias Burnus
@ 2022-07-04 19:08         ` Jakub Jelinek
  0 siblings, 0 replies; 6+ messages in thread
From: Jakub Jelinek @ 2022-07-04 19:08 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran

On Mon, Jul 04, 2022 at 08:29:37PM +0200, Tobias Burnus wrote:
> Fortran part to C/C++
> commit r13-1002-g03b71406323ddc065b1d7837d8b43b17e4b048b5
> 
> gcc/fortran/ChangeLog:
> 
> 	* gfortran.h (gfc_omp_namelist): Update by creating 'linear' struct,
> 	move 'linear_op' as 'op' to id and add 'old_modifier' to it.
> 	* dump-parse-tree.cc (show_omp_namelist): Update accordingly.
> 	* module.cc (mio_omp_declare_simd): Likewise.
> 	* trans-openmp.cc (gfc_trans_omp_clauses): Likewise.
> 	* openmp.cc (resolve_omp_clauses): Likewise; accept new-style
> 	'val' modifier with do/simd.
> 	(gfc_match_omp_clauses): Handle OpenMP 5.2 linear clause syntax.
> 
> libgomp/ChangeLog:
> 
> 	* libgomp.texi (OpenMP 5.2): Mark linear-clause change as 'Y'.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* c-c++-common/gomp/linear-4.c: New test.
> 	* gfortran.dg/gomp/linear-2.f90: New test.
> 	* gfortran.dg/gomp/linear-3.f90: New test.
> 	* gfortran.dg/gomp/linear-4.f90: New test.
> 	* gfortran.dg/gomp/linear-5.f90: New test.
> 	* gfortran.dg/gomp/linear-6.f90: New test.
> 	* gfortran.dg/gomp/linear-7.f90: New test.
> 	* gfortran.dg/gomp/linear-8.f90: New test.

Ok, thanks.

	Jakub


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-07-04 19:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-04 14:10 [Patch] OpenMP/Fortran: Add support for OpenMP 5.2 linear clause syntax Tobias Burnus
2022-07-04 14:53 ` Jakub Jelinek
2022-07-04 16:09   ` Tobias Burnus
2022-07-04 17:20     ` Jakub Jelinek
2022-07-04 18:29       ` Tobias Burnus
2022-07-04 19:08         ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).