Re: [PUSHED v4] Fortran support for init,set,shutdown OpenACC directives
Thomas Schwinge <[email protected]> Thu, 30 Jul 2026 10:36:42 +0200
| Newsgroups | gmane.comp.gcc.patches,gmane.comp.gcc.fortran |
|---|---|
| Message-ID | <[email protected]> |
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Hi Sebastian!
Great work! Thanks for thoroughly addressing the review comments.
This is now in GCC trunk, commit 0dbe46aeaf5c06cbd3deaa833e5ae2150fe67c56
"Fortran support for init,set,shutdown OpenACC directives". :-)
I've only incorporated some small additional changes; that was easier for
me to just do, instead of describing to you what to do. See the attached
'patch' (on top of your changes), and the following comments:
In the mean time, the 'get_num_devices_func' libgomp plugin function
again lost its 'unsigned int omp_requires_mask' argument, so I've
adjusted the new code for that.
In 'gcc/fortran/openmp.cc:resolve_omp_clauses', in the new checks you've
added, we were ICEing (and therefore a good number of OpenMP test case
regressions). That function gets called with 'code =3D=3D NULL': via
'gfc_resolve_omp_declare', 'gfc_resolve_omp_udm', so we can't
unconditionally dereference 'code'. I've fixed that as follows:
- if (!omp_clauses->device_num_expr && !omp_clauses->oacc_device_type_=
present
- && code->op =3D=3D EXEC_OACC_SET)
+ if (code && code->op =3D=3D EXEC_OACC_SET
+ && !omp_clauses->device_num_expr
+ && !omp_clauses->oacc_device_type_present)
gfc_error ([...]
I've decided to shorten 'GOACC_set_device_type_device_num' into
'GOACC_set_device' (and adjusted the ChangeLog for that).
Otherwise, just some minor reordering/reformatting/whitespace changes, to
make the new code fit into the existing even more naturally.
Gr=C3=BC=C3=9Fe
Thomas
On 2026-07-30T10:28:01+0200, I wrote:
> From: Sebastian Galindo <[email protected]>
>
> This patch adds parsing and libgomp runtime calls for these directives,
> sharing the existing implementation with runtime API calls. It also
> includes support for the device_type and device_num clauses in the
> Fortran front-end.
>
> For the device_type clause, the current implementation limits usage to
> accepting only a single clause per directive. While the OpenACC
> specification states that device_type should modify the device for
> subsequent clauses inside other directives or constructs, supporting
> this behavior requires a larger refactoring and may be addressed in
> the future.
>
> The set directive does not yet support the default_async clause, as
> further discussion is needed to agree on its semantics and libgomp
> implementation.
>
> gcc/ChangeLog:
>
> * builtin-types.def (BT_FN_VOID_INT_INT): New definition.
> * omp-builtins.def (BUILT_IN_GOACC_INIT): New builtin for
> init directive.
> (BUILT_IN_GOACC_SHUTDOWN): New builtin for shutdown directive.
> (BUILT_IN_GOACC_SET_DEVICE): New builtin for set directive.
>
> gcc/fortran/ChangeLog:
>
> * dump-parse-tree.cc (show_omp_clauses): Dump OpenACC DEVICE_TYPE
> and DEVICE_NUM clauses.
> (show_omp_node): Handle INIT, SHUTDOWN, and SET directives.
> (show_code_node): Likewise.
> * frontend-passes.cc (gfc_code_walker): Walk device_num_expr for
> INIT, SHUTDOWN, and SET directives.
> * gfortran.h (enum gfc_statement): Add ST_OACC_INIT,
> ST_OACC_SHUTDOWN, and ST_OACC_SET.
> (gfc_omp_clauses): Add device_num_expr and oacc_device_type
> fields.
> (enum gfc_exec_op): Add EXEC_OACC_INIT, EXEC_OACC_SHUTDOWN, and
> EXEC_OACC_SET.
> * match.h (gfc_match_oacc_init): Declare.
> (gfc_match_oacc_shutdown): Likewise.
> (gfc_match_oacc_set): Likewise.
> * openmp.cc (gfc_free_omp_clauses): Free device_num_expr.
> (match_oacc_device_type_kind): New helper to parse OpenACC
> device_type arguments.
> (match_oacc_device_type): New helper to match the OpenACC
> DEVICE_TYPE clause.
> (enum omp_mask2): Add OMP_CLAUSE_DEVICE_NUM.
> (gfc_match_omp_clauses): Match OpenACC DEVICE_TYPE and
> DEVICE_NUM clauses.
> (OACC_INIT_CLAUSES): New clause mask.
> (OACC_SHUTDOWN_CLAUSES): Likewise.
> (OACC_SET_CLAUSES): Likewise.
> (gfc_match_oacc_init): New matcher.
> (gfc_match_oacc_shutdown): Likewise.
> (gfc_match_oacc_set): Likewise.
> (resolve_omp_clauses): Resolve DEVICE_NUM; require at least one
> of DEVICE_TYPE and DEVICE_NUM on SET.
> (oacc_code_to_statement): Map new exec ops to statement codes.
> (gfc_resolve_oacc_directive): Resolve INIT, SET, and SHUTDOWN
> directives.
> * parse.cc (decode_oacc_directive): Recognize init, set, and
> shutdown directives.
> (next_statement): Treat INIT, SET, and SHUTDOWN as executable
> statements.
> (gfc_ascii_statement): Add ASCII names for new directives.
> (is_oacc): Recognize new exec ops.
> * resolve.cc (gfc_resolve_blocks): Resolve INIT, SET, and
> SHUTDOWN directives.
> * st.cc (gfc_free_statement): Free clauses for new directives.
> * trans-openmp.cc (gfc_trans_omp_clauses): Assert that
> DEVICE_NUM and DEVICE_TYPE do not appear on construct clauses.
> (gfc_trans_oacc_executable_directive): Lower INIT, SHUTDOWN, and
> SET to GOACC builtins.
> (gfc_trans_oacc_directive): Dispatch new directives.
> * trans.cc (trans_code): Dispatch new directives.
> * types.def (BT_FN_VOID_INT_INT): New definition.
>
> libgomp/ChangeLog:
>
> * libgomp.map (GOACC_2.5): Export GOACC_init, GOACC_shutdown, and
> GOACC_set_device.
> * libgomp_g.h (GOACC_init): Declare.
> (GOACC_shutdown): Likewise.
> (GOACC_set_device): Likewise.
> * oacc-init.c (GOACC_DIRECTIVE_DEVICE_MASK): New macro for
> supported device types.
> (acc_init_1): Accept explicit device number argument.
> (acc_shutdown_1): Shut down a single device or all devices of a
> type.
> (goacc_attach_host_thread_to_device): Whitespace fix.
> (GOACC_init): New entry point for init directive.
> (GOACC_shutdown): New entry point for shutdown directive.
> (GOACC_set_device): New entry point for set directive.
> (acc_init): Pass default device number to acc_init_1.
> (acc_shutdown): Pass default device number to acc_shutdown_1.
> (acc_set_device_num): Whitespace fix.
> (goacc_restore_bind): Whitespace fix.
> (goacc_lazy_initialize): Pass default device number to acc_init_1.
> * testsuite/libgomp.oacc-fortran/init-1.f90: New test.
> * testsuite/libgomp.oacc-fortran/lib-1-directives.f90: New test.
> * testsuite/libgomp.oacc-fortran/lib-4-directives.f90: New test.
> * testsuite/libgomp.oacc-fortran/lib-5-directives.f90: New test.
> * testsuite/libgomp.oacc-fortran/lib-5-init.f90: New test.
> * testsuite/libgomp.oacc-fortran/set-1.f90: New test.
> * testsuite/libgomp.oacc-fortran/shutdown-1.f90: New test.
>
> gcc/testsuite/ChangeLog:
>
> * gfortran.dg/goacc/acc-init-1.f90: New test.
> * gfortran.dg/goacc/acc-init-clauses-1.f90: New test.
> * gfortran.dg/goacc/acc-set-1.f90: New test.
> * gfortran.dg/goacc/acc-set-clauses-1.f90: New test.
> * gfortran.dg/goacc/acc-shutdown-1.f90: New test.
> * gfortran.dg/goacc/acc-shutdown-clauses-1.f90: New test.
> * gfortran.dg/goacc/uninit-if-clause.f95: Test INIT with
> uninitialized IF clause.
> * gfortran.dg/goacc/update-if_present-2.f90: Update expected
> errors now that INIT and SHUTDOWN are recognized.
>
> Signed-off-by: Sebastian Galindo <[email protected]>
> Co-authored-by: Thomas Schwinge <[email protected]>
> ---
> gcc/builtin-types.def | 1 +
> gcc/fortran/dump-parse-tree.cc | 31 +++
> gcc/fortran/frontend-passes.cc | 8 +
> gcc/fortran/gfortran.h | 4 +
> gcc/fortran/match.h | 3 +
> gcc/fortran/openmp.cc | 126 +++++++++++-
> gcc/fortran/parse.cc | 20 +-
> gcc/fortran/resolve.cc | 6 +
> gcc/fortran/st.cc | 3 +
> gcc/fortran/trans-openmp.cc | 74 ++++++-
> gcc/fortran/trans.cc | 3 +
> gcc/fortran/types.def | 1 +
> gcc/omp-builtins.def | 6 +
> .../gfortran.dg/goacc/acc-init-1.f90 | 47 +++++
> .../gfortran.dg/goacc/acc-init-clauses-1.f90 | 28 +++
> gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90 | 36 ++++
> .../gfortran.dg/goacc/acc-set-clauses-1.f90 | 58 ++++++
> .../gfortran.dg/goacc/acc-shutdown-1.f90 | 47 +++++
> .../goacc/acc-shutdown-clauses-1.f90 | 43 ++++
> .../gfortran.dg/goacc/uninit-if-clause.f95 | 5 +-
> .../gfortran.dg/goacc/update-if_present-2.f90 | 4 +-
> libgomp/libgomp.map | 7 +
> libgomp/libgomp_g.h | 6 +
> libgomp/oacc-init.c | 185 ++++++++++++++++--
> .../testsuite/libgomp.oacc-fortran/init-1.f90 | 59 ++++++
> .../libgomp.oacc-fortran/lib-1-directives.f90 | 17 ++
> .../libgomp.oacc-fortran/lib-4-directives.f90 | 37 ++++
> .../libgomp.oacc-fortran/lib-5-directives.f90 | 59 ++++++
> .../libgomp.oacc-fortran/lib-5-init.f90 | 59 ++++++
> .../testsuite/libgomp.oacc-fortran/set-1.f90 | 82 ++++++++
> .../libgomp.oacc-fortran/shutdown-1.f90 | 53 +++++
> 31 files changed, 1094 insertions(+), 24 deletions(-)
> create mode 100644 gcc/testsuite/gfortran.dg/goacc/acc-init-1.f90
> create mode 100644 gcc/testsuite/gfortran.dg/goacc/acc-init-clauses-1.f90
> create mode 100644 gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90
> create mode 100644 gcc/testsuite/gfortran.dg/goacc/acc-set-clauses-1.f90
> create mode 100644 gcc/testsuite/gfortran.dg/goacc/acc-shutdown-1.f90
> create mode 100644 gcc/testsuite/gfortran.dg/goacc/acc-shutdown-clauses-=
1.f90
> create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/init-1.f90
> create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-1-directiv=
es.f90
> create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-4-directiv=
es.f90
> create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-5-directiv=
es.f90
> create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-5-init.f90
> create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/set-1.f90
> create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/shutdown-1.f90
>
> diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
> index 23bfa76eaa4..19da735791e 100644
> --- a/gcc/builtin-types.def
> +++ b/gcc/builtin-types.def
> @@ -694,6 +694,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_PTR_CONST_PTR_UINT8, BT_PT=
R, BT_CONST_PTR, BT_UINT8)
> DEF_FUNCTION_TYPE_2 (BT_FN_PTR_CONST_PTR_INT, BT_PTR, BT_CONST_PTR, BT_I=
NT)
> DEF_FUNCTION_TYPE_2 (BT_FN_VOID_ULONGLONG_ULONGLONG,
> BT_VOID, BT_ULONGLONG, BT_ULONGLONG)
> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_INT_INT, BT_VOID, BT_INT, BT_INT)
>=20=20
> DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
>=20=20
> diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree=
.cc
> index 8d13acd8656..da185baecec 100644
> --- a/gcc/fortran/dump-parse-tree.cc
> +++ b/gcc/fortran/dump-parse-tree.cc
> @@ -2494,6 +2494,28 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
> show_expr (omp_clauses->nocontext);
> fputc (')', dumpfile);
> }
> + if (omp_clauses->oacc_device_type_present)
> + {
> + const char *s;
> + switch (omp_clauses->oacc_device_type)
> + {
> + case GOMP_DEVICE_NONE: s =3D "all"; break;
> + case GOMP_DEVICE_HOST: s =3D "host"; break;
> + case GOMP_DEVICE_NVIDIA_PTX: s =3D "nvidia"; break;
> + case GOMP_DEVICE_GCN: s =3D "radeon"; break;
> + default:
> + gcc_unreachable ();
> + }
> + fputs (" DEVICE_TYPE(", dumpfile);
> + fputs (s, dumpfile);
> + fputc (')', dumpfile);
> + }
> + if (omp_clauses->device_num_expr)
> + {
> + fputs (" DEVICE_NUM(", dumpfile);
> + show_expr (omp_clauses->device_num_expr);
> + fputc (')', dumpfile);
> + }
> }
>=20=20
> /* Show a single OpenMP or OpenACC directive node and everything underne=
ath it
> @@ -2523,6 +2545,9 @@ show_omp_node (int level, gfc_code *c)
> case EXEC_OACC_CACHE: name =3D "CACHE"; is_oacc =3D true; break;
> case EXEC_OACC_ENTER_DATA: name =3D "ENTER DATA"; is_oacc =3D true; =
break;
> case EXEC_OACC_EXIT_DATA: name =3D "EXIT DATA"; is_oacc =3D true; br=
eak;
> + case EXEC_OACC_INIT: name =3D "INIT"; is_oacc =3D true; break;
> + case EXEC_OACC_SHUTDOWN: name =3D "SHUTDOWN"; is_oacc =3D true; brea=
k;
> + case EXEC_OACC_SET: name =3D "SET"; is_oacc =3D true; break;
> case EXEC_OMP_ALLOCATE: name =3D "ALLOCATE"; break;
> case EXEC_OMP_ALLOCATORS: name =3D "ALLOCATORS"; break;
> case EXEC_OMP_ASSUME: name =3D "ASSUME"; break;
> @@ -2634,6 +2659,9 @@ show_omp_node (int level, gfc_code *c)
> case EXEC_OACC_CACHE:
> case EXEC_OACC_ENTER_DATA:
> case EXEC_OACC_EXIT_DATA:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> case EXEC_OMP_ALLOCATE:
> case EXEC_OMP_ALLOCATORS:
> case EXEC_OMP_ASSUME:
> @@ -4031,6 +4059,9 @@ show_code_node (int level, gfc_code *c)
> case EXEC_OACC_CACHE:
> case EXEC_OACC_ENTER_DATA:
> case EXEC_OACC_EXIT_DATA:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> case EXEC_OMP_ALLOCATE:
> case EXEC_OMP_ALLOCATORS:
> case EXEC_OMP_ASSUME:
> diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes=
.cc
> index 9bf5d40b9cc..8abe07e8f59 100644
> --- a/gcc/fortran/frontend-passes.cc
> +++ b/gcc/fortran/frontend-passes.cc
> @@ -5740,6 +5740,14 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t code=
fn, walk_expr_fn_t exprfn,
> WALK_SUBEXPR (n->expr);
> }
> break;
> +
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> + if (co->ext.omp_clauses)
> + WALK_SUBEXPR (co->ext.omp_clauses->device_num_expr);
> + break;
> +
> default:
> break;
> }
> diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
> index 48ddd9a72d5..a5b2e035c84 100644
> --- a/gcc/fortran/gfortran.h
> +++ b/gcc/fortran/gfortran.h
> @@ -273,6 +273,7 @@ enum gfc_statement
> ST_OACC_SERIAL_LOOP, ST_OACC_END_SERIAL_LOOP, ST_OACC_SERIAL,
> ST_OACC_END_SERIAL, ST_OACC_ENTER_DATA, ST_OACC_EXIT_DATA, ST_OACC_ROU=
TINE,
> ST_OACC_ATOMIC, ST_OACC_END_ATOMIC,
> + ST_OACC_INIT, ST_OACC_SHUTDOWN, ST_OACC_SET,
> ST_OMP_ATOMIC, ST_OMP_BARRIER, ST_OMP_CRITICAL, ST_OMP_END_ATOMIC,
> ST_OMP_END_CRITICAL, ST_OMP_END_DO, ST_OMP_END_MASTER, ST_OMP_END_ORDE=
RED,
> ST_OMP_END_PARALLEL, ST_OMP_END_PARALLEL_DO, ST_OMP_END_PARALLEL_SECTI=
ONS,
> @@ -1770,12 +1771,14 @@ typedef struct gfc_omp_clauses
> struct gfc_expr *num_gangs_expr;
> struct gfc_expr *num_workers_expr;
> struct gfc_expr *vector_length_expr;
> + struct gfc_expr *device_num_expr;
> gfc_expr_list *wait_list;
> gfc_expr_list *tile_list;
> unsigned async:1, gang:1, worker:1, vector:1, seq:1, independent:1;
> unsigned par_auto:1, gang_static:1;
> unsigned if_present:1, finalize:1;
> unsigned nohost:1;
> + unsigned oacc_device_type:4, oacc_device_type_present:1;
> locus loc;
> }
> gfc_omp_clauses;
> @@ -3286,6 +3289,7 @@ enum gfc_exec_op
> EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP, EXEC_OACC_UPDATE,
> EXEC_OACC_WAIT, EXEC_OACC_CACHE, EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_=
DATA,
> EXEC_OACC_ATOMIC, EXEC_OACC_DECLARE,
> + EXEC_OACC_INIT, EXEC_OACC_SHUTDOWN, EXEC_OACC_SET,
> EXEC_OMP_CRITICAL, EXEC_OMP_FIRST_OPENMP_EXEC =3D EXEC_OMP_CRITICAL,
> EXEC_OMP_DO, EXEC_OMP_FLUSH, EXEC_OMP_MASTER,
> EXEC_OMP_ORDERED, EXEC_OMP_PARALLEL, EXEC_OMP_PARALLEL_DO,
> diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
> index 0641e5a434c..43cc804225c 100644
> --- a/gcc/fortran/match.h
> +++ b/gcc/fortran/match.h
> @@ -131,6 +131,9 @@ gfc_common_head *gfc_get_common (const char *, int);
> /* OpenACC directive matchers. */
> match gfc_match_oacc_atomic (void);
> match gfc_match_oacc_cache (void);
> +match gfc_match_oacc_init (void);
> +match gfc_match_oacc_shutdown (void);
> +match gfc_match_oacc_set (void);
> match gfc_match_oacc_wait (void);
> match gfc_match_oacc_update (void);
> match gfc_match_oacc_declare (void);
> diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
> index 3613dc8bd45..e559a2db0db 100644
> --- a/gcc/fortran/openmp.cc
> +++ b/gcc/fortran/openmp.cc
> @@ -209,6 +209,7 @@ gfc_free_omp_clauses (gfc_omp_clauses *c)
> gfc_free_expr (c->num_gangs_expr);
> gfc_free_expr (c->num_workers_expr);
> gfc_free_expr (c->vector_length_expr);
> + gfc_free_expr (c->device_num_expr);
> for (enum gfc_omp_list_type t =3D OMP_LIST_FIRST; t < OMP_LIST_NUM;
> t =3D gfc_omp_list_type (t + 1))
> gfc_free_omp_namelist (c->lists[t], t);
> @@ -832,6 +833,73 @@ cleanup:
> return MATCH_ERROR;
> }
>=20=20
> +static int
> +match_oacc_device_type_kind (void)
> +{
> + char name[GFC_MAX_SYMBOL_LEN + 1];
> +
> + /* Since device_type arg accept * as all,
> + we need to check first the case when
> + the user inputs * as the parameter. */
> + gfc_gobble_whitespace ();
> + name[0] =3D (char) gfc_next_char ();
> +
> + if (name[0] =3D=3D '*')
> + return GOMP_DEVICE_NONE;
> +
> + /* If is not *, we try to match the
> + pre-defined names. */
> +
> + match m =3D gfc_match (" %n ", name + 1);
> +
> + if (m !=3D MATCH_YES)
> + return -1;
> +
> + if (strcmp (name ,"host") =3D=3D 0)
> + return GOMP_DEVICE_HOST;
> + if (strcmp (name, "nvidia") =3D=3D 0)
> + return GOMP_DEVICE_NVIDIA_PTX;
> + if (strcmp (name, "radeon") =3D=3D 0)
> + return GOMP_DEVICE_GCN;
> +
> + return -1;
> +}
> +
> +static match
> +match_oacc_device_type (gfc_omp_clauses *c)
> +{
> + locus old_loc =3D gfc_current_locus;
> +
> + int result =3D match_oacc_device_type_kind ();
> + match m;
> +
> + if (result =3D=3D -1)
> + goto syntax;
> +
> + m =3D gfc_match_char (')', true);
> +
> + if (m !=3D MATCH_YES)
> + goto single_argument;
> +
> + c->oacc_device_type =3D (unsigned) result;
> + c->oacc_device_type_present =3D 1;
> +
> + return MATCH_YES;
> +
> +single_argument:
> + gfc_error ("OpenACC %<DEVICE_TYPE%> clause only accepts one argument, "
> + "unexpected char at %C");
> + goto cleanup;
> +
> +syntax:
> + gfc_error ("Syntax error in OpenACC %<DEVICE_TYPE%> argument at %C. E=
xpected "
> + "host, radeon, nvidia or * as argument.");
> +
> +cleanup:
> + gfc_current_locus =3D old_loc;
> + return MATCH_ERROR;
> +}
> +
> static match
> match_omp_oacc_expr_list (const char *str, gfc_expr_list **list,
> bool allow_asterisk, bool is_omp)
> @@ -1182,6 +1250,7 @@ enum omp_mask2
> OMP_CLAUSE_INTEROP, /* OpenMP 5.1 */
> OMP_CLAUSE_LOCAL, /* OpenMP 6.0 */
> OMP_CLAUSE_DYN_GROUPPRIVATE, /* OpenMP 6.1 */
> + OMP_CLAUSE_DEVICE_NUM,
> /* This must come last. */
> OMP_MASK2_LAST
> };
> @@ -3156,7 +3225,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const=
omp_mask mask,
> OMP_MAP_FORCE_DEVICEPTR, false,
> allow_derived))
> continue;
> - if ((mask & OMP_CLAUSE_DEVICE_TYPE)
> + if ((mask & OMP_CLAUSE_DEVICE_TYPE) && openacc
> + && gfc_match_dupl_check (!c->oacc_device_type_present,
> + "device_type", true) =3D=3D MATCH_YES
> + && match_oacc_device_type (c) =3D=3D MATCH_YES)
> + continue;
> + if ((mask & OMP_CLAUSE_DEVICE_TYPE) && !openacc
> && gfc_match_dupl_check (c->device_type =3D=3D OMP_DEVICE_TYPE_UN=
SET,
> "device_type", true) =3D=3D MATCH_YES)
> {
> @@ -3175,6 +3249,16 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const=
omp_mask mask,
> break;
> continue;
> }
> + if ((mask & OMP_CLAUSE_DEVICE_NUM)
> + && (m =3D gfc_match_dupl_check (!c->device_num_expr,
> + "device_num")) !=3D MATCH_NO)
> + {
> + if (m =3D=3D MATCH_ERROR)
> + goto error;
> + if (gfc_match ("( %e )", &c->device_num_expr) !=3D MATCH_YES)
> + goto error;
> + continue;
> + }
> if ((mask & OMP_CLAUSE_DEVICE_RESIDENT)
> && gfc_match_omp_variable_list
> ("device_resident (",
> @@ -5007,6 +5091,12 @@ error:
> (omp_mask (OMP_CLAUSE_GANG) | OMP_CLAUSE_WORKER | OMP_CLAUSE_VECTOR =
\
> | OMP_CLAUSE_SEQ \
> | OMP_CLAUSE_NOHOST)
> +#define OACC_INIT_CLAUSES =
\
> + (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICE_NUM | OMP_CLAUSE_DEVICE_=
TYPE)
> +#define OACC_SHUTDOWN_CLAUSES =
\
> + (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICE_NUM | OMP_CLAUSE_DEVICE_=
TYPE)
> +#define OACC_SET_CLAUSES =
\
> + (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICE_NUM | OMP_CLAUSE_DEVICE_=
TYPE)
>=20=20
>=20=20
> static match
> @@ -5301,6 +5391,24 @@ gfc_match_oacc_cache (void)
> return MATCH_YES;
> }
>=20=20
> +match
> +gfc_match_oacc_init (void)
> +{
> + return match_acc (EXEC_OACC_INIT, OACC_INIT_CLAUSES);
> +}
> +
> +match
> +gfc_match_oacc_shutdown (void)
> +{
> + return match_acc (EXEC_OACC_SHUTDOWN, OACC_SHUTDOWN_CLAUSES);
> +}
> +
> +match
> +gfc_match_oacc_set (void)
> +{
> + return match_acc (EXEC_OACC_SET, OACC_SET_CLAUSES);
> +}
> +
> /* Determine the OpenACC 'routine' directive's level of parallelism. */
>=20=20
> static oacc_routine_lop
> @@ -11386,6 +11494,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_cla=
uses *omp_clauses,
> if (omp_clauses->async)
> if (omp_clauses->async_expr)
> resolve_scalar_int_expr (omp_clauses->async_expr, "ASYNC");
> + if (omp_clauses->device_num_expr)
> + resolve_scalar_int_expr (omp_clauses->device_num_expr, "DEVICE_NUM");
> + if (code && code->op =3D=3D EXEC_OACC_SET
> + && !omp_clauses->device_num_expr
> + && !omp_clauses->oacc_device_type_present)
> + gfc_error ("At least one of the clauses %<DEVICE_TYPE%> and %<DEVICE=
_NUM%> "
> + "should be present in %<SET%> directive at %L", &code->loc);
> if (omp_clauses->num_gangs_expr)
> resolve_positive_int_expr (omp_clauses->num_gangs_expr, "NUM_GANGS");
> if (omp_clauses->num_workers_expr)
> @@ -13638,6 +13753,12 @@ oacc_code_to_statement (gfc_code *code)
> return ST_OACC_EXIT_DATA;
> case EXEC_OACC_DECLARE:
> return ST_OACC_DECLARE;
> + case EXEC_OACC_INIT:
> + return ST_OACC_INIT;
> + case EXEC_OACC_SHUTDOWN:
> + return ST_OACC_SHUTDOWN;
> + case EXEC_OACC_SET:
> + return ST_OACC_SET;
> default:
> gcc_unreachable ();
> }
> @@ -13971,6 +14092,9 @@ gfc_resolve_oacc_directive (gfc_code *code, gfc_n=
amespace *ns ATTRIBUTE_UNUSED)
> case EXEC_OACC_EXIT_DATA:
> case EXEC_OACC_WAIT:
> case EXEC_OACC_CACHE:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> resolve_omp_clauses (code, code->ext.omp_clauses, NULL, true);
> break;
> case EXEC_OACC_PARALLEL_LOOP:
> diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
> index 7b6cf525a80..eeb98865513 100644
> --- a/gcc/fortran/parse.cc
> +++ b/gcc/fortran/parse.cc
> @@ -790,6 +790,9 @@ decode_oacc_directive (void)
> case 'h':
> matcha ("host_data", gfc_match_oacc_host_data, ST_OACC_HOST_DATA);
> break;
> + case 'i':
> + matcha ("init", gfc_match_oacc_init, ST_OACC_INIT);
> + break;
> case 'p':
> matcha ("parallel loop", gfc_match_oacc_parallel_loop,
> ST_OACC_PARALLEL_LOOP);
> @@ -806,6 +809,8 @@ decode_oacc_directive (void)
> case 's':
> matcha ("serial loop", gfc_match_oacc_serial_loop, ST_OACC_SERIAL_=
LOOP);
> matcha ("serial", gfc_match_oacc_serial, ST_OACC_SERIAL);
> + matcha ("set", gfc_match_oacc_set, ST_OACC_SET);
> + matcha ("shutdown", gfc_match_oacc_shutdown, ST_OACC_SHUTDOWN);
> break;
> case 'u':
> matcha ("update", gfc_match_oacc_update, ST_OACC_UPDATE);
> @@ -1975,7 +1980,8 @@ next_statement (void)
> case ST_FORM_TEAM: case ST_SYNC_TEAM: \
> case ST_EVENT_POST: case ST_EVENT_WAIT: case ST_FAIL_IMAGE: \
> case ST_OACC_UPDATE: case ST_OACC_WAIT: case ST_OACC_CACHE: \
> - case ST_OACC_ENTER_DATA: case ST_OACC_EXIT_DATA
> + case ST_OACC_ENTER_DATA: case ST_OACC_EXIT_DATA: \
> + case ST_OACC_INIT: case ST_OACC_SHUTDOWN: case ST_OACC_SET
>=20=20
> /* Statements that mark other executable statements. */
>=20=20
> @@ -2692,6 +2698,15 @@ gfc_ascii_statement (gfc_statement st, bool strip_=
sentinel)
> case ST_OACC_END_ATOMIC:
> p =3D "!$ACC END ATOMIC";
> break;
> + case ST_OACC_INIT:
> + p =3D "!ACC INIT";
> + break;
> + case ST_OACC_SHUTDOWN:
> + p =3D "!ACC SHUTDOWN";
> + break;
> + case ST_OACC_SET:
> + p =3D "!ACC SET";
> + break;
> case ST_OMP_ALLOCATE:
> case ST_OMP_ALLOCATE_EXEC:
> p =3D "!$OMP ALLOCATE";
> @@ -8039,6 +8054,9 @@ is_oacc (gfc_state_data *sd)
> case EXEC_OACC_EXIT_DATA:
> case EXEC_OACC_ATOMIC:
> case EXEC_OACC_ROUTINE:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> return true;
>=20=20
> default:
> diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
> index 036da9a939e..389a7451619 100644
> --- a/gcc/fortran/resolve.cc
> +++ b/gcc/fortran/resolve.cc
> @@ -13053,6 +13053,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *n=
s)
> case EXEC_OACC_ENTER_DATA:
> case EXEC_OACC_EXIT_DATA:
> case EXEC_OACC_ROUTINE:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> case EXEC_OMP_ALLOCATE:
> case EXEC_OMP_ALLOCATORS:
> case EXEC_OMP_ASSUME:
> @@ -14839,6 +14842,9 @@ start:
> case EXEC_OACC_EXIT_DATA:
> case EXEC_OACC_ATOMIC:
> case EXEC_OACC_DECLARE:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> gfc_resolve_oacc_directive (code, ns);
> break;
>=20=20
> diff --git a/gcc/fortran/st.cc b/gcc/fortran/st.cc
> index 39711e32620..4c7e274b72a 100644
> --- a/gcc/fortran/st.cc
> +++ b/gcc/fortran/st.cc
> @@ -221,6 +221,9 @@ gfc_free_statement (gfc_code *p)
> case EXEC_OACC_ENTER_DATA:
> case EXEC_OACC_EXIT_DATA:
> case EXEC_OACC_ROUTINE:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> case EXEC_OMP_ALLOCATE:
> case EXEC_OMP_ALLOCATORS:
> case EXEC_OMP_ASSUME:
> diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
> index 31a84d51f16..3e4375f6d60 100644
> --- a/gcc/fortran/trans-openmp.cc
> +++ b/gcc/fortran/trans-openmp.cc
> @@ -6412,6 +6412,10 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp=
_clauses *clauses,
> /* OpenACC 'nohost' clauses cannot appear here. */
> gcc_checking_assert (!clauses->nohost);
>=20=20
> + /* OpenACC 'device_num' and 'device_type' clauses cannot appear here. =
*/
> + gcc_checking_assert (!clauses->device_num_expr
> + && !clauses->oacc_device_type_present);
> +
> return nreverse (omp_clauses);
> }
>=20=20
> @@ -6482,7 +6486,7 @@ gfc_trans_oacc_construct (gfc_code *code)
> return gfc_finish_block (&block);
> }
>=20=20
> -/* update, enter_data, exit_data, cache. */
> +/* update, enter_data, exit_data, cache, init, set, shutdown. */
> static tree
> gfc_trans_oacc_executable_directive (gfc_code *code)
> {
> @@ -6504,6 +6508,10 @@ gfc_trans_oacc_executable_directive (gfc_code *cod=
e)
> case EXEC_OACC_CACHE:
> construct_code =3D OACC_CACHE;
> break;
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> + goto builtin_oacc_exec_directive;
> default:
> gcc_unreachable ();
> }
> @@ -6515,6 +6523,67 @@ gfc_trans_oacc_executable_directive (gfc_code *cod=
e)
> oacc_clauses);
> gfc_add_expr_to_block (&block, stmt);
> return gfc_finish_block (&block);
> +
> +builtin_oacc_exec_directive:
> +
> + enum built_in_function builtin_code;
> +
> + switch (code->op)
> + {
> + case EXEC_OACC_INIT:
> + builtin_code =3D BUILT_IN_GOACC_INIT;
> + break;
> + case EXEC_OACC_SHUTDOWN:
> + builtin_code =3D BUILT_IN_GOACC_SHUTDOWN;
> + break;
> + case EXEC_OACC_SET:
> + builtin_code =3D BUILT_IN_GOACC_SET_DEVICE;
> + break;
> + default:
> + gcc_unreachable ();
> + }
> +
> + location_t loc =3D input_location;
> + gfc_omp_clauses *clauses =3D code->ext.omp_clauses;
> +
> + gfc_start_block (&block);
> +
> + tree n_device;
> + if (clauses->device_num_expr)
> + n_device =3D gfc_convert_expr_to_tree (&block, clauses->device_num_e=
xpr);
> + else
> + /* no 'device_num' clause specified by
> + the user, we don't modify the value of ICV
> + 'acc-current-device-num-var' or we do not
> + take any action in init and shutdown directive
> + using -1 value. */
> + n_device =3D build_int_cst (integer_type_node, -1);
> +
> + /* GOMP_DEVICE_NONE is used to make the operation
> + in all the devices.
> +
> + GOMP_DEVICE_DEFAULT is used in set directive
> + to do nothing if the clause do not appear. */
> + int device_type =3D code->op =3D=3D EXEC_OACC_SET ?
> + GOMP_DEVICE_DEFAULT :
> + GOMP_DEVICE_NONE;
> + if (clauses->oacc_device_type_present)
> + device_type =3D clauses->oacc_device_type;
> +
> + tree d_type =3D build_int_cst (integer_type_node, device_type);
> +
> + stmt =3D builtin_decl_explicit (builtin_code);
> +
> + stmt =3D build_call_expr_loc (loc, stmt, 2, n_device, d_type);
> +
> + if (clauses->if_expr)
> + stmt =3D build3_loc (input_location, COND_EXPR, void_type_node,
> + gfc_convert_expr_to_tree (&block, clauses->if_expr),
> + stmt, NULL_TREE);
> +
> + gfc_add_expr_to_block (&block, stmt);
> +
> + return gfc_finish_block (&block);
> }
>=20=20
> static tree
> @@ -9893,6 +9962,9 @@ gfc_trans_oacc_directive (gfc_code *code)
> case EXEC_OACC_CACHE:
> case EXEC_OACC_ENTER_DATA:
> case EXEC_OACC_EXIT_DATA:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> return gfc_trans_oacc_executable_directive (code);
> case EXEC_OACC_WAIT:
> return gfc_trans_oacc_wait_directive (code);
> diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc
> index 7418b811a72..cf37261673c 100644
> --- a/gcc/fortran/trans.cc
> +++ b/gcc/fortran/trans.cc
> @@ -2685,6 +2685,9 @@ trans_code (gfc_code * code, tree cond)
> case EXEC_OACC_EXIT_DATA:
> case EXEC_OACC_ATOMIC:
> case EXEC_OACC_DECLARE:
> + case EXEC_OACC_INIT:
> + case EXEC_OACC_SHUTDOWN:
> + case EXEC_OACC_SET:
> res =3D gfc_trans_oacc_directive (code);
> break;
>=20=20
> diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
> index eb253d8970e..73a1e0cd734 100644
> --- a/gcc/fortran/types.def
> +++ b/gcc/fortran/types.def
> @@ -125,6 +125,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_CONST_PTR_SIZE, BT_VO=
ID, BT_CONST_PTR, BT_SIZE)
> DEF_FUNCTION_TYPE_2 (BT_FN_PTR_CONST_PTR_INT, BT_PTR, BT_CONST_PTR, BT_I=
NT)
> DEF_FUNCTION_TYPE_2 (BT_FN_VOID_ULONGLONG_ULONGLONG,
> BT_VOID, BT_ULONGLONG, BT_ULONGLONG)
> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_INT_INT, BT_VOID, BT_INT, BT_INT)
>=20=20
> DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
>=20=20
> diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
> index 8e6b6fb3acf..500cc32ab4d 100644
> --- a/gcc/omp-builtins.def
> +++ b/gcc/omp-builtins.def
> @@ -51,6 +51,12 @@ DEF_GOACC_BUILTIN (BUILT_IN_GOACC_WAIT, "GOACC_wait",
> ATTR_NOTHROW_LIST)
> DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DECLARE, "GOACC_declare",
> BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_INIT, "GOACC_init",
> + BT_FN_VOID_INT_INT, ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_SHUTDOWN, "GOACC_shutdown",
> + BT_FN_VOID_INT_INT, ATTR_NOTHROW_LIST)
> +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_SET_DEVICE, "GOACC_set_device",
> + BT_FN_VOID_INT_INT, ATTR_NOTHROW_LIST)
>=20=20
> DEF_GOACC_BUILTIN_COMPILER (BUILT_IN_ACC_ON_DEVICE, "acc_on_device",
> BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
> diff --git a/gcc/testsuite/gfortran.dg/goacc/acc-init-1.f90 b/gcc/testsui=
te/gfortran.dg/goacc/acc-init-1.f90
> new file mode 100644
> index 00000000000..931cce7a924
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/goacc/acc-init-1.f90
> @@ -0,0 +1,47 @@
> +! Test parsing and lowering of the OpenACC init directive.
> +
> +! { dg-do compile }
> +! { dg-additional-options "-fdump-tree-original" }
> +
> +subroutine init0
> + implicit none
> + !$acc init
> +end subroutine init0
> +
> +subroutine init1
> + implicit none
> + !$acc init device_type(host)
> +end subroutine init1
> +
> +subroutine init2
> + implicit none
> + !$acc init device_type(nvidia)
> +end subroutine init2
> +
> +subroutine init3
> + implicit none
> + !$acc init device_num(0)
> +end subroutine init3
> +
> +subroutine init4
> + implicit none
> + !$acc init device_type(host) device_num(0)
> +end subroutine init4
> +
> +subroutine init5
> + implicit none
> + !$acc init if(.false.)
> +end subroutine init5
> +
> +subroutine init6(l)
> + implicit none
> + logical, value :: l
> + !$acc init if(l) device_type(radeon) device_num(1)
> +end subroutine init6
> +
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_init \\(-1, 0\\)" 2=
"original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_init \\(-1, 2\\)" 1=
"original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_init \\(-1, 5\\)" 1=
"original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_init \\(0, 0\\)" 1 =
"original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_init \\(0, 2\\)" 1 =
"original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_init \\(1, 8\\)" 1 =
"original" } }
> diff --git a/gcc/testsuite/gfortran.dg/goacc/acc-init-clauses-1.f90 b/gcc=
/testsuite/gfortran.dg/goacc/acc-init-clauses-1.f90
> new file mode 100644
> index 00000000000..30c86a798ee
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/goacc/acc-init-clauses-1.f90
> @@ -0,0 +1,28 @@
> +! Test invalid clauses on the OpenACC init directive.
> +
> +! { dg-do compile }
> +
> +subroutine bad1
> + implicit none
> + !$acc init device_type(doesnt_exist) ! { dg-error "Expected host, rade=
on, nvidia or \\\* as argument" }
> +end subroutine bad1
> +
> +subroutine bad2
> + implicit none
> + !$acc init device_type(nvidia, host) ! { dg-error "OpenACC 'DEVICE_TYP=
E' clause only accepts one argument" }
> +end subroutine bad2
> +
> +subroutine bad3
> + implicit none
> + !$acc init if_present ! { dg-error "Failed to match clause" }
> +end subroutine bad3
> +
> +subroutine bad4
> + implicit none
> + !$acc init async ! { dg-error "Failed to match clause" }
> +end subroutine bad4
> +
> +subroutine bad5
> + implicit none
> + !$acc init wait ! { dg-error "Failed to match clause" }
> +end subroutine bad5
> diff --git a/gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90 b/gcc/testsuit=
e/gfortran.dg/goacc/acc-set-1.f90
> new file mode 100644
> index 00000000000..013c301c775
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90
> @@ -0,0 +1,36 @@
> +! Test parsing and lowering of the OpenACC set directive.
> +
> +! { dg-do compile }
> +! { dg-additional-options "-fdump-tree-original" }
> +
> +subroutine set0
> + implicit none
> + !$acc set device_type(host)
> +end subroutine set0
> +
> +subroutine set1
> + implicit none
> + !$acc set device_type(nvidia)
> +end subroutine set1
> +
> +subroutine set2
> + implicit none
> + !$acc set device_num(0)
> +end subroutine set2
> +
> +subroutine set3
> + implicit none
> + !$acc set device_type(host) device_num(0)
> +end subroutine set3
> +
> +subroutine set4(l)
> + implicit none
> + logical, value :: l
> + !$acc set if(l) device_type(radeon) device_num(1)
> +end subroutine set4
> +
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(-1, 2=
\\)" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(-1, 5=
\\)" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(0, 1\=
\)" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(0, 2\=
\)" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(1, 8\=
\)" 1 "original" } }
> diff --git a/gcc/testsuite/gfortran.dg/goacc/acc-set-clauses-1.f90 b/gcc/=
testsuite/gfortran.dg/goacc/acc-set-clauses-1.f90
> new file mode 100644
> index 00000000000..9ed31a0fea2
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/goacc/acc-set-clauses-1.f90
> @@ -0,0 +1,58 @@
> +! Test invalid clauses on the OpenACC set directive.
> +
> +! { dg-do compile }
> +
> +subroutine bad1
> + implicit none
> + !$acc set device_type(doesnt_exist) ! { dg-error "Expected host, radeo=
n, nvidia or \\* as argument" }
> +end subroutine bad1
> +
> +subroutine bad2
> + implicit none
> + !$acc set device_type(nvidia, host) ! { dg-error "OpenACC 'DEVICE_TYPE=
' clause only accepts one argument" }
> +end subroutine bad2
> +
> +subroutine bad3
> + implicit none
> + !$acc set ! { dg-error "At least one of the clauses 'DEVICE_TYPE' and =
'DEVICE_NUM' should be present in 'SET' directive" }
> +end subroutine bad3
> +
> +subroutine bad4
> + implicit none
> + !$acc set if(.true.) ! { dg-error "At least one of the clauses 'DEVICE=
_TYPE' and 'DEVICE_NUM' should be present in 'SET' directive" }
> +end subroutine bad4
> +
> +subroutine bad5
> + implicit none
> + !$acc set default_async(0) ! { dg-error "Failed to match clause" }
> +end subroutine bad5
> +
> +subroutine bad6
> + implicit none
> + !$acc set if_present ! { dg-error "Failed to match clause" }
> +end subroutine bad6
> +
> +subroutine bad7
> + implicit none
> + !$acc set async ! { dg-error "Failed to match clause" }
> +end subroutine bad7
> +
> +subroutine bad8
> + implicit none
> + !$acc set wait ! { dg-error "Failed to match clause" }
> +end subroutine bad8
> +
> +subroutine bad9
> + implicit none
> + !$acc set device_type(host) device_type(nvidia) ! { dg-error "Duplicat=
ed 'device_type' clause" }
> +end subroutine bad9
> +
> +subroutine bad10
> + implicit none
> + !$acc set device_num(0) device_num(1) ! { dg-error "Duplicated 'device=
_num' clause" }
> +end subroutine bad10
> +
> +subroutine bad11
> + implicit none
> + !$acc set if(.false.) if(.true.) ! { dg-error "Duplicated 'if' clause"=
}
> +end subroutine bad11
> diff --git a/gcc/testsuite/gfortran.dg/goacc/acc-shutdown-1.f90 b/gcc/tes=
tsuite/gfortran.dg/goacc/acc-shutdown-1.f90
> new file mode 100644
> index 00000000000..72db24750f1
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/goacc/acc-shutdown-1.f90
> @@ -0,0 +1,47 @@
> +! Test parsing and lowering of the OpenACC shutdown directive.
> +
> +! { dg-do compile }
> +! { dg-additional-options "-fdump-tree-original" }
> +
> +subroutine shutdown0
> + implicit none
> + !$acc shutdown
> +end subroutine shutdown0
> +
> +subroutine shutdown1
> + implicit none
> + !$acc shutdown device_type(host)
> +end subroutine shutdown1
> +
> +subroutine shutdown2
> + implicit none
> + !$acc shutdown device_type(nvidia)
> +end subroutine shutdown2
> +
> +subroutine shutdown3
> + implicit none
> + !$acc shutdown device_num(0)
> +end subroutine shutdown3
> +
> +subroutine shutdown4
> + implicit none
> + !$acc shutdown device_type(host) device_num(0)
> +end subroutine shutdown4
> +
> +subroutine shutdown5
> + implicit none
> + !$acc shutdown if(.false.)
> +end subroutine shutdown5
> +
> +subroutine shutdown6(l)
> + implicit none
> + logical, value :: l
> + !$acc shutdown if(l) device_type(radeon) device_num(1)
> +end subroutine shutdown6
> +
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_shutdown \\(-1, 0\\=
)" 2 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_shutdown \\(-1, 2\\=
)" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_shutdown \\(-1, 5\\=
)" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_shutdown \\(0, 0\\)=
" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_shutdown \\(0, 2\\)=
" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "__builtin_GOACC_shutdown \\(1, 8\\)=
" 1 "original" } }
> diff --git a/gcc/testsuite/gfortran.dg/goacc/acc-shutdown-clauses-1.f90 b=
/gcc/testsuite/gfortran.dg/goacc/acc-shutdown-clauses-1.f90
> new file mode 100644
> index 00000000000..242d05a5e67
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/goacc/acc-shutdown-clauses-1.f90
> @@ -0,0 +1,43 @@
> +! Test invalid clauses on the OpenACC shutdown directive.
> +
> +! { dg-do compile }
> +
> +subroutine bad1
> + implicit none
> + !$acc shutdown device_type(doesnt_exist) ! { dg-error "Expected host, =
radeon, nvidia or \\* as argument" }
> +end subroutine bad1
> +
> +subroutine bad2
> + implicit none
> + !$acc shutdown device_type(nvidia, host) ! { dg-error "OpenACC 'DEVICE=
_TYPE' clause only accepts one argument" }
> +end subroutine bad2
> +
> +subroutine bad3
> + implicit none
> + !$acc shutdown if_present ! { dg-error "Failed to match clause" }
> +end subroutine bad3
> +
> +subroutine bad4
> + implicit none
> + !$acc shutdown async ! { dg-error "Failed to match clause" }
> +end subroutine bad4
> +
> +subroutine bad5
> + implicit none
> + !$acc shutdown wait ! { dg-error "Failed to match clause" }
> +end subroutine bad5
> +
> +subroutine bad6
> + implicit none
> + !$acc shutdown device_type(host) device_type(nvidia) ! { dg-error "Dup=
licated 'device_type' clause" }
> +end subroutine bad6
> +
> +subroutine bad7
> + implicit none
> + !$acc shutdown device_num(0) device_num(1) ! { dg-error "Duplicated 'd=
evice_num' clause" }
> +end subroutine bad7
> +
> +subroutine bad8
> + implicit none
> + !$acc shutdown if(.false.) if(.true.) ! { dg-error "Duplicated 'if' cl=
ause" }
> +end subroutine bad8
> diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95 b/gcc/t=
estsuite/gfortran.dg/goacc/uninit-if-clause.f95
> index 940fe841c20..89301af4785 100644
> --- a/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
> +++ b/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
> @@ -3,12 +3,13 @@
>=20=20
> program test
> implicit none
> - logical :: b, b2, bs, b3, b4
> + logical :: b, b2, bs, b3, b4, b5
> ! { dg-note {'b' was declared here} {} { target *-*-* } .-1 }
> ! { dg-note {'b2' was declared here} {} { target *-*-* } .-2 }
> ! { dg-note {'bs' was declared here} {} { target *-*-* } .-3 }
> ! { dg-note {'b3' was declared here} {} { target *-*-* } .-4 }
> ! { dg-note {'b4' was declared here} {} { target *-*-* } .-5 }
> + ! { dg-note {'b5' was declared here} {} { target *-*-* } .-6 }
> integer :: data, data2
>=20=20
> !$acc parallel if(b) ! { dg-warning "is used uninitialized" }
> @@ -25,4 +26,6 @@ program test
>=20=20
> !$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized"=
}
>=20=20
> + !$acc init if(b5) ! { dg-warning "is used uninitialized" }
> +
> end program test
> diff --git a/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90 b/gc=
c/testsuite/gfortran.dg/goacc/update-if_present-2.f90
> index 41c2657b536..9a350a8c845 100644
> --- a/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90
> +++ b/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90
> @@ -20,8 +20,8 @@ subroutine t1
>=20=20
> !$acc declare link(a) if_present ! { dg-error "Unexpected junk after" }
>=20=20
> - !$acc init if_present ! { dg-error "Unclassifiable OpenACC directive" }
> - !$acc shutdown if_present ! { dg-error "Unclassifiable OpenACC directi=
ve" }
> + !$acc init if_present ! { dg-error "Failed to match clause" }
> + !$acc shutdown if_present ! { dg-error "Failed to match clause" }
>=20=20=20=20
> !$acc update self(a) device_type(nvidia) device(b) if_present ! { dg-e=
rror "Failed to match clause" }
> end subroutine t1
> diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
> index 8a59d4965b3..00e47d65d4c 100644
> --- a/libgomp/libgomp.map
> +++ b/libgomp/libgomp.map
> @@ -691,6 +691,13 @@ GOACC_2.0.2 {
> GOACC_exit_data;
> } GOACC_2.0.1;
>=20=20
> +GOACC_2.5 {
> + global:
> + GOACC_init;
> + GOACC_shutdown;
> + GOACC_set_device;
> +} GOACC_2.0.2;
> +
> GOMP_PLUGIN_1.0 {
> global:
> GOMP_PLUGIN_malloc;
> diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h
> index f5f1d8e677b..9caf9c3571b 100644
> --- a/libgomp/libgomp_g.h
> +++ b/libgomp/libgomp_g.h
> @@ -413,6 +413,12 @@ extern void GOMP_error (const char *, size_t);
>=20=20
> extern void GOACC_wait (int, int, ...);
>=20=20
> +/* oacc-init.c */
> +
> +extern void GOACC_init (int, int);
> +extern void GOACC_shutdown (int, int);
> +extern void GOACC_set_device (int, int);
> +
> /* oacc-mem.c */
>=20=20
> extern void GOACC_enter_exit_data (int, size_t, void **, size_t *,
> diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
> index bfd50bf39a5..b9e6d405b0b 100644
> --- a/libgomp/oacc-init.c
> +++ b/libgomp/oacc-init.c
> @@ -69,6 +69,10 @@ static gomp_mutex_t goacc_thread_lock;
> grouped by device in target.c:devices). */
> static struct gomp_device_descr *dispatchers[_ACC_device_hwm] =3D { 0 };
>=20=20
> +/* Device types for init and shutdown directives to check all devices. =
*/
> +#define GOACC_DIRECTIVE_DEVICE_MASK =
\
> + ((1 << acc_device_host) | (1 << acc_device_nvidia) | (1 << acc_device_=
radeon))
> +
> attribute_hidden void
> goacc_register (struct gomp_device_descr *disp)
> {
> @@ -231,7 +235,8 @@ acc_dev_num_out_of_range (acc_device_t d, int ord, in=
t ndevs)
> held before calling this function. */
>=20=20
> static struct gomp_device_descr *
> -acc_init_1 (acc_device_t d, acc_construct_t parent_construct, int implic=
it)
> +acc_init_1 (acc_device_t d, acc_construct_t parent_construct, int implic=
it,
> + int dev_num)
> {
> gomp_mutex_lock (&acc_init_state_lock);
> acc_init_state =3D initializing;
> @@ -304,10 +309,12 @@ acc_init_1 (acc_device_t d, acc_construct_t parent_=
construct, int implicit)
>=20=20
> ndevs =3D base_dev->get_num_devices_func ();
>=20=20
> - if (ndevs <=3D 0 || goacc_device_num >=3D ndevs)
> - acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
> + dev_num =3D (dev_num =3D=3D -1 ? goacc_device_num : dev_num);
>=20=20
> - acc_dev =3D &base_dev[goacc_device_num];
> + if (ndevs <=3D 0 || dev_num >=3D ndevs)
> + acc_dev_num_out_of_range (d, dev_num, ndevs);
> +
> + acc_dev =3D &base_dev[dev_num];
>=20=20
> gomp_mutex_lock (&acc_dev->lock);
> if (acc_dev->state =3D=3D GOMP_DEVICE_INITIALIZED)
> @@ -341,7 +348,7 @@ acc_init_1 (acc_device_t d, acc_construct_t parent_co=
nstruct, int implicit)
> /* ACC_DEVICE_LOCK must be held before calling this function. */
>=20=20
> static void
> -acc_shutdown_1 (acc_device_t d)
> +acc_shutdown_1 (acc_device_t d, int dev_num)
> {
> struct gomp_device_descr *base_dev;
> struct goacc_thread *walk;
> @@ -353,21 +360,42 @@ acc_shutdown_1 (acc_device_t d)
>=20=20
> ndevs =3D base_dev->get_num_devices_func ();
>=20=20
> - /* Unload all the devices of this type that have been opened. */
> - for (i =3D 0; i < ndevs; i++)
> - {
> - struct gomp_device_descr *acc_dev =3D &base_dev[i];
> + if (dev_num !=3D -1 && ndevs <=3D dev_num)
> + acc_dev_num_out_of_range (d, dev_num, ndevs);
>=20=20
> + if (dev_num !=3D -1)
> + {
> + struct gomp_device_descr *acc_dev =3D &base_dev[dev_num];
> gomp_mutex_lock (&acc_dev->lock);
> gomp_unload_device (acc_dev);
> gomp_mutex_unlock (&acc_dev->lock);
> }
> -=20=20
> + else
> + {
> + /* Unload all the devices of this type that have been opened. */
> + for (i =3D 0; i < ndevs; i++)
> + {
> + struct gomp_device_descr *acc_dev =3D &base_dev[i];
> +
> + gomp_mutex_lock (&acc_dev->lock);
> + gomp_unload_device (acc_dev);
> + gomp_mutex_unlock (&acc_dev->lock);
> + }
> + }
> +
> gomp_mutex_lock (&goacc_thread_lock);
>=20=20
> /* Free target-specific TLS data and close all devices. */
> for (walk =3D goacc_threads; walk !=3D NULL; walk =3D walk->next)
> {
> + /* These checks are necessary since init supports
> + * multiples devices. */
> + if (walk->base_dev !=3D base_dev)
> + continue;
> +
> + if (dev_num !=3D -1 && walk->dev !=3D &base_dev[dev_num])
> + continue;
> +
> if (walk->target_tls)
> base_dev->openacc.destroy_thread_data_func (walk->target_tls);
>=20=20
> @@ -409,20 +437,38 @@ acc_shutdown_1 (acc_device_t d)
>=20=20
> gomp_mutex_unlock (&goacc_thread_lock);
>=20=20
> - /* Close all the devices of this type that have been opened. */
> bool ret =3D true;
> - for (i =3D 0; i < ndevs; i++)
> +
> + if (dev_num !=3D -1)
> {
> - struct gomp_device_descr *acc_dev =3D &base_dev[i];
> + struct gomp_device_descr *acc_dev =3D &base_dev[dev_num];
> gomp_mutex_lock (&acc_dev->lock);
> +
> if (acc_dev->state =3D=3D GOMP_DEVICE_INITIALIZED)
> - {
> + {
> devices_active =3D true;
> ret &=3D gomp_fini_device (acc_dev);
> acc_dev->state =3D GOMP_DEVICE_UNINITIALIZED;
> }
> +
> gomp_mutex_unlock (&acc_dev->lock);
> }
> + else
> + {
> + /* Close all the devices of this type that have been opened. */
> + for (i =3D 0; i < ndevs; i++)
> + {
> + struct gomp_device_descr *acc_dev =3D &base_dev[i];
> + gomp_mutex_lock (&acc_dev->lock);
> + if (acc_dev->state =3D=3D GOMP_DEVICE_INITIALIZED)
> + {
> + devices_active =3D true;
> + ret &=3D gomp_fini_device (acc_dev);
> + acc_dev->state =3D GOMP_DEVICE_UNINITIALIZED;
> + }
> + gomp_mutex_unlock (&acc_dev->lock);
> + }
> + }
>=20=20
> if (!ret)
> gomp_fatal ("device finalization failed");
> @@ -541,6 +587,109 @@ goacc_attach_host_thread_to_device (int ord)
> =3D acc_dev->openacc.create_thread_data_func (ord);
> }
>=20=20
> +void
> +GOACC_init (int n_device, int d)
> +{
> + /* The OpenACC spec says that if the n_device isn't specified
> + then all the devices available are initializated, but
> + the current acc_init_1 implementation initialize just the
> + goacc_device_num device number. acc_init_1 it's keeped
> + because the profiling dispatch code. */
> +
> + gomp_init_targets_once ();
> + /* All the device types. */
> + if ((acc_device_t) d =3D=3D acc_device_none)
> + {
> + int i;
> + for (i =3D 0; i < _ACC_device_hwm; i++)
> + {
> + if (!(GOACC_DIRECTIVE_DEVICE_MASK & (1 << i)))
> + continue;
> + gomp_mutex_lock (&acc_device_lock);
> +
> + struct gomp_device_descr *dev
> + =3D resolve_device ((acc_device_t) i, false);
> + if (!dev || dev->get_num_devices_func () <=3D 0)
> + {
> + gomp_debug (0,
> + "init directive: Device type %s isn't available or "
> + "does not have devices.\n",
> + name_of_acc_device_t ((acc_device_t) i));
> + /* if isn't available, just continue. */
> + gomp_mutex_unlock (&acc_device_lock);
> + continue;
> + }
> +
> + gomp_debug (0,
> + "init directive: Initializing device type %s and device "
> + "number %d. \n",
> + name_of_acc_device_t ((acc_device_t) i), n_device);
> + cached_base_dev
> + =3D acc_init_1 ((acc_device_t) i, acc_construct_init, 0, n_device);
> + gomp_mutex_unlock (&acc_device_lock);
> + }
> + }
> + else
> + {
> + gomp_debug (
> + 0, "init directive: Initializing device type %s and device number %d\n",
> + name_of_acc_device_t ((acc_device_t) d), n_device);
> +
> + gomp_mutex_lock (&acc_device_lock);
> + cached_base_dev
> + =3D acc_init_1 ((acc_device_t) d, acc_construct_init, 0, n_device);
> + gomp_mutex_unlock (&acc_device_lock);
> +
> + goacc_attach_host_thread_to_device (-1);
> + }
> +}
> +
> +void
> +GOACC_shutdown (int n_device, int d)
> +{
> + gomp_init_targets_once ();
> +
> + if ((acc_device_t) d =3D=3D acc_device_none)
> + {
> + int i;
> + for (i =3D 0; i < _ACC_device_hwm; i++)
> + {
> + if (!(GOACC_DIRECTIVE_DEVICE_MASK & (1 << i)))
> + continue;
> +
> + gomp_mutex_lock (&acc_device_lock);
> +
> + struct gomp_device_descr *dev
> + =3D resolve_device ((acc_device_t) i, false);
> +
> + if (!dev || dev->get_num_devices_func () <=3D 0)
> + {
> + gomp_mutex_unlock (&acc_device_lock);
> + continue;
> + }
> +
> + acc_shutdown_1 ((acc_device_t) i, n_device);
> +
> + gomp_mutex_unlock (&acc_device_lock);
> + }
> + }
> + else
> + {
> + gomp_mutex_lock (&acc_device_lock);
> +
> + acc_shutdown_1 ((acc_device_t) d, n_device);
> +
> + gomp_mutex_unlock (&acc_device_lock);
> + }
> +}
> +
> +void
> +GOACC_set_device (int n_device, int d)
> +{
> + acc_set_device_type ((acc_device_t) d);
> + acc_set_device_num (n_device, (acc_device_t) d);
> +}
> +
> /* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serializati=
on of
> init/shutdown is per-process or per-thread. We choose per-process. =
*/
>=20=20
> @@ -553,7 +702,7 @@ acc_init (acc_device_t d)
> gomp_init_targets_once ();
>=20=20
> gomp_mutex_lock (&acc_device_lock);
> - cached_base_dev =3D acc_init_1 (d, acc_construct_runtime_api, 0);
> + cached_base_dev =3D acc_init_1 (d, acc_construct_runtime_api, 0, -1);
> gomp_mutex_unlock (&acc_device_lock);
>=20=20=20=20
> goacc_attach_host_thread_to_device (-1);
> @@ -569,7 +718,7 @@ acc_shutdown (acc_device_t d)
>=20=20
> gomp_mutex_lock (&acc_device_lock);
>=20=20
> - acc_shutdown_1 (d);
> + acc_shutdown_1 (d, -1);
>=20=20
> gomp_mutex_unlock (&acc_device_lock);
> }
> @@ -926,8 +1075,8 @@ goacc_lazy_initialize (void)
>=20=20
> gomp_mutex_lock (&acc_device_lock);
> if (!cached_base_dev)
> - cached_base_dev =3D acc_init_1 (acc_device_default,
> - acc_construct_parallel, 1);
> + cached_base_dev
> + =3D acc_init_1 (acc_device_default, acc_construct_parallel, 1, -1);
> gomp_mutex_unlock (&acc_device_lock);
>=20=20
> goacc_attach_host_thread_to_device (-1);
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/init-1.f90 b/libgomp/=
testsuite/libgomp.oacc-fortran/init-1.f90
> new file mode 100644
> index 00000000000..e33c4cb30ea
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/init-1.f90
> @@ -0,0 +1,59 @@
> +! { dg-do run }
> +!
> +! Test the OpenACC init directive at run time.
> +
> +use openacc
> +
> +implicit none
> +
> +logical :: l
> +integer :: n
> +
> +if (acc_get_num_devices (acc_device_host) .ne. 1) stop 1
> +
> +!$acc init
> +!$acc shutdown
> +
> +!$acc init device_type(host)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 2
> +if (acc_get_device_num (acc_device_host) .ne. 0) stop 3
> +
> +!$acc shutdown device_type(host)
> +
> +!$acc init device_type(host) device_num(0)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 4
> +if (acc_get_device_num (acc_device_host) .ne. 0) stop 5
> +
> +!$acc shutdown device_type(host)
> +
> +l =3D .true.
> +!$acc init if (l) device_type(host)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 6
> +
> +!$acc shutdown device_type(host)
> +
> +n =3D acc_get_num_devices (acc_device_default)
> +!$acc init if (.false.) device_num(n)
> +
> +if (acc_get_num_devices (acc_device_nvidia) .ne. 0) then
> + l =3D .true.
> + !$acc init if (l) device_type(nvidia)
> + l =3D .false.
> + !$acc init if (l) device_type(host)=20
> + if (acc_get_device_type () .ne. acc_device_nvidia) stop 7
> + !$acc shutdown device_type(nvidia)
> +end if
> +
> +if (acc_get_num_devices (acc_device_radeon) .ne. 0) then
> + l =3D .true.
> + !$acc init if (l) device_type(radeon)
> + l =3D .false.
> + !$acc init if (l) device_type(host)=20
> + if (acc_get_device_type () .ne. acc_device_radeon) stop 8
> + !$acc shutdown device_type(radeon)
> +end if
> +
> +end
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/lib-1-directives.f90 =
b/libgomp/testsuite/libgomp.oacc-fortran/lib-1-directives.f90
> new file mode 100644
> index 00000000000..182b238f844
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/lib-1-directives.f90
> @@ -0,0 +1,17 @@
> +! { dg-do run }
> +!
> +! Port of lib-1.f90 replacing applicable runtime calls with directives.
> +
> +use openacc
> +
> +if (acc_get_num_devices (acc_device_host) .ne. 1) STOP 1
> +!$acc set device_type(host)
> +if (acc_get_device_type () .ne. acc_device_host) STOP 2
> +!$acc set device_type(host) device_num(0)
> +if (acc_get_device_num (acc_device_host) .ne. 0) STOP 3
> +!$acc shutdown device_type(host)
> +
> +!$acc init device_type(host)
> +!$acc shutdown device_type(host)
> +
> +end
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/lib-4-directives.f90 =
b/libgomp/testsuite/libgomp.oacc-fortran/lib-4-directives.f90
> new file mode 100644
> index 00000000000..b4e8a6e7a54
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/lib-4-directives.f90
> @@ -0,0 +1,37 @@
> +! { dg-do run }
> +!
> +! Port of lib-4.f90 replacing applicable runtime calls with directives.
> +
> +program main
> + use openacc
> + implicit none
> +
> + integer n
> +
> + if (acc_get_num_devices (acc_device_host) .ne. 1) STOP 1
> +
> + if (acc_get_num_devices (acc_device_none) .ne. 0) STOP 2
> +
> + !$acc init device_type(host)
> +
> + if (acc_get_device_type () .ne. acc_device_host) STOP 3
> +
> + !$acc set device_type(host)
> +
> + if (acc_get_device_type () .ne. acc_device_host) STOP 4
> +
> + n =3D 0
> +
> + !$acc set device_type(host) device_num(n)
> +
> + if (acc_get_device_num (acc_device_host) .ne. 0) STOP 5
> +
> + if (.NOT. acc_async_test (n) ) STOP 6
> +
> + call acc_wait (n)
> +
> + call acc_wait_all ()
> +
> + !$acc shutdown device_type(host)
> +
> +end program
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/lib-5-directives.f90 =
b/libgomp/testsuite/libgomp.oacc-fortran/lib-5-directives.f90
> new file mode 100644
> index 00000000000..dde01c28852
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/lib-5-directives.f90
> @@ -0,0 +1,59 @@
> +! { dg-do run }
> +!
> +! Port of lib-5.f90 replacing applicable runtime calls with directives.
> +
> +program main
> + use openacc
> + implicit none
> +
> + integer n
> +
> + if (acc_get_num_devices (acc_device_nvidia) .ne. 0) then
> +
> + !$acc init device_type(nvidia)
> +
> + n =3D 0
> +
> + !$acc set device_type(nvidia) device_num(n)
> +
> + if (acc_get_device_num (acc_device_nvidia) .ne. 0) stop 11
> +
> + if (acc_get_num_devices (acc_device_nvidia) .gt. 1) then
> +
> + n =3D 1
> +
> + !$acc set device_type(nvidia) device_num(n)
> +
> + if (acc_get_device_num (acc_device_nvidia) .ne. 1) stop 12
> +
> + end if
> +
> + !$acc shutdown device_type(nvidia)
> +
> + end if
> +
> + if (acc_get_num_devices (acc_device_radeon) .ne. 0) then
> +
> + !$acc init device_type(radeon)
> +
> + n =3D 0
> +
> + !$acc set device_type(radeon) device_num(n)
> +
> + if (acc_get_device_num (acc_device_radeon) .ne. 0) stop 21
> +
> + if (acc_get_num_devices (acc_device_radeon) .gt. 1) then
> +
> + n =3D 1
> +
> + !$acc set device_type(radeon) device_num(n)
> +
> + if (acc_get_device_num (acc_device_radeon) .ne. 1) stop 22
> +
> + end if
> +
> + !$acc shutdown device_type(radeon)
> +
> + end if
> +
> +end program
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/lib-5-init.f90 b/libg=
omp/testsuite/libgomp.oacc-fortran/lib-5-init.f90
> new file mode 100644
> index 00000000000..3c50508e733
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/lib-5-init.f90
> @@ -0,0 +1,59 @@
> +! { dg-do run }
> +!
> +! Port of lib-5.f90 using !$acc init instead of call acc_init.
> +
> +program main
> + use openacc
> + implicit none
> +
> + integer n
> +
> + if (acc_get_num_devices (acc_device_nvidia) .ne. 0) then
> +
> + !$acc init device_type(nvidia)
> +
> + n =3D 0
> +
> + call acc_set_device_num (n, acc_device_nvidia)
> +
> + if (acc_get_device_num (acc_device_nvidia) .ne. 0) stop 11
> +
> + if (acc_get_num_devices (acc_device_nvidia) .gt. 1) then
> +
> + n =3D 1
> +
> + call acc_set_device_num (n, acc_device_nvidia)
> +
> + if (acc_get_device_num (acc_device_nvidia) .ne. 1) stop 12
> +
> + end if
> +
> + call acc_shutdown (acc_device_nvidia)
> +
> + end if
> +
> + if (acc_get_num_devices (acc_device_radeon) .ne. 0) then
> +
> + !$acc init device_type(radeon)
> +
> + n =3D 0
> +
> + call acc_set_device_num (n, acc_device_radeon)
> +
> + if (acc_get_device_num (acc_device_radeon) .ne. 0) stop 21
> +
> + if (acc_get_num_devices (acc_device_radeon) .gt. 1) then
> +
> + n =3D 1
> +
> + call acc_set_device_num (n, acc_device_radeon)
> +
> + if (acc_get_device_num (acc_device_radeon) .ne. 1) stop 22
> +
> + end if
> +
> + call acc_shutdown (acc_device_radeon)
> +
> + end if
> +
> +end program
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/set-1.f90 b/libgomp/t=
estsuite/libgomp.oacc-fortran/set-1.f90
> new file mode 100644
> index 00000000000..440c43e1638
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/set-1.f90
> @@ -0,0 +1,82 @@
> +! { dg-do run }
> +!
> +! Test the OpenACC set directive at run time.
> +
> +use openacc
> +
> +implicit none
> +
> +logical :: l
> +integer :: n
> +
> +if (acc_get_num_devices (acc_device_host) .ne. 1) stop 1
> +
> +call acc_init (acc_device_host)
> +
> +!$acc set device_type(host)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 2
> +
> +
> +! This set device_num(0) call init all the devices,
> +! so we can skip the init call later
> +
> +!$acc set device_num(0)
> +
> +if (acc_get_device_num (acc_device_host) .ne. 0) stop 3
> +
> +!$acc set device_type(host) device_num(0)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 4
> +if (acc_get_device_num (acc_device_host) .ne. 0) stop 5
> +
> +l =3D .true.
> +!$acc set if (l) device_type(host)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 6
> +
> +l =3D .false.
> +n =3D 1
> +!$acc set if (l) device_num(n)
> +
> +if (acc_get_device_num (acc_device_host) .ne. 0) stop 7
> +
> +call acc_shutdown (acc_device_host)
> +
> +if (acc_get_num_devices (acc_device_nvidia) .ne. 0) then
> +
> + !$acc set device_type(nvidia)
> +
> + if (acc_get_device_type () .ne. acc_device_nvidia) stop 11
> +
> + n =3D 0
> + !$acc set device_type(nvidia) device_num(n)
> +
> + if (acc_get_device_num (acc_device_nvidia) .ne. 0) stop 12
> +
> + l =3D .false.
> + !$acc set if (l) device_type(host)
> + if (acc_get_device_type () .ne. acc_device_nvidia) stop 13
> +
> + call acc_shutdown (acc_device_nvidia)
> +end if
> +
> +if (acc_get_num_devices (acc_device_radeon) .ne. 0) then
> +
> + !$acc set device_type(radeon)
> +
> + if (acc_get_device_type () .ne. acc_device_radeon) stop 21
> +
> + n =3D 0
> + !$acc set device_type(radeon) device_num(n)
> +
> + if (acc_get_device_num (acc_device_radeon) .ne. 0) stop 22
> +
> + l =3D .false.
> + !$acc set if (l) device_type(host)
> + if (acc_get_device_type () .ne. acc_device_radeon) stop 23
> +
> + call acc_shutdown (acc_device_radeon)
> +end if
> +
> +end
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/shutdown-1.f90 b/libg=
omp/testsuite/libgomp.oacc-fortran/shutdown-1.f90
> new file mode 100644
> index 00000000000..6cf06571f2c
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/shutdown-1.f90
> @@ -0,0 +1,53 @@
> +! { dg-do run }
> +!
> +! Test the OpenACC shutdown directive at run time.
> +
> +use openacc
> +
> +implicit none
> +
> +logical :: l
> +integer :: n
> +
> +if (acc_get_num_devices (acc_device_host) .ne. 1) stop 1
> +
> +!$acc init device_type(host)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 2
> +if (acc_get_device_num (acc_device_host) .ne. 0) stop 3
> +
> +!$acc shutdown device_type(host)
> +
> +!$acc init device_type(host) device_num(0)
> +
> +!$acc shutdown device_type(host) device_num(0)
> +
> +l =3D .true.
> +!$acc init if (l) device_type(host)
> +
> +if (acc_get_device_type () .ne. acc_device_host) stop 4
> +
> +!$acc shutdown if (l) device_type(host)
> +
> +n =3D acc_get_num_devices (acc_device_default)
> +!$acc shutdown if (.false.) device_num(n)
> +
> +if (acc_get_num_devices (acc_device_nvidia) .ne. 0) then
> + l =3D .true.
> + !$acc init if (l) device_type(nvidia)
> + if (acc_get_device_type () .ne. acc_device_nvidia) stop 5
> + l =3D .false.
> + !$acc shutdown if (l) device_type(host)
> + !$acc shutdown device_type(nvidia)
> +end if
> +
> +if (acc_get_num_devices (acc_device_radeon) .ne. 0) then
> + l =3D .true.
> + !$acc init if (l) device_type(radeon)
> + if (acc_get_device_type () .ne. acc_device_radeon) stop 6
> + l =3D .false.
> + !$acc shutdown if (l) device_type(host)
> + !$acc shutdown device_type(radeon)
> +end if
> +
> +end
> --=20
> 2.53.0
--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline; filename=patch
diff --git gcc/builtin-types.def gcc/builtin-types.def
index 1c49624d0bf..19da735791e 100644
--- gcc/builtin-types.def
+++ gcc/builtin-types.def
@@ -694,7 +694,6 @@ DEF_FUNCTION_TYPE_2 (BT_FN_PTR_CONST_PTR_UINT8, BT_PTR, BT_CONST_PTR, BT_UINT8)
DEF_FUNCTION_TYPE_2 (BT_FN_PTR_CONST_PTR_INT, BT_PTR, BT_CONST_PTR, BT_INT)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_ULONGLONG_ULONGLONG,
BT_VOID, BT_ULONGLONG, BT_ULONGLONG)
-
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_INT_INT, BT_VOID, BT_INT, BT_INT)
DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
diff --git gcc/fortran/frontend-passes.cc gcc/fortran/frontend-passes.cc
index cfcf1bff855..77d0f3bf24b 100644
--- gcc/fortran/frontend-passes.cc
+++ gcc/fortran/frontend-passes.cc
@@ -5730,13 +5730,10 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
case EXEC_OACC_INIT:
case EXEC_OACC_SHUTDOWN:
case EXEC_OACC_SET:
-
if (co->ext.omp_clauses)
- {
- WALK_SUBEXPR (co->ext.omp_clauses->device_num_expr);
- }
-
+ WALK_SUBEXPR (co->ext.omp_clauses->device_num_expr);
break;
+
default:
break;
}
diff --git gcc/fortran/openmp.cc gcc/fortran/openmp.cc
index 93b31f11173..e559a2db0db 100644
--- gcc/fortran/openmp.cc
+++ gcc/fortran/openmp.cc
@@ -836,7 +836,6 @@ cleanup:
static int
match_oacc_device_type_kind (void)
{
-
char name[GFC_MAX_SYMBOL_LEN + 1];
/* Since device_type arg accept * as all,
@@ -3226,16 +3225,11 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
OMP_MAP_FORCE_DEVICEPTR, false,
allow_derived))
continue;
-
if ((mask & OMP_CLAUSE_DEVICE_TYPE) && openacc
&& gfc_match_dupl_check (!c->oacc_device_type_present,
- "device_type", true)
- == MATCH_YES
+ "device_type", true) == MATCH_YES
&& match_oacc_device_type (c) == MATCH_YES)
- {
- continue;
- }
-
+ continue;
if ((mask & OMP_CLAUSE_DEVICE_TYPE) && !openacc
&& gfc_match_dupl_check (c->device_type == OMP_DEVICE_TYPE_UNSET,
"device_type", true) == MATCH_YES)
@@ -3256,8 +3250,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
continue;
}
if ((mask & OMP_CLAUSE_DEVICE_NUM)
- && (m = gfc_match_dupl_check (!c->device_num_expr, "device_num"))
- != MATCH_NO)
+ && (m = gfc_match_dupl_check (!c->device_num_expr,
+ "device_num")) != MATCH_NO)
{
if (m == MATCH_ERROR)
goto error;
@@ -5097,16 +5091,14 @@ error:
(omp_mask (OMP_CLAUSE_GANG) | OMP_CLAUSE_WORKER | OMP_CLAUSE_VECTOR \
| OMP_CLAUSE_SEQ \
| OMP_CLAUSE_NOHOST)
-
#define OACC_INIT_CLAUSES \
(omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICE_NUM | OMP_CLAUSE_DEVICE_TYPE)
-
#define OACC_SHUTDOWN_CLAUSES \
(omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICE_NUM | OMP_CLAUSE_DEVICE_TYPE)
-
#define OACC_SET_CLAUSES \
(omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICE_NUM | OMP_CLAUSE_DEVICE_TYPE)
+
static match
match_acc (gfc_exec_op op, const omp_mask mask)
{
@@ -11502,15 +11494,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
if (omp_clauses->async)
if (omp_clauses->async_expr)
resolve_scalar_int_expr (omp_clauses->async_expr, "ASYNC");
-
if (omp_clauses->device_num_expr)
resolve_scalar_int_expr (omp_clauses->device_num_expr, "DEVICE_NUM");
-
- if (!omp_clauses->device_num_expr && !omp_clauses->oacc_device_type_present
- && code->op == EXEC_OACC_SET)
+ if (code && code->op == EXEC_OACC_SET
+ && !omp_clauses->device_num_expr
+ && !omp_clauses->oacc_device_type_present)
gfc_error ("At least one of the clauses %<DEVICE_TYPE%> and %<DEVICE_NUM%> "
"should be present in %<SET%> directive at %L", &code->loc);
-
if (omp_clauses->num_gangs_expr)
resolve_positive_int_expr (omp_clauses->num_gangs_expr, "NUM_GANGS");
if (omp_clauses->num_workers_expr)
@@ -14103,8 +14093,8 @@ gfc_resolve_oacc_directive (gfc_code *code, gfc_namespace *ns ATTRIBUTE_UNUSED)
case EXEC_OACC_WAIT:
case EXEC_OACC_CACHE:
case EXEC_OACC_INIT:
- case EXEC_OACC_SET:
case EXEC_OACC_SHUTDOWN:
+ case EXEC_OACC_SET:
resolve_omp_clauses (code, code->ext.omp_clauses, NULL, true);
break;
case EXEC_OACC_PARALLEL_LOOP:
diff --git gcc/fortran/parse.cc gcc/fortran/parse.cc
index 958099dcdee..eeb98865513 100644
--- gcc/fortran/parse.cc
+++ gcc/fortran/parse.cc
@@ -1981,7 +1981,7 @@ next_statement (void)
case ST_EVENT_POST: case ST_EVENT_WAIT: case ST_FAIL_IMAGE: \
case ST_OACC_UPDATE: case ST_OACC_WAIT: case ST_OACC_CACHE: \
case ST_OACC_ENTER_DATA: case ST_OACC_EXIT_DATA: \
- case ST_OACC_SHUTDOWN: case ST_OACC_SET: case ST_OACC_INIT
+ case ST_OACC_INIT: case ST_OACC_SHUTDOWN: case ST_OACC_SET
/* Statements that mark other executable statements. */
diff --git gcc/fortran/trans-openmp.cc gcc/fortran/trans-openmp.cc
index a1a1f1103f5..e0af09c9401 100644
--- gcc/fortran/trans-openmp.cc
+++ gcc/fortran/trans-openmp.cc
@@ -6537,7 +6537,7 @@ builtin_oacc_exec_directive:
builtin_code = BUILT_IN_GOACC_SHUTDOWN;
break;
case EXEC_OACC_SET:
- builtin_code = BUILT_IN_GOACC_SET_DEVICE_TYPE_DEVICE_NUM;
+ builtin_code = BUILT_IN_GOACC_SET_DEVICE;
break;
default:
gcc_unreachable ();
@@ -6548,7 +6548,7 @@ builtin_oacc_exec_directive:
gfc_start_block (&block);
- tree n_device = NULL;
+ tree n_device;
if (clauses->device_num_expr)
n_device = gfc_convert_expr_to_tree (&block, clauses->device_num_expr);
else
@@ -6567,7 +6567,6 @@ builtin_oacc_exec_directive:
int device_type = code->op == EXEC_OACC_SET ?
GOMP_DEVICE_DEFAULT :
GOMP_DEVICE_NONE;
-
if (clauses->oacc_device_type_present)
device_type = clauses->oacc_device_type;
@@ -6585,7 +6584,6 @@ builtin_oacc_exec_directive:
gfc_add_expr_to_block (&block, stmt);
return gfc_finish_block (&block);
-
}
static tree
diff --git gcc/omp-builtins.def gcc/omp-builtins.def
index 84b3c84db3f..500cc32ab4d 100644
--- gcc/omp-builtins.def
+++ gcc/omp-builtins.def
@@ -49,20 +49,15 @@ DEF_GOACC_BUILTIN (BUILT_IN_GOACC_UPDATE, "GOACC_update",
DEF_GOACC_BUILTIN (BUILT_IN_GOACC_WAIT, "GOACC_wait",
BT_FN_VOID_INT_INT_VAR,
ATTR_NOTHROW_LIST)
-
+DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DECLARE, "GOACC_declare",
+ BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
DEF_GOACC_BUILTIN (BUILT_IN_GOACC_INIT, "GOACC_init",
BT_FN_VOID_INT_INT, ATTR_NOTHROW_LIST)
-
DEF_GOACC_BUILTIN (BUILT_IN_GOACC_SHUTDOWN, "GOACC_shutdown",
BT_FN_VOID_INT_INT, ATTR_NOTHROW_LIST)
-
-DEF_GOACC_BUILTIN (BUILT_IN_GOACC_SET_DEVICE_TYPE_DEVICE_NUM,
- "GOACC_set_device_type_device_num",
+DEF_GOACC_BUILTIN (BUILT_IN_GOACC_SET_DEVICE, "GOACC_set_device",
BT_FN_VOID_INT_INT, ATTR_NOTHROW_LIST)
-DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DECLARE, "GOACC_declare",
- BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
-
DEF_GOACC_BUILTIN_COMPILER (BUILT_IN_ACC_ON_DEVICE, "acc_on_device",
BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
diff --git gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90 gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90
index 7ef5c6615f0..013c301c775 100644
--- gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90
+++ gcc/testsuite/gfortran.dg/goacc/acc-set-1.f90
@@ -29,8 +29,8 @@ subroutine set4(l)
!$acc set if(l) device_type(radeon) device_num(1)
end subroutine set4
-! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device_type_device_num \\(-1, 2\\)" 1 "original" } }
-! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device_type_device_num \\(-1, 5\\)" 1 "original" } }
-! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device_type_device_num \\(0, 1\\)" 1 "original" } }
-! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device_type_device_num \\(0, 2\\)" 1 "original" } }
-! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device_type_device_num \\(1, 8\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(-1, 2\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(-1, 5\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(0, 1\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(0, 2\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOACC_set_device \\(1, 8\\)" 1 "original" } }
diff --git libgomp/libgomp.map libgomp/libgomp.map
index 5b3a9e3ca7a..00e47d65d4c 100644
--- libgomp/libgomp.map
+++ libgomp/libgomp.map
@@ -692,10 +692,10 @@ GOACC_2.0.2 {
} GOACC_2.0.1;
GOACC_2.5 {
- global:
- GOACC_init;
- GOACC_shutdown;
- GOACC_set_device_type_device_num;
+ global:
+ GOACC_init;
+ GOACC_shutdown;
+ GOACC_set_device;
} GOACC_2.0.2;
GOMP_PLUGIN_1.0 {
diff --git libgomp/libgomp_g.h libgomp/libgomp_g.h
index 5d7286b2558..9caf9c3571b 100644
--- libgomp/libgomp_g.h
+++ libgomp/libgomp_g.h
@@ -417,7 +417,7 @@ extern void GOACC_wait (int, int, ...);
extern void GOACC_init (int, int);
extern void GOACC_shutdown (int, int);
-extern void GOACC_set_device_type_device_num (int, int);
+extern void GOACC_set_device (int, int);
/* oacc-mem.c */
diff --git libgomp/oacc-init.c libgomp/oacc-init.c
index fde02a8e441..b9e6d405b0b 100644
--- libgomp/oacc-init.c
+++ libgomp/oacc-init.c
@@ -586,6 +586,7 @@ goacc_attach_host_thread_to_device (int ord)
thr->target_tls
= acc_dev->openacc.create_thread_data_func (ord);
}
+
void
GOACC_init (int n_device, int d)
{
@@ -608,7 +609,7 @@ GOACC_init (int n_device, int d)
struct gomp_device_descr *dev
= resolve_device ((acc_device_t) i, false);
- if (!dev || dev->get_num_devices_func (0) <= 0)
+ if (!dev || dev->get_num_devices_func () <= 0)
{
gomp_debug (0,
"init directive: Device type %s isn't available or "
@@ -661,7 +662,7 @@ GOACC_shutdown (int n_device, int d)
struct gomp_device_descr *dev
= resolve_device ((acc_device_t) i, false);
- if (!dev || dev->get_num_devices_func (0) <= 0)
+ if (!dev || dev->get_num_devices_func () <= 0)
{
gomp_mutex_unlock (&acc_device_lock);
continue;
@@ -683,7 +684,7 @@ GOACC_shutdown (int n_device, int d)
}
void
-GOACC_set_device_type_device_num (int n_device, int d)
+GOACC_set_device (int n_device, int d)
{
acc_set_device_type ((acc_device_t) d);
acc_set_device_num (n_device, (acc_device_t) d);
--=-=-=--