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.

Changes since v1:

- Addressed comments from Thomas Schwinge
- Addressed the note from Thomas Koenig :^)

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_TYPE_DEVICE_NUM): 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_type_device_num.
        * libgomp_g.h (GOACC_init): Declare.
        (GOACC_shutdown): Likewise.
        (GOACC_set_device_type_device_num): 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_type_device_num): 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]>
---
 gcc/builtin-types.def                         |   2 +
 gcc/fortran/dump-parse-tree.cc                |  31 +++
 gcc/fortran/frontend-passes.cc                |  11 +
 gcc/fortran/gfortran.h                        |   4 +
 gcc/fortran/match.h                           |   3 +
 gcc/fortran/openmp.cc                         | 139 +++++++++++-
 gcc/fortran/parse.cc                          |  20 +-
 gcc/fortran/resolve.cc                        |   6 +
 gcc/fortran/st.cc                             |   3 +
 gcc/fortran/trans-openmp.cc                   |  78 ++++++-
 gcc/fortran/trans.cc                          |   3 +
 gcc/fortran/types.def                         |   1 +
 gcc/omp-builtins.def                          |  11 +
 .../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                           |   8 +-
 libgomp/oacc-init.c                           | 205 +++++++++++++++---
 .../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, 1130 insertions(+), 36 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-directives.f90
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-4-directives.f90
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/lib-5-directives.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..1c49624d0bf 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -695,6 +695,8 @@ 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)
 
 DEF_FUNCTION_TYPE_3 (BT_FN_STRING_STRING_CONST_STRING_SIZE,
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 3f1b35b715a..9c4ac6274e1 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 = "all"; break;
+       case GOMP_DEVICE_HOST: s = "host"; break;
+       case GOMP_DEVICE_NVIDIA_PTX: s = "nvidia"; break;
+       case GOMP_DEVICE_GCN: s = "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);
+    }
 }
 
 /* Show a single OpenMP or OpenACC directive node and everything underneath it
@@ -2523,6 +2545,9 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OACC_CACHE: name = "CACHE"; is_oacc = true; break;
     case EXEC_OACC_ENTER_DATA: name = "ENTER DATA"; is_oacc = true; break;
     case EXEC_OACC_EXIT_DATA: name = "EXIT DATA"; is_oacc = true; break;
+    case EXEC_OACC_INIT: name = "INIT"; is_oacc = true; break;
+    case EXEC_OACC_SHUTDOWN: name = "SHUTDOWN"; is_oacc = true; break;
+    case EXEC_OACC_SET: name = "SET"; is_oacc = true; break;
     case EXEC_OMP_ALLOCATE: name = "ALLOCATE"; break;
     case EXEC_OMP_ALLOCATORS: name = "ALLOCATORS"; break;
     case EXEC_OMP_ASSUME: name = "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 fd34f0c1912..3afccc39f29 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -5737,6 +5737,17 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, 
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_ROUTINE,
   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_ORDERED,
   ST_OMP_END_PARALLEL, ST_OMP_END_PARALLEL_DO, ST_OMP_END_PARALLEL_SECTIONS,
@@ -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 = 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 d151aff8a45..fc404994a15 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 = OMP_LIST_FIRST; t < OMP_LIST_NUM;
        t = gfc_omp_list_type (t + 1))
     gfc_free_omp_namelist (c->lists[t], t);
@@ -832,6 +833,74 @@ cleanup:
   return MATCH_ERROR;
 }
 
+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] = (char) gfc_next_char ();
+
+  if (name[0] == '*')
+    return GOMP_DEVICE_NONE;
+
+  /* If is not *, we try to match the
+     pre-defined names.  */
+
+  match m = gfc_match (" %n ", name + 1);
+
+  if (m != MATCH_YES)
+    return -1;
+
+  if (strcmp (name ,"host") == 0)
+    return GOMP_DEVICE_HOST;
+  if (strcmp (name, "nvidia") == 0)
+    return GOMP_DEVICE_NVIDIA_PTX;
+  if (strcmp (name, "radeon") == 0)
+    return GOMP_DEVICE_GCN;
+
+  return -1;
+}
+
+static match
+match_oacc_device_type (gfc_omp_clauses *c)
+{
+  locus old_loc = gfc_current_locus;
+
+  int result = match_oacc_device_type_kind ();
+  match m;
+
+  if (result == -1)
+    goto syntax;
+
+  m = gfc_match_char (')', true);
+
+  if (m != MATCH_YES)
+    goto single_argument;
+
+  c->oacc_device_type = (unsigned) result;
+  c->oacc_device_type_present = 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.  
Expected "
+            "host, radeon, nvidia or * as argument.");
+
+cleanup:
+  gfc_current_locus = 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 +1251,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 +3226,17 @@ 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)
+                  == MATCH_YES
+             && match_oacc_device_type (c) == MATCH_YES)
+           {
+             continue;
+           }
+
+         if ((mask & OMP_CLAUSE_DEVICE_TYPE) && !openacc
              && gfc_match_dupl_check (c->device_type == OMP_DEVICE_TYPE_UNSET,
                                       "device_type", true) == MATCH_YES)
            {
@@ -3175,6 +3255,16 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const 
omp_mask mask,
                break;
              continue;
            }
