]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
OpenMP 5.0: requires directive
authorChung-Lin Tang <cltang@codesourcery.com>
Tue, 2 Feb 2021 12:34:01 +0000 (20:34 +0800)
committerChung-Lin Tang <cltang@codesourcery.com>
Tue, 2 Feb 2021 12:34:01 +0000 (20:34 +0800)
This is a merge of:
https://gcc.gnu.org/pipermail/gcc-patches/2021-January/563393.html

This patch completes more of the reverse_offload, unified_address, and
unified_shared_memory clauses for the OpenMP 5.0 requires directive,
including runtime verification of the offload target.
(currently no offload devices actually support above features, only
warning messages are emitted)

This may possibly reverted/updated when a final patch is approved
for mainline.

2021-02-02  Chung-Lin Tang  <cltang@codesourcery.com>

gcc/c/ChangeLog:

* c-parser.c (c_parser_declaration_or_fndef): Set
OMP_REQUIRES_TARGET_USED in omp_requires_mask if function has
"omp declare target" attribute.
(c_parser_omp_target_data): Set    OMP_REQUIRES_TARGET_USED in
omp_requires_mask.
(c_parser_omp_target_enter_data): Likewise.
(c_parser_omp_target_exit_data): Likewise.
(c_parser_omp_requires): Adjust to only mention "not implemented yet"
for OMP_REQUIRES_DYNAMIC_ALLOCATORS.

gcc/cp/ChangeLog:

* parser.c (cp_parser_simple_declaration): Set
OMP_REQUIRES_TARGET_USED in omp_requires_mask if function has
"omp declare target" attribute.
(cp_parser_omp_target_data): Set OMP_REQUIRES_TARGET_USED in
omp_requires_mask.
(cp_parser_omp_target_enter_data): Likewise.
(cp_parser_omp_target_exit_data): Likewise.
(cp_parser_omp_requires): Adjust to only mention "not implemented yet"
for OMP_REQUIRES_DYNAMIC_ALLOCATORS.

gcc/fortran/ChangeLog:

* openmp.c (gfc_check_omp_requires): Fix REVERSE_OFFLOAD typo.
(gfc_match_omp_requires): Adjust to only mention "not implemented yet"
for OMP_REQUIRES_DYNAMIC_ALLOCATORS.
* parse.c ("tree.h"): Add include.
("omp-general.h"): Likewise.
(gfc_parse_file): Add code to merge omp_requires to omp_requires_mask.

gcc/ChangeLog:

* omp-offload.c (omp_finish_file): Add code to reate OpenMP requires
mask variable in .gnu.gomp_requires section if needed.

gcc/testsuite/ChangeLog:

* c-c++-common/gomp/requires-4.c: Remove prune of "not supported yet".
* gcc/testsuite/gfortran.dg/gomp/requires-4.f90: Fix REVERSE_OFFLOAD typo.
* gcc/testsuite/gfortran.dg/gomp/requires-8.f90: Likewise.

include/ChangeLog:

* gomp-constants.h (GOMP_REQUIRES_UNIFIED_ADDRESS): New symbol.
(GOMP_REQUIRES_UNIFIED_SHARED_MEMORY): Likewise.
(GOMP_REQUIRES_REVERSE_OFFLOAD): Likewise.

libgcc/ChangeLog:

* offloadstuff.c (__requires_mask_table): New symbol to mark start of
.gnu.gomp_requires section.
(__requires_mask_table_end): New symbol to mark end of
.gnu.gomp_requires section.

libgomp/ChangeLog:

* libgomp-plugin.h (GOMP_OFFLOAD_supported_features): New declaration.
* libgomp.h (struct gomp_device_descr): New 'supported_features_func'
plugin hook field.
* oacc-host.c (host_supported_features): New host hook function.
(host_dispatch): Initialize 'supported_features_func' host hook.
* plugin/plugin-gcn.c (GOMP_OFFLOAD_supported_features): New function.
* plugin/plugin-nvptx.c (GOMP_OFFLOAD_supported_features): Likewise.
* target.c (<stdio.h>): Add include of standard header.
(gomp_requires_mask): New static variable.
(__requires_mask_table): New declaration.
(__requires_mask_table_end): Likewise.
(gomp_load_plugin_for_device): Add loading of 'supported_features' hook.
(gomp_target_init): Add code to summarize .gnu._gomp_requires section
mask values, emit error if inconsistency found.

