Hi!

On Mon, 01 Aug 2016 17:21:37 +0200, I wrote:
> Some checking of OpenACC clauses currently done in the front ends should
> be moved later, and be unified.  (Also, I suppose, for supporting of the
> device_type clause, such checking actually *must* be moved later, into
> the oaccdevlow pass, or similar.)  Here is a first preparatory patch.  OK
> for trunk?
> 
> commit e02a9b65c505b404f8d985b0ec6ccb99d73515d3
> Author: Thomas Schwinge <tho...@codesourcery.com>
> Date:   Wed Jul 27 15:54:38 2016 +0200
> 
>     Use verify_oacc_routine_clauses for C/C++

Here is a Fortran patch.  This depends on other Fortran patches in flight
(such as Cesar's), and on PR72741 "Fortran OpenACC routine directive
doesn't properly handle clauses specifying the level of parallelism" be
resolved, and thereabouts, but I'm posting it anyway, in case anyone has
any review comments already.  I suppose, to begin with, the call of
gfc_oacc_routine_dims will move later into the Fortran front end
pipeline, to the point then function declarations' attributes are set, or
similar.  Also, as discussed already, the Fortran front end currently is
very "forgetful" in regards to OpenACC/OpenMP clauses' specific location
information, so we're not able at present to produce diagnostics with
precise location information.

commit 6480b966af617e61b35b59bb089dd009064743e5
Author: Thomas Schwinge <tho...@codesourcery.com>
Date:   Fri Jul 29 13:12:49 2016 +0200

    Use verify_oacc_routine_clauses for Fortran
    
        gcc/fortran/
        * openmp.c: Include "trans-stmt.h".
        (gfc_oacc_routine_dims): Move function...
        * trans-openmp.c: ... here, and re-implement it.  Adjust all
        users.
        * trans-stmt.h (gfc_oacc_routine_dims): New prototype.
        gcc/testsuite/
        * gfortran.dg/goacc/pr72741.f90: Update.
        * gfortran.dg/goacc/routine-level-of-parallelism-1.f: New file.
---
 gcc/fortran/openmp.c                               |  47 +---------
 gcc/fortran/trans-openmp.c                         |  67 +++++++++++++
 gcc/fortran/trans-stmt.h                           |   7 +-
 gcc/testsuite/gfortran.dg/goacc/pr72741.f90        |  10 +-
 .../goacc/routine-level-of-parallelism-1.f         | 104 +++++++++++++++++++++
 5 files changed, 181 insertions(+), 54 deletions(-)

diff --git gcc/fortran/openmp.c gcc/fortran/openmp.c
index f7a907d..b0a10a8 100644
--- gcc/fortran/openmp.c
+++ gcc/fortran/openmp.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "parse.h"
 #include "diagnostic.h"
 #include "gomp-constants.h"
+#include "trans-stmt.h"
 
 /* Match an end of OpenMP directive.  End of OpenMP directive is optional
    whitespace, followed by '\n' or comment '!'.  */
@@ -1714,44 +1715,6 @@ gfc_match_oacc_cache (void)
   return MATCH_YES;
 }
 
-/* Determine the loop level for a routine.  Returns OACC_FUNCTION_NONE if
-   any error is detected.  */
-
-static oacc_function
-gfc_oacc_routine_dims (gfc_omp_clauses *clauses)
-{
-  int level = -1;
-  oacc_function ret = OACC_FUNCTION_SEQ;
-
-  if (clauses)
-    {
-      unsigned mask = 0;
-
-      if (clauses->gang)
-       {
-         level = GOMP_DIM_GANG, mask |= GOMP_DIM_MASK (level);
-         ret = OACC_FUNCTION_GANG;
-       }
-      if (clauses->worker)
-       {
-         level = GOMP_DIM_WORKER, mask |= GOMP_DIM_MASK (level);
-         ret = OACC_FUNCTION_WORKER;
-       }
-      if (clauses->vector)
-       {
-         level = GOMP_DIM_VECTOR, mask |= GOMP_DIM_MASK (level);
-         ret = OACC_FUNCTION_VECTOR;
-       }
-      if (clauses->seq)
-       level = GOMP_DIM_MAX, mask |= GOMP_DIM_MASK (level);
-
-      if (mask != (mask & -mask))
-       ret = OACC_FUNCTION_NONE;
-    }
-
-  return ret;
-}
-
 match
 gfc_match_oacc_routine (void)
 {
@@ -1828,13 +1791,7 @@ gfc_match_oacc_routine (void)
          != MATCH_YES))
     return MATCH_ERROR;
 