+         if ((mask & OMP_CLAUSE_DEVICE_NUM)
+             && (m = gfc_match_dupl_check (!c->device_num_expr, "device_num"))
+                  != MATCH_NO)
+           {
+             if (m == MATCH_ERROR)
+               goto error;
+             if (gfc_match ("( %e )", &c->device_num_expr) != MATCH_YES)
+               goto error;
+             continue;
+           }
          if ((mask & OMP_CLAUSE_DEVICE_RESIDENT)
              && gfc_match_omp_variable_list
                   ("device_resident (",
@@ -3246,6 +3336,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const 
omp_mask mask,
                }
              continue;
            }
+
          if ((mask & OMP_CLAUSE_DIST_SCHEDULE)
              && c->dist_sched_kind == OMP_SCHED_NONE
              && gfc_match ("dist_schedule ( static") == MATCH_YES)
@@ -3279,6 +3370,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const 
omp_mask mask,
                goto error;
              continue;
            }
+
+
          break;
        case 'e':
          if ((mask & OMP_CLAUSE_ENTER))
@@ -5008,6 +5101,14 @@ error:
    | 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)
@@ -5301,6 +5402,24 @@ gfc_match_oacc_cache (void)
   return MATCH_YES;
 }
 
+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.  */
 
 static oacc_routine_lop
@@ -11383,6 +11502,15 @@ 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)
+    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)
@@ -13635,6 +13763,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 ();
     }
@@ -13968,6 +14102,9 @@ gfc_resolve_oacc_directive (gfc_code *code, 
gfc_namespace *ns ATTRIBUTE_UNUSED)
     case EXEC_OACC_EXIT_DATA:
     case EXEC_OACC_WAIT:
     case EXEC_OACC_CACHE:
+    case EXEC_OACC_INIT:
+    case EXEC_OACC_SET:
+    case EXEC_OACC_SHUTDOWN:
       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..958099dcdee 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_SHUTDOWN: case ST_OACC_SET: case ST_OACC_INIT
 
 /* Statements that mark other executable statements.  */
 
@@ -2692,6 +2698,15 @@ gfc_ascii_statement (gfc_statement st, bool 
strip_sentinel)
     case ST_OACC_END_ATOMIC:
       p = "!$ACC END ATOMIC";
       break;
+    case ST_OACC_INIT:
+      p = "!ACC INIT";
+      break;
+    case ST_OACC_SHUTDOWN:
+      p = "!ACC SHUTDOWN";
+      break;
+    case ST_OACC_SET:
+      p = "!ACC SET";
+      break;
     case ST_OMP_ALLOCATE:
     case ST_OMP_ALLOCATE_EXEC:
       p = "!$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;
 
     default:
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 6dc1b8e315d..86d28cf7375 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -13041,6 +13041,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns)
        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:
@@ -14827,6 +14830,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;
 
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 52b1554ac33..49e08987361 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "options.h"
+#include "tree-core.h"
 #include "tree.h"
 #include "gfortran.h"
 #include "basic-block.h"
@@ -6421,6 +6422,10 @@ gfc_trans_omp_clauses (stmtblock_t *block, 
gfc_omp_clauses *clauses,
   /* OpenACC 'nohost' clauses cannot appear here.  */
   gcc_checking_assert (!clauses->nohost);
 
+  /* 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);
 }
 
@@ -6491,7 +6496,7 @@ gfc_trans_oacc_construct (gfc_code *code)
   return gfc_finish_block (&block);
 }
 
-/* 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)
 {
@@ -6513,6 +6518,10 @@ gfc_trans_oacc_executable_directive (gfc_code *code)
       case EXEC_OACC_CACHE:
        construct_code = OACC_CACHE;
        break;
+      case EXEC_OACC_INIT:
+      case EXEC_OACC_SHUTDOWN:
+      case EXEC_OACC_SET:
+       goto builtin_oacc_exec_directive;
       default:
        gcc_unreachable ();
     }
@@ -6524,6 +6533,69 @@ gfc_trans_oacc_executable_directive (gfc_code *code)
                     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 = BUILT_IN_GOACC_INIT;
+      break;
+    case EXEC_OACC_SHUTDOWN:
+      builtin_code = BUILT_IN_GOACC_SHUTDOWN;
+      break;
+    case EXEC_OACC_SET:
+      builtin_code = BUILT_IN_GOACC_SET_DEVICE_TYPE_DEVICE_NUM;
+      break;
+    default:
+      gcc_unreachable ();
+  }
+
+  location_t loc = input_location;
+  gfc_omp_clauses *clauses = code->ext.omp_clauses;
+
+  gfc_start_block (&block);
+
+  tree n_device = NULL;
+  if (clauses->device_num_expr)
+    n_device = gfc_convert_expr_to_tree (&block, clauses->device_num_expr);
+  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 = 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 = code->op == EXEC_OACC_SET ?
+                   GOMP_DEVICE_DEFAULT       :
+                   GOMP_DEVICE_NONE;
+
+  if (clauses->oacc_device_type_present)
+    device_type = clauses->oacc_device_type;
+
+  tree d_type = build_int_cst (integer_type_node, device_type);
+
+  stmt = builtin_decl_explicit (builtin_code);
+
+  stmt = build_call_expr_loc (loc, stmt, 2, n_device, d_type);
+
+  if (clauses->if_expr)
+    stmt = 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);
+
 }
 
 static tree
@@ -9867,6 +9939,7 @@ gfc_trans_oacc_declare (gfc_code *code)
   return gfc_finish_block (&block);
 }
 
+
 tree
 gfc_trans_oacc_directive (gfc_code *code)
 {
@@ -9889,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 = gfc_trans_oacc_directive (code);
          break;
 
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_VOID, 
BT_CONST_PTR, BT_SIZE)
 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 a/gcc/omp-builtins.def b/gcc/omp-builtins.def
index 8e6b6fb3acf..84b3c84db3f 100644
--- a/gcc/omp-builtins.def
+++ b/gcc/omp-builtins.def
@@ -49,6 +49,17 @@ 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_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",
+                  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)
 
diff --git a/gcc/testsuite/gfortran.dg/goacc/acc-init-1.f90 
b/gcc/testsuite/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, radeon, 
nvidia or \\\* as argument" }
+end subroutine bad1
+
+subroutine bad2
+  implicit none
+  !$acc init device_type(nvidia, host) ! { dg-error "OpenACC 'DEVICE_TYPE' 
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/testsuite/gfortran.dg/goacc/acc-set-1.f90
new file mode 100644
index 00000000000..7ef5c6615f0
--- /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_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" } }
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, radeon, 
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 "Duplicated 
'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/testsuite/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 
"Duplicated 'device_type' clause" }
+end subroutine bad6
+
+subroutine bad7
+  implicit none
+  !$acc shutdown device_num(0) device_num(1) ! { dg-error "Duplicated 
'device_num' clause" }
+end subroutine bad7
+
+subroutine bad8
+  implicit none
+  !$acc shutdown if(.false.) if(.true.) ! { dg-error "Duplicated 'if' clause" }
+end subroutine bad8
diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95 
b/gcc/testsuite/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 @@
 
 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
 
   !$acc parallel if(b) ! { dg-warning "is used uninitialized" }
@@ -25,4 +26,6 @@ program test
 
   !$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized" }
 
+  !$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/gcc/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
 
   !$acc declare link(a) if_present ! { dg-error "Unexpected junk after" }
 
-  !$acc init if_present ! { dg-error "Unclassifiable OpenACC directive" }
-  !$acc shutdown if_present ! { dg-error "Unclassifiable OpenACC directive" }
+  !$acc init if_present ! { dg-error "Failed to match clause" }
+  !$acc shutdown if_present ! { dg-error "Failed to match clause" }
   
   !$acc update self(a) device_type(nvidia) device(b) if_present ! { dg-error 
"Failed to match clause" }
 end subroutine t1
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index 8a59d4965b3..5b3a9e3ca7a 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -691,6 +691,13 @@ GOACC_2.0.2 {
        GOACC_exit_data;
 } GOACC_2.0.1;
 
+GOACC_2.5 {
+    global:
+        GOACC_init;
+        GOACC_shutdown;
+        GOACC_set_device_type_device_num;
+} 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..cb2d607aef6 100644
--- a/libgomp/libgomp_g.h
+++ b/libgomp/libgomp_g.h
@@ -26,7 +26,7 @@
 /* This file contains prototypes of functions in the external ABI.
    This file is included by files in the testsuite.  */
 
-#ifndef LIBGOMP_G_H 
+#ifndef LIBGOMP_G_H
 #define LIBGOMP_G_H 1
 
 #include <stdbool.h>
@@ -413,6 +413,12 @@ extern void GOMP_error (const char *, size_t);
 
 extern void GOACC_wait (int, int, ...);
 
+/* oacc-init.c */
+
+extern void GOACC_init (int, int);
+extern void GOACC_shutdown (int, int);
+extern void GOACC_set_device_type_device_num (int, int);
+
 /* oacc-mem.c */
 
 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 70bf10c84d9..5cbe02ba41f 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] = { 0 };
 