* testsuite/libgomp.c-c++-common/requires-1.c: New test.
* testsuite/libgomp.c-c++-common/requires-1-aux.c: New file linked with
above test.
* testsuite/libgomp.c-c++-common/requires-2.c: New test.
* testsuite/libgomp.c-c++-common/requires-2-aux.c: New file linked with
above test.

liboffloadmic/ChangeLog:

* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_supported_features):
New function.

21 files changed:
gcc/c/c-parser.c
gcc/cp/parser.c
gcc/fortran/openmp.c
gcc/fortran/parse.c
gcc/omp-offload.c
gcc/testsuite/c-c++-common/gomp/requires-4.c
gcc/testsuite/gfortran.dg/gomp/requires-4.f90
gcc/testsuite/gfortran.dg/gomp/requires-8.f90
include/gomp-constants.h
libgcc/offloadstuff.c
libgomp/libgomp-plugin.h
libgomp/libgomp.h
libgomp/oacc-host.c
libgomp/plugin/plugin-gcn.c
libgomp/plugin/plugin-nvptx.c
libgomp/target.c
libgomp/testsuite/libgomp.c-c++-common/requires-1-aux.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/requires-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/requires-2-aux.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/requires-2.c [new file with mode: 0644]
liboffloadmic/plugin/libgomp-plugin-intelmic.cpp

index 6b9898a1c7051f581d611574eb9c1d4368861314..cb491d2d0a447ec29d64050d432381987a6e3355 100644 (file)
@@ -2444,6 +2444,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
          break;
        }
 
+      if (flag_openmp
+         && lookup_attribute ("omp declare target",
+                              DECL_ATTRIBUTES (current_function_decl)))
+       omp_requires_mask
+         = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
       if (DECL_DECLARED_INLINE_P (current_function_decl))
         tv = TV_PARSE_INLINE;
       else
@@ -19447,6 +19453,10 @@ c_parser_omp_teams (location_t loc, c_parser *parser,
 static tree
 c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p)
 {
+  if (flag_openmp)
+    omp_requires_mask
+      = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
   tree clauses
     = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
                                "#pragma omp target data");
@@ -19589,6 +19599,10 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser,
       return NULL_TREE;
     }
 
+  if (flag_openmp)
+    omp_requires_mask
+      = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
   tree clauses
     = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK,
                                "#pragma omp target enter data");
@@ -19675,6 +19689,10 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
       return NULL_TREE;
     }
 
+  if (flag_openmp)
+    omp_requires_mask
+      = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
   tree clauses
     = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK,
                                "#pragma omp target exit data");
@@ -21261,7 +21279,7 @@ c_parser_omp_requires (c_parser *parser)
              c_parser_skip_to_pragma_eol (parser, false);
              return;
            }
-         if (p)
+         if (this_req == OMP_REQUIRES_DYNAMIC_ALLOCATORS)
            sorry_at (cloc, "%qs clause on %<requires%> directive not "
                            "supported yet", p);
          if (p)
index 6eb228099bc78340bc24260d1ba5c292dfa22b11..1af233690a262b45ba376b3007797813648a781a 100644 (file)
@@ -13813,6 +13813,11 @@ cp_parser_simple_declaration (cp_parser* parser,
          /* Otherwise, we're done with the list of declarators.  */
          else
            {
+             if (flag_openmp && lookup_attribute ("omp declare target",
+                                                  DECL_ATTRIBUTES (decl)))
+               omp_requires_mask
+                 = (enum omp_requires) (omp_requires_mask
+                                        | OMP_REQUIRES_TARGET_USED);
              pop_deferring_access_checks ();
              return;
            }
@@ -40412,6 +40417,10 @@ cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
 static tree
 cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
 {
+  if (flag_openmp)
+    omp_requires_mask
+      = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
   tree clauses
     = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
                                 "#pragma omp target data", pragma_tok);
@@ -40515,6 +40524,10 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok,
       return NULL_TREE;
     }
 
+  if (flag_openmp)
+    omp_requires_mask
+      = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
   tree clauses
     = cp_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK,
                                 "#pragma omp target enter data", pragma_tok);
@@ -40605,6 +40618,10 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok,
       return NULL_TREE;
     }
 
+  if (flag_openmp)
+    omp_requires_mask
+      = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
   tree clauses
     = cp_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK,
                                 "#pragma omp target exit data", pragma_tok);
@@ -42736,7 +42753,7 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok)
              cp_parser_skip_to_pragma_eol (parser, pragma_tok);
              return false;
            }