-  dims = gfc_oacc_routine_dims (c);
-  if (dims == OACC_FUNCTION_NONE)
-    {
-      gfc_error ("Multiple loop axes specified for routine %C");
-      gfc_current_locus = old_loc;
-      return MATCH_ERROR;
-    }
+  dims = gfc_oacc_routine_dims (c, old_loc);
 
   if (isym != NULL)
     /* There is nothing to do for intrinsic procedures.  */
diff --git gcc/fortran/trans-openmp.c gcc/fortran/trans-openmp.c
index 0d646ed..254732c 100644
--- gcc/fortran/trans-openmp.c
+++ gcc/fortran/trans-openmp.c
@@ -4570,3 +4570,70 @@ gfc_trans_omp_declare_simd (gfc_namespace *ns)
       DECL_ATTRIBUTES (fndecl) = c;
     }
 }
+
+/* Determine and verify the level of parallelism for an OpenACC routine.  */
+
+oacc_function
+gfc_oacc_routine_dims (gfc_omp_clauses *clauses, locus location)
+{
+  /* This is implemented in terms of OMP_CLAUSE trees, so that we can use the
+     generic functions for checking validity.  This has a little bit of
+     overhead, but as the number of clauses on OpenACC routine directives as
+     well as the number of OpenACC routine directives will both be rather
+     small, this is acceptable.  */
+  tree clauses_t = NULL_TREE;
+  /* We don't have specific location information available for the individual
+     clauses...  */
+  location_t loc = location.lb->location;
+  if (clauses)
+    {
+      if (clauses->gang)
+       {
+         tree c = build_omp_clause (loc, OMP_CLAUSE_GANG);
+         OMP_CLAUSE_CHAIN (c) = clauses_t;
+         clauses_t = c;
+       }
+      if (clauses->worker)
+       {
+         tree c = build_omp_clause (loc, OMP_CLAUSE_WORKER);
+         OMP_CLAUSE_CHAIN (c) = clauses_t;
+         clauses_t = c;
+       }
+      if (clauses->vector)
+       {
+         tree c = build_omp_clause (loc, OMP_CLAUSE_VECTOR);
+         OMP_CLAUSE_CHAIN (c) = clauses_t;
+         clauses_t = c;
+       }
+      if (clauses->seq)
+       {
+         tree c = build_omp_clause (loc, OMP_CLAUSE_SEQ);
+         OMP_CLAUSE_CHAIN (c) = clauses_t;
+         clauses_t = c;
+       }
+    }
+  verify_oacc_routine_clauses (&clauses_t, loc);
+
+  gcc_checking_assert (clauses_t != NULL_TREE
+                      && OMP_CLAUSE_CHAIN (clauses_t) == NULL_TREE);
+  oacc_function ret;
+  switch (OMP_CLAUSE_CODE (clauses_t))
+    {
+    case OMP_CLAUSE_GANG:
+      ret = OACC_FUNCTION_GANG;
+      break;
+    case OMP_CLAUSE_WORKER:
+      ret = OACC_FUNCTION_WORKER;
+      break;
+    case OMP_CLAUSE_VECTOR:
+      ret = OACC_FUNCTION_VECTOR;
+      break;
+    case OMP_CLAUSE_SEQ:
+      ret = OACC_FUNCTION_SEQ;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  return ret;
+}
diff --git gcc/fortran/trans-stmt.h gcc/fortran/trans-stmt.h
index f9c8e74..1e50298 100644
--- gcc/fortran/trans-stmt.h
+++ gcc/fortran/trans-stmt.h
@@ -63,12 +63,11 @@ tree gfc_trans_deallocate (gfc_code *);
 tree gfc_trans_deallocate_array (tree);
 
 /* trans-openmp.c */
+tree gfc_trans_oacc_declare (gfc_namespace *);
+tree gfc_trans_oacc_directive (gfc_code *);
 tree gfc_trans_omp_directive (gfc_code *);
 void gfc_trans_omp_declare_simd (gfc_namespace *);
-
-/* trans-openacc.c */
-tree gfc_trans_oacc_directive (gfc_code *);
-tree gfc_trans_oacc_declare (gfc_namespace *);
+oacc_function gfc_oacc_routine_dims (gfc_omp_clauses *, locus);
 
 /* trans-io.c */
 tree gfc_trans_open (gfc_code *);
diff --git gcc/testsuite/gfortran.dg/goacc/pr72741.f90 
gcc/testsuite/gfortran.dg/goacc/pr72741.f90
index cf89727..a5cb218 100644
--- gcc/testsuite/gfortran.dg/goacc/pr72741.f90
+++ gcc/testsuite/gfortran.dg/goacc/pr72741.f90
@@ -1,12 +1,12 @@
 SUBROUTINE v_1
-  !$ACC ROUTINE VECTOR WORKER ! { dg-error "Multiple loop axes" }
+  !$ACC ROUTINE VECTOR WORKER ! { dg-error ".worker. specifies a conflicting 
level of parallelism" }
 END SUBROUTINE v_1
 
 SUBROUTINE sub_1
   IMPLICIT NONE
   EXTERNAL :: g_1
-  !$ACC ROUTINE (g_1) GANG WORKER ! { dg-error "Multiple loop axes" }
-  !$ACC ROUTINE (ABORT) SEQ VECTOR ! { dg-error "Multiple loop axes" }
+  !$ACC ROUTINE (g_1) GANG WORKER ! { dg-error ".gang. specifies a conflicting 
level of parallelism" }
+  !$ACC ROUTINE (ABORT) SEQ VECTOR ! { dg-error ".vector. specifies a 
conflicting level of parallelism" }
 
   CALL v_1
   CALL g_1
@@ -16,8 +16,8 @@ END SUBROUTINE sub_1
 MODULE m_w_1
   IMPLICIT NONE
   EXTERNAL :: w_1
-  !$ACC ROUTINE (w_1) WORKER SEQ ! { dg-error "Multiple loop axes" }
-  !$ACC ROUTINE (ABORT) VECTOR GANG ! { dg-error "Multiple loop axes" }
+  !$ACC ROUTINE (w_1) WORKER SEQ ! { dg-error ".worker. specifies a 
conflicting level of parallelism" }
+  !$ACC ROUTINE (ABORT) VECTOR GANG ! { dg-error ".gang. specifies a 
conflicting level of parallelism" }
 
 CONTAINS
   SUBROUTINE sub_2
diff --git gcc/testsuite/gfortran.dg/goacc/routine-level-of-parallelism-1.f 
gcc/testsuite/gfortran.dg/goacc/routine-level-of-parallelism-1.f
new file mode 100644
index 0000000..e2f3c61
--- /dev/null
+++ gcc/testsuite/gfortran.dg/goacc/routine-level-of-parallelism-1.f
@@ -0,0 +1,104 @@
+! Test various aspects of clauses specifying incompatible levels of
+! parallelism with the OpenACC routine directive.  The C/C++ counterpart
+! is ../../c-c++-common/goacc/routine-level-of-parallelism-1.c.
+
+! We currently don't have precise location information for these, so can't
+! match them properly.
+! { dg-prune-output "specifies a conflicting level of parallelism" }
+
+      MODULE m_g_1
+      EXTERNAL :: g_1
+!$ACC ROUTINE (g_1) GANG GANG ! { dg-error "Unclassifiable OpenACC directive" }
+      END
+
+      SUBROUTINE w_1
+!$ACC ROUTINE WORKER WORKER ! { dg-error "Unclassifiable OpenACC directive" }
+      END
+
+      SUBROUTINE v_1
+!$ACC ROUTINE VECTOR VECTOR ! { dg-error "Unclassifiable OpenACC directive" }
+      END
+
+      MODULE m_s_1
+      EXTERNAL :: s_1
+!$ACC ROUTINE (s_1) SEQ SEQ ! { dg-error "Unclassifiable OpenACC directive" }
+      END
+
+
+      SUBROUTINE g_2
+!$ACC ROUTINE GANG GANG GANG ! { dg-error "Unclassifiable OpenACC directive" }
+      END
+
+      MODULE m_w_2
+      EXTERNAL :: w_2
+!$ACC ROUTINE (w_2) WORKER WORKER WORKER ! { dg-error "Unclassifiable OpenACC 
directive" }
+      END
+
+      MODULE m_v_2
+      EXTERNAL :: v_2
+!$ACC ROUTINE (v_2) VECTOR VECTOR VECTOR ! { dg-error "Unclassifiable OpenACC 
directive" }
+      END
+
+      SUBROUTINE s_2
+!$ACC ROUTINE SEQ SEQ SEQ ! { dg-error "Unclassifiable OpenACC directive" }
+      END
+
+
+      SUBROUTINE g_3
+!$ACC ROUTINE
+!$ACC& GANG
+!$ACC& WORKER ! { dg-error ".worker. specifies a conflicting level of 
parallelism" "" { xfail *-*-* } }
+      END
+
+      MODULE m_g_3
+      EXTERNAL :: g_3
+!$ACC ROUTINE (g_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*g_3." "" { xfail *-*-* } }
+!$ACC& GANG
+!$ACC& SEQ ! { dg-error ".seq. specifies a conflicting level of parallelism" 
"" { xfail *-*-* } }
+     
+!$ACC ROUTINE (g_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*g_3." "" { xfail *-*-* } }
+!$ACC& GANG
+!$ACC& VECTOR ! { dg-error ".vector. specifies a conflicting level of 
parallelism" "" { xfail *-*-* } }
+      END
+
+      MODULE m_w_3
+      EXTERNAL :: w_3
+!$ACC ROUTINE (w_3)
+!$ACC& WORKER
+!$ACC& VECTOR ! { dg-error ".vector. specifies a conflicting level of 
parallelism" "" { xfail *-*-* } }
+!$ACC ROUTINE (w_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*w_3." "" { xfail *-*-* } }
+!$ACC& WORKER
+!$ACC& GANG ! { dg-error ".gang. specifies a conflicting level of parallelism" 
"" { xfail *-*-* } }
+!$ACC ROUTINE (w_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*w_3." "" { xfail *-*-* } }
+!$ACC& WORKER
+!$ACC& SEQ ! { dg-error ".seq. specifies a conflicting level of parallelism" 
"" { xfail *-*-* } }
+      END
+
+      SUBROUTINE v_3
+!$ACC ROUTINE (v_3)
+!$ACC& VECTOR
+!$ACC& SEQ ! { dg-error ".seq. specifies a conflicting level of parallelism" 
"" { xfail *-*-* } }
+      END
+
+      MODULE m_v_3
+      EXTERNAL :: v_3
+!$ACC ROUTINE (v_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*v_3." "" { xfail *-*-* } }
+!$ACC& VECTOR
+!$ACC& WORKER ! { dg-error ".worker. specifies a conflicting level of 
parallelism" "" { xfail *-*-* } }
+!$ACC ROUTINE (v_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*v_3." "" { xfail *-*-* } }
+!$ACC& VECTOR
+!$ACC& GANG ! { dg-error ".gang. specifies a conflicting level of parallelism" 
"" { xfail *-*-* } }
+      END
+
+      MODULE m_s_3
+      EXTERNAL :: s_3
+!$ACC ROUTINE (s_3)
+!$ACC& SEQ
+!$ACC& GANG ! { dg-error ".gang. specifies a conflicting level of parallelism" 
"" { xfail *-*-* } }
+!$ACC ROUTINE (s_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*s_3." "" { xfail *-*-* } }
+!$ACC& SEQ
+!$ACC& VECTOR ! { dg-error ".vector. specifies a conflicting level of 
parallelism" "" { xfail *-*-* } }
+!$ACC ROUTINE (s_3) ! { dg-error ".#pragma acc routine. already applied to 
.\[void \]*s_3." "" { xfail *-*-* } }
+!$ACC& SEQ
+!$ACC& WORKER ! { dg-error ".worker. specifies a conflicting level of 
parallelism" "" { xfail *-*-* } }
+      END


Grüße
 Thomas

Reply via email to