+/* 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, int 
ndevs)
    held before calling this function.  */
 
 static struct gomp_device_descr *
-acc_init_1 (acc_device_t d, acc_construct_t parent_construct, int implicit)
+acc_init_1 (acc_device_t d, acc_construct_t parent_construct, int implicit,
+           int dev_num)
 {
   gomp_mutex_lock (&acc_init_state_lock);
   acc_init_state = initializing;
@@ -304,10 +309,12 @@ acc_init_1 (acc_device_t d, acc_construct_t 
parent_construct, int implicit)
 
   ndevs = base_dev->get_num_devices_func (0);
 
-  if (ndevs <= 0 || goacc_device_num >= ndevs)
-    acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
+  dev_num = (dev_num == -1 ? goacc_device_num : dev_num);
 
-  acc_dev = &base_dev[goacc_device_num];
+  if (ndevs <= 0 || dev_num >= ndevs)
+    acc_dev_num_out_of_range (d, dev_num, ndevs);
+
+  acc_dev = &base_dev[dev_num];
 
   gomp_mutex_lock (&acc_dev->lock);
   if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
@@ -341,7 +348,7 @@ acc_init_1 (acc_device_t d, acc_construct_t 
parent_construct, int implicit)
 /* ACC_DEVICE_LOCK must be held before calling this function.  */
 
 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)
 
   ndevs = base_dev->get_num_devices_func (0);
 