-         if (p)
+         if (this_req == OMP_REQUIRES_DYNAMIC_ALLOCATORS)
            sorry_at (cloc, "%qs clause on %<requires%> directive not "
                            "supported yet", p);
          if (p)
index 8dc2871cd41b83ebdf71af389624b19f086aa6f8..61a340d7f3963f625084584de218918da91d3aee 100644 (file)
@@ -3545,7 +3545,7 @@ gfc_check_omp_requires (gfc_namespace *ns, int ref_omp_requires)
       if ((ref_omp_requires & OMP_REQ_REVERSE_OFFLOAD)
          && !(ns->omp_requires & OMP_REQ_REVERSE_OFFLOAD))
        gfc_error ("Program unit at %L has OpenMP device constructs/routines "
-                  "but does not set !$OMP REQUIRES REVERSE_OFFSET but other "
+                  "but does not set !$OMP REQUIRES REVERSE_OFFLOAD but other "
                   "program units do", &ns->proc_name->declared_at);
       if ((ref_omp_requires & OMP_REQ_UNIFIED_ADDRESS)
          && !(ns->omp_requires & OMP_REQ_UNIFIED_ADDRESS))
@@ -3732,7 +3732,8 @@ gfc_match_omp_requires (void)
       else
        goto error;
 
-      if (requires_clause & ~OMP_REQ_ATOMIC_MEM_ORDER_MASK)
+      /* Currently, everything except 'dynamic_allocators' is allowed.  */
+      if (requires_clause == OMP_REQ_DYNAMIC_ALLOCATORS)
        gfc_error_now ("Sorry, %qs clause at %L on REQUIRES directive is not "
                       "yet supported", clause, &old_loc);
       if (!gfc_omp_requires_add_clause (requires_clause, clause, &old_loc, NULL))
index bade7953acd0fbecde58fd05c8dc1cbbc8c4179f..ef3e219a2d48dd91fcd8066f7e15693a40c2233f 100644 (file)
@@ -22,10 +22,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "options.h"
+#include "tree.h"
 #include "gfortran.h"
 #include <setjmp.h>
 #include "match.h"
 #include "parse.h"
+#include "omp-general.h"
 
 /* Current statement label.  Zero means no statement label.  Because new_st
    can get wiped during statement matching, we have to keep it separate.  */
@@ -6568,6 +6570,23 @@ done:
        gfc_current_ns = gfc_current_ns->sibling)
     gfc_check_omp_requires (gfc_current_ns, omp_requires);
 
+  if (omp_requires)
+    {
+      omp_requires_mask = (enum omp_requires) OMP_REQUIRES_TARGET_USED;
+      if (omp_requires & OMP_REQ_REVERSE_OFFLOAD)
+       omp_requires_mask
+         = (enum omp_requires) (omp_requires_mask
+                                | OMP_REQUIRES_REVERSE_OFFLOAD);
+      if (omp_requires & OMP_REQ_UNIFIED_ADDRESS)
+       omp_requires_mask
+         = (enum omp_requires) (omp_requires_mask
+                                | OMP_REQUIRES_UNIFIED_ADDRESS);
+      if (omp_requires & OMP_REQ_UNIFIED_SHARED_MEMORY)
+       omp_requires_mask
+         = (enum omp_requires) (omp_requires_mask
+                                | OMP_REQUIRES_UNIFIED_SHARED_MEMORY);
+    }
+
   /* Do the parse tree dump.  */
   gfc_current_ns = flag_dump_fortran_original ? gfc_global_ns_list : NULL;
 
index bb3bfd130ee4183af71ec2424767c8b257e5c966..e2d99cb261b0c19373999db89eb541573b9996dd 100644 (file)
@@ -418,6 +418,24 @@ omp_finish_file (void)
 
       varpool_node::finalize_decl (vars_decl);
       varpool_node::finalize_decl (funcs_decl);
