Fortran: intrinsic.texi is touched.
Middle-end: the known-intrinsics omp_runtime_api_procname is touched.
[The rest is in libgomp itself.]
* * *
Yes another patch on the way to implement OpenMP's kernel language ...
This patch adds some named constants (enum, parameter) and one of the
groupprivate API routines: namely omp_get_gprivate_limit, the only one
that takes a device number as argument.
The function currently always returns 0 which is not quite right
on nvptx as that accepts the 'groupprivate' directive and the API
routine also covers this. - However, it only really becomes useful
as soon as the 'dyn_groupprivate' clause of 'target' is honored.
[There is parser support for it, but no runtime support - which
is also delayed because it touches GOMP_target_ext which is ABI
relevant - and, hence, needs to be carefully designed.]
The other functions also need to be eventually implemented, but
possibly all (and not only some) as builtin functions? In any
case, those are tight to an actual implementation and only make
sense when the actual support has landed.
* * *
While touching it, I noticed that the documentation of the
named constants in gfortran's intrinsic.texi (OpenMP's
intrinsic module) were incomplete. Eventually, this list
should be moved to libgomp, cleaned up and their C/C++ counter
part needs to be added as well. But for now, it is at least
complete again.
Comments, concerns, remarks before I commit it?
Tobias
PS: While 'groupprivate' is in principle usable today, an
experimental implementation of the rest will become available
eventually (GCC 17?), cf. the GUTA talk at the Cauldron:
https://conf.gnu-tools-cauldron.org/prg26/talk/9ULSQA/
Note that Cauldron videos are meanwhile available.
libgomp: Add omp_get_gprivate_limit API routine
This API routine returns the maximally possible limit of for groupprivate
variables, be it via the directive or using the dyn_groupprivate clause.
GCC still has to support dyn_groupprivate, however, 'groupprivate' is
supported on some offload devices. Note that for simplicity, the added API
routines currently always return 0.
For some reasons, there is a 'omp_access_pteam' named constant, even if
it is nowhere specified for what it can be used. The API routines
and the 'dyn_groupprivate' clause technically accept other values, but,
effectively, only 'omp_access_cgroup' is specified.
gcc/fortran/ChangeLog:
* intrinsic.texi (OpenMP intrinsic modules): Update list of
kind value and parameters.
gcc/ChangeLog:
* omp-general.cc (omp_runtime_api_procname): Add
omp_get_gprivate_limit.
libgomp/ChangeLog:
* fortran.c (omp_get_gprivate_limit_): Add.
* libgomp-plugin.h (GOMP_OFFLOAD_get_gprivate_limit): Add.
* libgomp.h (struct gomp_device_descr): Add get_gprivate_limit_func.
* libgomp.map: Add omp_get_gprivate_limit_.
* libgomp.texi (omp_get_gprivate_limit): Document new routine.
* omp.h.in (omp_access_t, omp_get_gprivate_limit): Add.
* omp_lib.f90.in (omp_access_kind, omp_get_gprivate_limit): Add.
* omp_lib.h.in (omp_access_kind, omp_get_gprivate_limit): Add.
* plugin/plugin-gcn.c (GOMP_OFFLOAD_get_gprivate_limit): Add.
* plugin/plugin-nvptx.c (GOMP_OFFLOAD_get_gprivate_limit): Add.
* target.c (omp_get_gprivate_limit): Add.
* testsuite/libgomp.c-c++-common/gprivate-1.c: New test.
* testsuite/libgomp.fortran/gprivate-1.f90: New test.
gcc/fortran/intrinsic.texi | 72 +++++++++++++++++++++-
gcc/omp-general.cc | 1 +
libgomp/fortran.c | 9 +++
libgomp/libgomp-plugin.h | 1 +
libgomp/libgomp.h | 1 +
libgomp/libgomp.map | 2 +
libgomp/libgomp.texi | 45 +++++++++++++-
libgomp/omp.h.in | 9 +++
libgomp/omp_lib.f90.in | 13 ++++
libgomp/omp_lib.h.in | 16 +++++
libgomp/plugin/plugin-gcn.c | 12 ++++
libgomp/plugin/plugin-nvptx.c | 12 ++++
libgomp/target.c | 23 +++++++
.../testsuite/libgomp.c-c++-common/gprivate-1.c | 42 +++++++++++++
libgomp/testsuite/libgomp.fortran/gprivate-1.f90 | 49 +++++++++++++++
15 files changed, 305 insertions(+), 2 deletions(-)
diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi
index bce59971e4b..53c6baed0b6 100644
--- a/gcc/fortran/intrinsic.texi
+++ b/gcc/fortran/intrinsic.texi
@@ -16410,15 +16410,23 @@ OpenMP Application Program Interface v6.0}.
named constants:
@table @asis
+@item @code{omp_access_kind}
@item @code{omp_allocator_handle_kind}
@item @code{omp_alloctrait_key_kind}
@item @code{omp_alloctrait_val_kind}
+@item @code{omp_control_tool_kind}
+@item @code{omp_control_tool_result_kind}
@item @code{omp_depend_kind}
+@item @code{omp_event_handle_kind}
+@item @code{omp_interop_fr_kind}
+@item @code{omp_interop_kind}
+@item @code{omp_interop_property_kind}
+@item @code{omp_interop_rc_kind}
@item @code{omp_lock_kind}
@item @code{omp_lock_hint_kind}
+@item @code{omp_memspace_handle_kind}
@item @code{omp_nest_lock_kind}
@item @code{omp_pause_resource_kind}
-@item @code{omp_memspace_handle_kind}
@item @code{omp_proc_bind_kind}
@item @code{omp_sched_kind}
@item @code{omp_sync_hint_kind}
@@ -16543,6 +16551,8 @@ The following scalar integer named constants are of the kind
@item @code{omp_cgroup_mem_alloc}
@item @code{omp_pteam_mem_alloc}
@item @code{omp_thread_mem_alloc}
+@item @code{ompx_gnu_pinned_mem_alloc} (GCC specific)
+@item @code{ompx_gnu_managed_mem_alloc} (GCC specific)
@end table
The following scalar integer named constants are of the kind
@@ -16554,6 +16564,66 @@ The following scalar integer named constants are of the kind
@item @code{omp_const_mem_space}
@item @code{omp_high_bw_mem_space}
@item @code{omp_low_lat_mem_space}
+@item @code{ompx_gnu_managed_mem_space} (GCC specific)
+@end table
+
+The following scalar integer named constant is of the kind
+@code{omp_interop_kind}:
+
+@table @asis
+@item @code{omp_interop_none}
+@end table
+
+The following scalar integer named constants are of the kind
+@code{omp_interop_fr_kind}:
+
+@table @asis
+@item @code{omp_ifr_cuda}
+@item @code{omp_ifr_cuda_driver}
+@item @code{omp_ifr_opencl}
+@item @code{omp_ifr_sycl}
+@item @code{omp_ifr_hip}
+@item @code{omp_ifr_level_zero}
+@item @code{omp_ifr_hsa}
+@item @code{omp_ifr_last}
+@end table
+
+The following scalar integer named constants are of the kind
+@code{omp_interop_property_kind}:
+
+@table @asis
+@item @code{omp_ipr_fr_id}
+@item @code{omp_ipr_fr_name}
+@item @code{omp_ipr_vendor}
+@item @code{omp_ipr_vendor_name}
+@item @code{omp_ipr_device_num}
+@item @code{omp_ipr_platform}
+@item @code{omp_ipr_device}
+@item @code{omp_ipr_device_context}
+@item @code{omp_ipr_targetsync}
+@item @code{omp_ipr_first}
+@end table
+
+The following scalar integer named constants are of the kind
+@code{omp_interop_rc_kind}:
+
+@table @asis
+@item @code{omp_irc_no_value}
+@item @code{omp_irc_success}
+@item @code{omp_irc_empty}
+@item @code{omp_irc_out_of_range}
+@item @code{omp_irc_type_int}
+@item @code{omp_irc_type_ptr}
+@item @code{omp_irc_type_str}
+@item @code{omp_irc_other}
+@end table
+
+The following scalar integer named constants are of the kind
+@code{omp_access_kind}:
+
+@table @asis
+@item @code{omp_access_cgroup}
+@item @code{omp_access_pteam}
@end table
The following scalar integer named constants are of the kind
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index 5d0bd02f3a3..9162972dc88 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -4021,6 +4021,7 @@ omp_runtime_api_procname (const char *name)
"get_device_from_uid",
"get_device_num",
"get_dynamic",
+ "get_gprivate_limit",
"get_initial_device",
"get_interop_name",
"get_interop_rc_desc",
diff --git a/libgomp/fortran.c b/libgomp/fortran.c
index a28b86ae666..3af77c6c7ba 100644
--- a/libgomp/fortran.c
+++ b/libgomp/fortran.c
@@ -104,6 +104,7 @@ ialias_redirect (omp_get_interop_name)
ialias_redirect (omp_get_interop_type_desc)
ialias_redirect (omp_get_interop_rc_desc)
ialias_redirect (omp_control_tool)
+ialias_redirect (omp_get_gprivate_limit)
ialias_redirect (omp_get_supported_active_team_dims)
ialias_redirect (omp_get_supported_active_league_dims)
#endif
@@ -875,6 +876,14 @@ omp_get_supported_active_league_dims_ (int *device_num, int *native_support)
return omp_get_supported_active_league_dims (*device_num, *native_support);
}
+size_t
+omp_get_gprivate_limit_ (int device_num, int access_group, bool present_agrp)
+{
+ if (!present_agrp)
+ access_group = omp_access_cgroup;
+ return omp_get_gprivate_limit (device_num, access_group);
+}
+
void
omp_display_env_ (const int32_t *verbose)
{
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index a01873131fb..c67eeec6978 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -169,6 +169,7 @@ extern const char *GOMP_OFFLOAD_get_uid (int);
extern int GOMP_OFFLOAD_get_numa_node (int);
extern int GOMP_OFFLOAD_supported_teams_dim (int, int);
extern int GOMP_OFFLOAD_supported_threads_dim (int, int);
+extern size_t GOMP_OFFLOAD_get_gprivate_limit (int, omp_access_t);
extern unsigned int GOMP_OFFLOAD_get_caps (void);
extern unsigned int GOMP_OFFLOAD_get_dev_caps (int);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index c4bab109736..fed3da2e662 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1460,6 +1460,7 @@ struct gomp_device_descr
__typeof (GOMP_OFFLOAD_get_numa_node) *get_numa_node_func;
__typeof (GOMP_OFFLOAD_supported_teams_dim) *supported_teams_dim_func;
__typeof (GOMP_OFFLOAD_supported_threads_dim) *supported_threads_dim_func;
+ __typeof (GOMP_OFFLOAD_get_gprivate_limit) *get_gprivate_limit_func;
__typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
__typeof (GOMP_OFFLOAD_get_dev_caps) *get_dev_caps_func;
__typeof (GOMP_OFFLOAD_get_type) *get_type_func;
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index 00e47d65d4c..19890c05c76 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -250,6 +250,8 @@ OMP_6.0 {
OMP_6.1 {
global:
omp_get_device_distances;
+ omp_get_gprivate_limit;
+ omp_get_gprivate_limit_;
omp_get_num_teams_dim;
omp_get_num_threads_dim;
omp_get_supported_active_league_dims;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index f3f95df0c8b..659f7669195 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -3955,7 +3955,7 @@ They have C linkage and do not throw exceptions.
@c * omp_get_dyn_gprivate_nofb_ptr:: <fixme>/TR15
@c * omp_get_dyn_gprivate_size:: <fixme>/TR15
@c * omp_get_dyn_gprivate_memspace:: <fixme>/TR15
-@c * omp_get_gprivate_limit:: <fixme>/TR15
+* omp_get_gprivate_limit:: Absolute limit of groupprivate memory
@end menu
@@ -4418,6 +4418,49 @@ was already deallocated or when the used allocator has already been destroyed.
+@node omp_get_gprivate_limit
+@subsection @code{omp_get_gprivate_limit} -- Absolute limit of groupprivate memory
+@table @asis
+@item @emph{Description}:
+The @code{omp_get_gprivate_limit} routine returns the maximally possible limit
+on groupprivate memory, which consists of memory allocatable via the
+@code{dyn_groupprivate} clause and of variables that appear in the
+@code{groupprivate} clause. The @var{device_num} must be a conforming device number.
+The @var{access_group} takes @code{omp_access_cgroup} as argument. The effect of
+running this routine in a @code{target} region is unspecified.
+
+@item @emph{C}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{size_t omp_get_gprivate_limit(int *dev_num,}
+@item @tab @code{ omp_access_t access_group)}
+@end multitable
+
+@item @emph{C++}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{size_t omp_get_gprivate_limit(int *dev_num,}
+@item @tab @code{ omp_access_t access_group = omp_access_cgroup)}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{integer (kind=c_size_t) function omp_get_gprivate_limit( &}
+@item @tab @code{ device_num, access_group)}
+@item @tab @code{use, intrinsic :: iso_c_binding, only : c_size_t, c_int}
+@item @tab @code{integer (kind=c_int), value :: device_num}
+@item @tab @code{integer (kind=omp_access_kind), value, optional :: access_group}
+@end multitable
+
+@c @item @emph{See also}:
+@c @ref{omp_alloc}, @ref{omp_aligned_alloc}, @ref{omp_calloc},
+@c @ref{omp_aligned_calloc}, @ref{omp_realloc}
+
+@item @emph{Reference}:
+@c TODO: Update once OpenMP 6.1 is released
+@uref{https://www.openmp.org, OpenMP Technical Report 15}, Section 34.13.5
+@end table
+
+
+
@node Tool Control Routine
@section Tool Control Routine
diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in
index 605ea9bb5a6..6ffec871fd0 100644
--- a/libgomp/omp.h.in
+++ b/libgomp/omp.h.in
@@ -115,6 +115,11 @@ typedef __UINTPTR_TYPE__ omp_uintptr_t;
# define __GOMP_UINTPTR_T_ENUM
#endif
+typedef enum omp_access_t {
+ omp_access_cgroup = 0,
+ omp_access_pteam = 1
+} omp_access_t;
+
typedef enum omp_memspace_handle_t __GOMP_UINTPTR_T_ENUM
{
omp_default_mem_space = 0,
@@ -259,6 +264,7 @@ typedef enum omp_control_tool_result_t {
#ifdef __cplusplus
extern "C" {
# define __GOMP_NOTHROW throw ()
+# define __GOMP_DEFAULT_ACCESS = omp_access_cgroup
# define __GOMP_DEFAULT_NULL_ALLOCATOR = omp_null_allocator
# define __GOMP_DEFAULT_NULL = __null
#else
@@ -343,6 +349,9 @@ extern int omp_is_initial_device (void) __GOMP_NOTHROW;
extern int omp_get_initial_device (void) __GOMP_NOTHROW;
extern int omp_get_max_task_priority (void) __GOMP_NOTHROW;
+extern __SIZE_TYPE__ omp_get_gprivate_limit (int,
+ omp_access_t __GOMP_DEFAULT_ACCESS) __GOMP_NOTHROW;
+
extern void omp_fulfill_event (omp_event_handle_t) __GOMP_NOTHROW;
extern void omp_set_num_teams (int) __GOMP_NOTHROW;
diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in
index 740b5a88641..598ae10fbdf 100644
--- a/libgomp/omp_lib.f90.in
+++ b/libgomp/omp_lib.f90.in
@@ -34,6 +34,7 @@
integer, parameter :: omp_sync_hint_kind = 4
integer, parameter :: omp_lock_hint_kind = omp_sync_hint_kind
integer, parameter :: omp_pause_resource_kind = 4
+ integer, parameter :: omp_access_kind = c_int
integer, parameter :: omp_allocator_handle_kind = c_intptr_t
integer, parameter :: omp_alloctrait_key_kind = c_int
integer, parameter :: omp_alloctrait_val_kind = c_intptr_t
@@ -219,6 +220,8 @@
integer (omp_interop_rc_kind), parameter :: omp_irc_type_ptr = -4
integer (omp_interop_rc_kind), parameter :: omp_irc_type_str = -5
integer (omp_interop_rc_kind), parameter :: omp_irc_other = -6
+ integer (omp_access_kind), parameter :: omp_access_cgroup = 0
+ integer (omp_access_kind), parameter :: omp_access_pteam = 1
integer (omp_control_tool_kind), parameter :: omp_control_tool_start = 1
integer (omp_control_tool_kind), parameter :: omp_control_tool_pause = 2
integer (omp_control_tool_kind), parameter :: omp_control_tool_flush = 3
@@ -710,6 +713,16 @@
end function omp_get_teams_thread_limit
end interface
+ interface
+ integer (kind=c_size_t) function omp_get_gprivate_limit (&
+ device_num, access_group)
+ use, intrinsic :: iso_c_binding, only : c_size_t, c_int
+ import :: omp_access_kind
+ integer (kind=c_int), value :: device_num
+ integer (kind=omp_access_kind), value, optional :: access_group
+ end function omp_get_gprivate_limit
+ end interface
+
interface
subroutine omp_fulfill_event (event)
use omp_lib_kinds
diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in
index cce424eaa35..70ebca71a9b 100644
--- a/libgomp/omp_lib.h.in
+++ b/libgomp/omp_lib.h.in
@@ -89,6 +89,13 @@
integer omp_event_handle_kind
integer omp_interop_kind, omp_interop_fr_kind
integer omp_interop_property_kind, omp_interop_rc_kind
+
+ integer omp_access_kind
+ parameter (omp_access_kind = 4)
+ integer (omp_access_kind) omp_access_cgroup
+ integer (omp_access_kind) omp_access_pteam
+ parameter (omp_access_cgroup = 0)
+ parameter (omp_access_pteam = 1)
integer omp_control_tool_kind
integer omp_control_tool_result_kind
parameter (omp_allocator_handle_kind = @INTPTR_T_KIND@)
@@ -771,6 +778,15 @@
end function omp_get_supported_threads_dim
end interface
+ interface
+ integer (kind=c_size_t) function omp_get_gprivate_limit ( &
+ & device_num, access_group)
+ use, intrinsic :: iso_c_binding, only : c_size_t, c_int
+ import :: omp_access_kind
+ integer (kind=c_int), value :: device_num
+ integer (kind=omp_access_kind),value,optional :: access_group
+ end function omp_get_gprivate_limit
+ end interface
interface
! This function only supports integer(4) for simplicity.
diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index 4aad9532183..9d36178f33f 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -3744,6 +3744,18 @@ GOMP_OFFLOAD_supported_threads_dim (int ord, int dim)
return limit_worker_threads (__INT_MAX__);
}
+/* The maximum amount of memory available in a groupprivate memory space,
+ inclusive of groupprivate variables and any groupprivate copy of an
+ instantiated dynamic groupprivate block. */
+
+size_t
+GOMP_OFFLOAD_get_gprivate_limit (int ord, omp_access_t access)
+{
+ if (access != omp_access_cgroup)
+ return 0;
+ return 0; /* FIXME. dyn_groupprivate unsupported, but otherwise supported. */
+}
+
/* Return the specific capabilities the HSA accelerator have. */
unsigned int
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index 4a559877c9e..62c43e7bd7a 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -1428,6 +1428,18 @@ GOMP_OFFLOAD_supported_threads_dim (int ord, int dim)
return max_warps_block;
}
+/* The maximum amount of memory available in a groupprivate memory space,
+ inclusive of groupprivate variables and any groupprivate copy of an
+ instantiated dynamic groupprivate block. */
+
+size_t
+GOMP_OFFLOAD_get_gprivate_limit (int ord, omp_access_t access)
+{
+ if (access != omp_access_cgroup)
+ return 0;
+ return 0; /* FIXME. dyn_groupprivate unsupported, but otherwise supported. */
+}
+
unsigned int
GOMP_OFFLOAD_get_caps (void)
{
diff --git a/libgomp/target.c b/libgomp/target.c
index f508040e0ca..f09e4ef3855 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -6387,6 +6387,27 @@ omp_get_device_from_uid (const char *uid)
return omp_invalid_device;
}
+/* The maximum amount of memory available in a groupprivate memory space,
+ inclusive of groupprivate variables and any groupprivate copy of an
+ instantiated dynamic groupprivate block. */
+
+size_t
+omp_get_gprivate_limit (int device_num, omp_access_t access_group)
+{
+ if (device_num == omp_default_device)
+ device_num = gomp_get_default_device ();
+
+ if (device_num == omp_initial_device
+ || device_num == omp_get_initial_device ())
+ /* FIXME - update once dyn_groupprivate is supported on the host. */
+ return access_group != omp_access_cgroup ? 0 : 0;
+
+ struct gomp_device_descr *devicep = resolve_device (device_num, false);
+ if (devicep == NULL || !devicep->get_gprivate_limit_func)
+ return 0;
+ return devicep->get_gprivate_limit_func (devicep->target_id, access_group);
+}
+
/* Return the numa distance between the numa node of the calling host
thread and each of the NDEV devices in DEVICES.
Special values:
@@ -6447,6 +6468,7 @@ ialias (omp_get_supported_active_team_dims)
ialias (omp_get_supported_active_league_dims)
ialias (omp_get_supported_threads_dim)
ialias (omp_get_supported_teams_dim)
+ialias (omp_get_gprivate_limit)
ialias (omp_get_uid_from_device)
ialias (omp_get_device_from_uid)
ialias (omp_get_device_distances)
@@ -6497,6 +6519,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
DLSYM_OPT (get_numa_node, get_numa_node);
DLSYM_OPT (supported_threads_dim, supported_threads_dim);
DLSYM_OPT (supported_teams_dim, supported_teams_dim);
+ DLSYM_OPT (get_gprivate_limit, get_gprivate_limit);
DLSYM (get_caps);
DLSYM_OPT (get_dev_caps, get_dev_caps);
DLSYM (get_type);
diff --git a/libgomp/testsuite/libgomp.c-c++-common/gprivate-1.c b/libgomp/testsuite/libgomp.c-c++-common/gprivate-1.c
new file mode 100644
index 00000000000..9dd8f98a1ea
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/gprivate-1.c
@@ -0,0 +1,42 @@
+#include <omp.h>
+
+void
+test_it (int dev)
+{
+ // Invalid access argument - expect 0
+ if (omp_get_gprivate_limit (dev, (omp_access_t) -1) != 0)
+ __builtin_abort ();
+
+ // Invalid access argument - expect 0
+ if (omp_get_gprivate_limit (dev, (omp_access_t) 99) != 0)
+ __builtin_abort ();
+
+ // FIXME: cgroup - should be valid in principle:
+ // - offload: groupprivate permitted for offloading,
+ // even if dyn_groupprivate is not implemented.
+ // - host: dyn_groupprivate implementable, but not implemented.
+ //
+ if (dev == omp_invalid_device
+ && omp_get_gprivate_limit (dev, omp_access_cgroup) != 0)
+ __builtin_abort ();
+ else if (dev != omp_invalid_device // For now, expect 0
+ && omp_get_gprivate_limit (dev, omp_access_cgroup) != 0)
+ __builtin_abort ();
+
+ // pteam - enum value defined but otherwise not specified at all!
+ // but in principle the limit question could be answered.
+ //
+ // Still, for now assume == 0.
+ if (omp_get_gprivate_limit (dev, omp_access_pteam) != 0)
+ __builtin_abort ();
+}
+
+int main ()
+{
+ // avoid - will exit after printing: libgomp: omp_invalid_device encountered
+ // test_it (omp_invalid_device);
+ test_it (omp_default_device);
+
+ for (int dev = omp_initial_device; dev <= omp_get_num_devices (); dev++)
+ test_it (dev);
+}
diff --git a/libgomp/testsuite/libgomp.fortran/gprivate-1.f90 b/libgomp/testsuite/libgomp.fortran/gprivate-1.f90
new file mode 100644
index 00000000000..1cd5cb9f3f3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/gprivate-1.f90
@@ -0,0 +1,49 @@
+module m
+ use omp_lib
+ implicit none (type, external)
+contains
+subroutine test_it (dev)
+ integer, value :: dev
+
+ ! Invalid access argument - expect 0
+ if (omp_get_gprivate_limit (dev, -1_omp_access_kind) /= 0) &
+ stop 1
+
+ ! Invalid access argument - expect 0
+ if (omp_get_gprivate_limit (dev, 99_omp_access_kind) /= 0) &
+ stop 2
+
+ ! FIXME: cgroup - should be valid in principle:
+ ! - offload: groupprivate permitted for offloading,
+ ! even if dyn_groupprivate is not implemented.
+ ! - host: dyn_groupprivate implementable, but not implemented.
+ !
+ if (dev == omp_invalid_device &
+ .and. omp_get_gprivate_limit (dev, omp_access_cgroup) /= 0) then
+ stop 3
+ else if (dev /= omp_invalid_device & ! For now, expect 0
+ .and. omp_get_gprivate_limit (dev, omp_access_cgroup) /= 0) then
+ stop 4
+ end if
+
+ ! pteam - enum value defined but otherwise not specified at all!
+ ! but in principle the limit question could be answered.
+ !
+ ! Still, for now assume == 0.
+ if (omp_get_gprivate_limit (dev, omp_access_pteam) /= 0) &
+ stop 5
+end
+end
+
+program main
+ use m
+ implicit none (type, external)
+ integer :: dev
+ ! avoid - will exit after printing: libgomp: omp_invalid_device encountered
+ ! call test_it (omp_invalid_device)
+ call test_it (omp_default_device)
+
+ do dev = omp_initial_device, omp_get_num_devices ()
+ call test_it (dev)
+ end do
+end