-  /* Unload all the devices of this type that have been opened.  */
-  for (i = 0; i < ndevs; i++)
-    {
-      struct gomp_device_descr *acc_dev = &base_dev[i];
+  if (dev_num != -1 && ndevs <= dev_num)
+    acc_dev_num_out_of_range (d, dev_num, ndevs);
 
+  if (dev_num != -1)
+    {
+      struct gomp_device_descr *acc_dev = &base_dev[dev_num];
       gomp_mutex_lock (&acc_dev->lock);
       gomp_unload_device (acc_dev);
       gomp_mutex_unlock (&acc_dev->lock);
     }
-  
+  else
+    {
+      /* Unload all the devices of this type that have been opened.  */
+      for (i = 0; i < ndevs; i++)
+       {
+         struct gomp_device_descr *acc_dev = &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);
 
-  /* Free target-specific TLS data and close all devices.  */
+  /* Free target-specific TLS data and close devices.  */
   for (walk = goacc_threads; walk != NULL; walk = walk->next)
     {
+      /* These checks are necessary since init supports
+       * multiples devices.  */
+      if (walk->base_dev != base_dev)
+       continue;
+
+      if (dev_num != -1 && walk->dev != &base_dev[dev_num])
+       continue;
+
       if (walk->target_tls)
        base_dev->openacc.destroy_thread_data_func (walk->target_tls);
 
@@ -409,20 +437,38 @@ acc_shutdown_1 (acc_device_t d)
 
   gomp_mutex_unlock (&goacc_thread_lock);
 
-  /* Close all the devices of this type that have been opened.  */
   bool ret = true;
-  for (i = 0; i < ndevs; i++)
+
+  if (dev_num != -1)
     {
-      struct gomp_device_descr *acc_dev = &base_dev[i];
+      struct gomp_device_descr *acc_dev = &base_dev[dev_num];
       gomp_mutex_lock (&acc_dev->lock);
+
       if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
-        {
+       {
          devices_active = true;
          ret &= gomp_fini_device (acc_dev);
          acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
        }
+
       gomp_mutex_unlock (&acc_dev->lock);
     }
+  else
+    {
+      /* Close all the devices of this type that have been opened.  */
+      for (i = 0; i < ndevs; i++)
+       {
+         struct gomp_device_descr *acc_dev = &base_dev[i];
+         gomp_mutex_lock (&acc_dev->lock);
+         if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
+           {
+             devices_active = true;
+             ret &= gomp_fini_device (acc_dev);
+             acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
+           }
+         gomp_mutex_unlock (&acc_dev->lock);
+       }
+    }
 
   if (!ret)
     gomp_fatal ("device finalization failed");
@@ -502,13 +548,13 @@ goacc_attach_host_thread_to_device (int ord)
   struct goacc_thread *thr = goacc_thread ();
   struct gomp_device_descr *acc_dev = NULL, *base_dev = NULL;
   int num_devices;
-  
+
   if (thr && thr->dev && (thr->dev->target_id == ord || ord < 0))
     return;
-  
+
   if (ord < 0)
     ord = goacc_device_num;
-  
+
   /* Decide which type of device to use.  If the current thread has a device
      type already (e.g. set by acc_set_device_type), use that, else use the
      global default.  */
@@ -519,15 +565,15 @@ goacc_attach_host_thread_to_device (int ord)
       assert (cached_base_dev);
       base_dev = cached_base_dev;
     }
-  
+
   num_devices = base_dev->get_num_devices_func (0);
   if (num_devices <= 0 || ord >= num_devices)
     acc_dev_num_out_of_range (acc_device_type (base_dev->type), ord,
                              num_devices);
-  
+
   if (!thr)
     thr = goacc_new_thread ();
-  
+
   thr->base_dev = base_dev;
   thr->dev = acc_dev = &base_dev[ord];
   thr->saved_bound_dev = NULL;
@@ -540,10 +586,111 @@ 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)
+{
+  /* 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 == acc_device_none)
+    {
+      int i;
+      for (i = 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
+           = resolve_device ((acc_device_t) i, false);
+         if (!dev || dev->get_num_devices_func (0) <= 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
+           = 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
+       = 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 == acc_device_none)
+    {
+      int i;
+      for (i = 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
+           = resolve_device ((acc_device_t) i, false);
+
+         if (!dev || dev->get_num_devices_func (0) <= 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_type_device_num (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 serialization of
    init/shutdown is per-process or per-thread.  We choose per-process.  */
-
 void
 acc_init (acc_device_t d)
 {
@@ -553,9 +700,9 @@ acc_init (acc_device_t d)
   gomp_init_targets_once ();
 
   gomp_mutex_lock (&acc_device_lock);
-  cached_base_dev = acc_init_1 (d, acc_construct_runtime_api, 0);
+  cached_base_dev = acc_init_1 (d, acc_construct_runtime_api, 0, -1);
   gomp_mutex_unlock (&acc_device_lock);
-  
+
   goacc_attach_host_thread_to_device (-1);
 }
 
@@ -569,7 +716,7 @@ acc_shutdown (acc_device_t d)
 
   gomp_mutex_lock (&acc_device_lock);
 
-  acc_shutdown_1 (d);
+  acc_shutdown_1 (d, -1);
 
   gomp_mutex_unlock (&acc_device_lock);
 }
@@ -783,7 +930,7 @@ acc_set_device_num (int ord, acc_device_t d)
 
       goacc_attach_host_thread_to_device (ord);
     }
-  
+
   goacc_device_num = ord;
 }
 