+
+      if (flag_openmp && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0)
+       {
+         const char *requires_section = ".gnu.gomp_requires";
+         tree maskvar = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                                    get_identifier (".gomp_requires_mask"),
+                                    unsigned_type_node);
+         SET_DECL_ALIGN (maskvar, TYPE_ALIGN (unsigned_type_node));
+         TREE_STATIC (maskvar) = 1;
+         DECL_INITIAL (maskvar)
+           = build_int_cst (unsigned_type_node,
+                            ((unsigned int) omp_requires_mask
+                             & (OMP_REQUIRES_UNIFIED_ADDRESS
+                                | OMP_REQUIRES_UNIFIED_SHARED_MEMORY
+                                | OMP_REQUIRES_REVERSE_OFFLOAD)));
+         set_decl_section_name (maskvar, requires_section);
+         varpool_node::finalize_decl (maskvar);
+       }
     }
   else
     {
index 88ba7746cf81698c3aeb3f9ed877448fd5ca43e0..8f45d83ea6e30c2d564ec14d6fd5f463575e1a51 100644 (file)
@@ -9,5 +9,3 @@ foo (void)
 #pragma omp requires unified_shared_memory     /* { dg-error "'unified_shared_memory' clause used lexically after first target construct or offloading API" } */
 #pragma omp requires unified_address   /* { dg-error "'unified_address' clause used lexically after first target construct or offloading API" } */
 #pragma omp requires reverse_offload   /* { dg-error "'reverse_offload' clause used lexically after first target construct or offloading API" } */
-
-/* { dg-prune-output "not supported yet" } */
index e0eb4dbc603df1eef6f10ef3c23838e2d216f562..cc4bc3e70400cb6450474e1b44e1b4cc100250ba 100644 (file)
@@ -9,7 +9,7 @@ end module m
 subroutine foo
   !$omp target
   !$omp end target
-! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFSET but other program units do" "" { target *-*-* } 9 }
+! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFLOAD but other program units do" "" { target *-*-* } 9 }
 ! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES UNIFIED_ADDRESS but other program units do" "" { target *-*-* } 9 }
 ! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES UNIFIED_SHARED_MEMORY but other program units do" "" { target *-*-* } 9 }
 end
index 3c32ae9860e57cb320d1967e8747edf374a77f0e..3819b0c28cc279e1c628eb03b8e4f67ba5023b8b 100644 (file)
@@ -13,7 +13,7 @@ contains
  end subroutine foo
 end module m
 
-subroutine bar  ! { dg-error "has OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFSET but other program units do" }
+subroutine bar  ! { dg-error "has OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFLOAD but other program units do" }
   !use m
   !$omp requires unified_shared_memory
   !$omp declare target
index d3d4514c84b95a81be0be7671a99a45e4f4deb6a..b8efb30b1e1600a083558206bf70f567c8b88cb0 100644 (file)
@@ -344,6 +344,12 @@ enum gomp_map_kind
 #define GOMP_DEPEND_INOUT              3
 #define GOMP_DEPEND_MUTEXINOUTSET      4
 
+/* Flag values for requires-directive features, must match corresponding
+   OMP_REQUIRES_* values in gcc/omp-general.h.  */
+#define GOMP_REQUIRES_UNIFIED_ADDRESS       0x10
+#define GOMP_REQUIRES_UNIFIED_SHARED_MEMORY 0x20
+#define GOMP_REQUIRES_REVERSE_OFFLOAD       0x80
+
 /* HSA specific data structures.  */
 
 /* Identifiers of device-specific target arguments.  */
index 0bbe1c240e2dbd97dda1061bc4d2bdc76853ce5c..6caaaa0965628291570c0f9b09eaf44cc31f3794 100644 (file)
@@ -54,6 +54,9 @@ const void *const __offload_var_table[0]
   __attribute__ ((__used__, visibility ("hidden"),
                  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
 
+const unsigned int const __requires_mask_table[0]
+  __attribute__ ((__used__, section (".gnu.gomp_requires"))) = { };
+
 #elif defined CRT_END
 
 const void *const __offload_funcs_end[0]
@@ -63,6 +66,9 @@ const void *const __offload_vars_end[0]
   __attribute__ ((__used__, visibility ("hidden"),
                  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
 
+const unsigned int const __requires_mask_table_end[0]
+  __attribute__ ((__used__, section (".gnu.gomp_requires"))) = { };
+
 #elif defined CRT_TABLE
 
 extern const void *const __offload_func_table[];
@@ -77,6 +83,9 @@ const void *const __OFFLOAD_TABLE__[]
   &__offload_var_table, &__offload_vars_end
 };
 
+extern const unsigned int const __requires_mask_table[];
+extern const unsigned int const __requires_mask_table_end[];
+
 #else /* ! CRT_BEGIN && ! CRT_END && ! CRT_TABLE  */
 #error "One of CRT_BEGIN, CRT_END or CRT_TABLE must be defined."
 #endif
index e8eebee55ec266c9b5836e84d455fc54e84d78d3..43f62bad9b520b1256871fe2803683faf295c6bb 100644 (file)
@@ -122,6 +122,7 @@ extern int GOMP_OFFLOAD_get_type (void);
 extern int GOMP_OFFLOAD_get_num_devices (void);
 extern bool GOMP_OFFLOAD_init_device (int);
 extern bool GOMP_OFFLOAD_fini_device (int);
+extern bool GOMP_OFFLOAD_supported_features (unsigned *);
 extern unsigned GOMP_OFFLOAD_version (void);
 extern int GOMP_OFFLOAD_load_image (int, unsigned, const void *,
                                    struct addr_pair **);
index 096029fb8b0746eb8a4ad5709dba0739a85e11cf..c4efa1aa8434ee7c59542b05fa0c9d0e2f57ae14 100644 (file)
@@ -1180,6 +1180,7 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
   __typeof (GOMP_OFFLOAD_init_device) *init_device_func;
   __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
+  __typeof (GOMP_OFFLOAD_supported_features) *supported_features_func;
   __typeof (GOMP_OFFLOAD_version) *version_func;
   __typeof (GOMP_OFFLOAD_load_image) *load_image_func;
   __typeof (GOMP_OFFLOAD_unload_image) *unload_image_func;
index 550c0b300fa66037aad6aa434e876914d15b07b9..e61687755be9b9d60a186904f10ff3980d5d8bdd 100644 (file)
@@ -71,6 +71,12 @@ host_fini_device (int n __attribute__ ((unused)))
   return true;
 }
 
+static bool
+host_supported_features (unsigned int *n)
+{
+  return (*n == 0);
+}
+
 static unsigned
 host_version (void)
 {
@@ -297,6 +303,7 @@ static struct gomp_device_descr host_dispatch =
     .get_num_devices_func = host_get_num_devices,
     .init_device_func = host_init_device,
     .fini_device_func = host_fini_device,
+    .supported_features_func = host_supported_features,
     .version_func = host_version,
     .load_image_func = host_load_image,
     .unload_image_func = host_unload_image,
index 24504a032c672cef73a21d2e0d3f05a5c8b57095..d2786c651385cb9f3a988ec5aa53ab2cb9030222 100644 (file)
@@ -4064,4 +4064,12 @@ GOMP_OFFLOAD_openacc_destroy_thread_data (void *data)
   free (data);
 }
 
+/* Indicate which GOMP_REQUIRES_* features are supported, currently none.  */
+
+bool
+GOMP_OFFLOAD_supported_features (unsigned int *mask)
+{
+  return (*mask == 0);
+}
+
 /* }}} */
index d2ee232f4f673abc94762deae72d4203e87d4a57..942fb989bac5ff0faa1401a7dc8fcb2fd4b9eb88 100644 (file)
@@ -1233,6 +1233,14 @@ GOMP_OFFLOAD_fini_device (int n)
   return true;
 }
 
+/* Indicate which GOMP_REQUIRES_* features are supported, currently none.  */
+
+bool
+GOMP_OFFLOAD_supported_features (unsigned int *mask)
+{
+  return (*mask == 0);
+}
+
 /* Return the libgomp version number we're compatible with.  There is
    no requirement for cross-version compatibility.  */
 
index 0c9fe58e14d5691a94c317bee26a5c5b0b555306..699dc72cb72236f4c5aeb1e1d4bee1108f964e6e 100644 (file)
@@ -31,6 +31,7 @@
 #include "gomp-constants.h"
 #include <limits.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #ifdef HAVE_INTTYPES_H
 # include <inttypes.h>  /* For PRIu64.  */
@@ -96,6 +97,16 @@ static int num_devices;
 /* Number of GOMP_OFFLOAD_CAP_OPENMP_400 devices.  */
 static int num_devices_openmp;
 
+/* Mask of requires directive clause values, summarized from .gnu.gomp.requires
+   section. Offload plugins are queried with this mask to see if all required
+   features are supported.  */
+static unsigned int gomp_requires_mask;
+
+/* Start/end of .gnu.gomp.requires section of program, defined in
+   crtoffloadbegin/end.o.  */
+extern const unsigned int __requires_mask_table[];
+extern const unsigned int __requires_mask_table_end[];
+
 /* Similar to gomp_realloc, but release register_lock before gomp_fatal.  */
 
 static void *
@@ -2384,6 +2395,20 @@ gomp_init_device (struct gomp_device_descr *devicep)
       gomp_fatal ("device initialization failed");
     }
 
+  unsigned int features = gomp_requires_mask;
+  if (!devicep->supported_features_func (&features))
+    {
+      char buf[64], *end = buf + sizeof (buf), *p = buf;
+      if (features & GOMP_REQUIRES_UNIFIED_ADDRESS)
+       p += snprintf (p, end - p, "unified_address");
+      if (features & GOMP_REQUIRES_UNIFIED_SHARED_MEMORY)
+       p += snprintf (p, end - p, "%sunified_shared_memory",
+                      (p == buf ? "" : ", "));
+      if (features & GOMP_REQUIRES_REVERSE_OFFLOAD)
+       p += snprintf (p, end - p, "%sreverse_offload", (p == buf ? "" : ", "));
+      gomp_error ("device does not support required features: %s", buf);
+    }
+
   /* Load to device all images registered by the moment.  */
   for (i = 0; i < num_offload_images; i++)
     {
@@ -3664,6 +3689,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (get_num_devices);
   DLSYM (init_device);
   DLSYM (fini_device);
+  DLSYM (supported_features);
   DLSYM (load_image);
   DLSYM (unload_image);
   DLSYM (alloc);
@@ -3776,6 +3802,28 @@ gomp_target_init (void)
   if (gomp_target_offload_var == GOMP_TARGET_OFFLOAD_DISABLED)
     return;
 
+  gomp_requires_mask = 0;
+  const unsigned int *mask_ptr = __requires_mask_table;
+  bool error_emitted = false;
+  while (mask_ptr != __requires_mask_table_end)
+    {
+      if (gomp_requires_mask == 0)
+       gomp_requires_mask = *mask_ptr;
+      else if (gomp_requires_mask != *mask_ptr)
+       {
+         if (!error_emitted)
+           {
+             gomp_error ("requires-directive clause inconsistency between "
+                         "compilation units detected");
+             error_emitted = true;
+           }
+         /* This is inconsistent, but still merge to query for all features
+            later.  */
+         gomp_requires_mask |= *mask_ptr;
+       }
+      mask_ptr++;
+    }
+
   cur = OFFLOAD_PLUGINS;
   if (*cur)
     do
diff --git a/libgomp/testsuite/libgomp.c-c++-common/requires-1-aux.c b/libgomp/testsuite/libgomp.c-c++-common/requires-1-aux.c
new file mode 100644 (file)
index 0000000..8b93415
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-skip-if "" { *-*-* } } */
+
+#pragma omp requires reverse_offload
+
+int x;
+
+void foo (void)
+{
+  #pragma omp target
+  x = 1;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/requires-1.c b/libgomp/testsuite/libgomp.c-c++-common/requires-1.c
new file mode 100644 (file)
index 0000000..02585ad
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-additional-sources requires-1-aux.c } */
+
+#pragma omp requires unified_shared_memory
+
+int a[10];
+extern void foo (void);
+
+int
+main (void)
+{
+  #pragma omp target
+  for (int i = 0; i < 10; i++)
+    a[i] = 0;
+
+  foo ();
+  return 0;
+}
+
+/* { dg-output "libgomp: requires-directive clause inconsistency between compilation units detected" } */
+/* { dg-prune-output "device does not support required features" } */
diff --git a/libgomp/testsuite/libgomp.c-c++-common/requires-2-aux.c b/libgomp/testsuite/libgomp.c-c++-common/requires-2-aux.c
new file mode 100644 (file)
index 0000000..8b93415
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-skip-if "" { *-*-* } } */
+
+#pragma omp requires reverse_offload
+
+int x;
+
+void foo (void)
+{
+  #pragma omp target
+  x = 1;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/requires-2.c b/libgomp/testsuite/libgomp.c-c++-common/requires-2.c
new file mode 100644 (file)
index 0000000..0302f89
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-additional-sources requires-2-aux.c } */
+
+#pragma omp requires reverse_offload
+
+int a[10];
+extern void foo (void);
+
+int
+main (void)
+{
+  #pragma omp target
+  for (int i = 0; i < 10; i++)
+    a[i] = 0;
+
+  foo ();
+  return 0;
+}
+
+/* { dg-output "libgomp: device does not support required features: reverse_offload" } */
index d1678d0514e91e775fff7fe361b861f706b53782..f92418fa4164b9fb68a8081982764d21d725f6ba 100644 (file)
@@ -233,6 +233,14 @@ GOMP_OFFLOAD_fini_device (int device)
   return true;
 }
 
+/* Indicate which GOMP_REQUIRES_* features are supported, currently none.  */
+
+extern "C" bool
+GOMP_OFFLOAD_supported_features (unsigned int *mask)
+{
+  return (*mask == 0);
+}
+
 static bool
 get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
 {