@@ -911,7 +1058,7 @@ goacc_restore_bind (void)
 }
 
 /* This is called from any OpenACC support function that may need to implicitly
-   initialize the libgomp runtime, either globally or from a new host thread. 
+   initialize the libgomp runtime, either globally or from a new host thread.
    On exit "goacc_thread" will return a valid & populated thread block.  */
 
 attribute_hidden void
@@ -926,8 +1073,8 @@ goacc_lazy_initialize (void)
 
   gomp_mutex_lock (&acc_device_lock);
   if (!cached_base_dev)
-    cached_base_dev = acc_init_1 (acc_device_default,
-                                 acc_construct_parallel, 1);
+    cached_base_dev
+      = acc_init_1 (acc_device_default, acc_construct_parallel, 1, -1);
   gomp_mutex_unlock (&acc_device_lock);
 
   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 = .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 = 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 = .true.
+  !$acc init if (l) device_type(nvidia)
+  l = .false.
+  !$acc init if (l) device_type(host) 
+  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 = .true.
+  !$acc init if (l) device_type(radeon)
+  l = .false.
+  !$acc init if (l) device_type(host) 
+  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 = 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 = 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 = 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 = 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 = 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/libgomp/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 = 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 = 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 = 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 = 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/testsuite/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 = .true.
+!$acc set if (l) device_type(host)
+
+if (acc_get_device_type () .ne. acc_device_host) stop 6
+
+l = .false.
+n = 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 = 0
+  !$acc set device_type(nvidia) device_num(n)
+
+  if (acc_get_device_num (acc_device_nvidia) .ne. 0) stop 12
+
+  l = .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 = 0
+  !$acc set device_type(radeon) device_num(n)
+
+  if (acc_get_device_num (acc_device_radeon) .ne. 0) stop 22
+
+  l = .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/libgomp/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 = .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 = 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 = .true.
+  !$acc init if (l) device_type(nvidia)
+  if (acc_get_device_type () .ne. acc_device_nvidia) stop 5
+  l = .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 = .true.
+  !$acc init if (l) device_type(radeon)
+  if (acc_get_device_type () .ne. acc_device_radeon) stop 6
+  l = .false.
+  !$acc shutdown if (l) device_type(host)
+  !$acc shutdown device_type(radeon)
+end if
+
+end
-- 
2.54.0

Reply via email to