aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Burnus <tburnus@baylibre.com>2025-06-06 16:22:06 +0200
committerTobias Burnus <tburnus@baylibre.com>2025-06-06 16:39:53 +0200
commit5f56185a23e4e6d417091ba21f9eac4d0b4da239 (patch)
tree7d0496b175aaf7bd95d453e5b79bc9790940f311
parentc8963f01ac813346f543ae118e702df8c28cd884 (diff)
downloadgcc-5f56185a23e4e6d417091ba21f9eac4d0b4da239.zip
gcc-5f56185a23e4e6d417091ba21f9eac4d0b4da239.tar.gz
gcc-5f56185a23e4e6d417091ba21f9eac4d0b4da239.tar.bz2
OpenMP: Add omp_get_initial_device/omp_get_num_devices builtins
By adding omp_get_initial_device and omp_get_num_devices builtins for C, C++, and Fortran, the following can be achieved: * By making them pure, multiple calls can be avoiding in some cases. * Some comparisons can be optimized at compile time. omp_get_initial_device will be converted to omp_get_num_devices for consistency; note that OpenMP 6 also permits omp_initial_device (== -1) as value. If GCC has not been configure for offloading, either intrinsic will leads to 0 - and on the offload side, -1 (= omp_initial_device) is returned for omp_initial_device. gcc/fortran/ChangeLog: * f95-lang.cc (ATTR_PURE_NOTHROW_LIST): Define. * trans-expr.cc (get_builtin_fn): Handle omp_get_num_devices and omp_get_intrinsic_device. * gfortran.h (gfc_option_t): Add disable_omp_... for them. * options.cc (gfc_handle_option): Handle them with -fno-builtin-. gcc/ChangeLog: * gimple-fold.cc (gimple_fold_builtin_omp_get_initial_device, gimple_fold_builtin_omp_get_num_devices): New. (gimple_fold_builtin): Call them. * omp-builtins.def (BUILT_IN_OMP_GET_INITIAL_DEVICE): Add (BUILT_IN_OMP_GET_NUM_DEVICES): Make uservisible + pure. libgomp/ChangeLog: * libgomp.texi (omp_get_num_devices, omp_get_intrinsic_device): Document builtin handling. gcc/testsuite/ChangeLog: * c-c++-common/gomp/omp_get_num_devices_initial_device-2.c: New test. * c-c++-common/gomp/omp_get_num_devices_initial_device.c: New test. * gfortran.dg/gomp/omp_get_num_devices_initial_device-2.f90: New test. * gfortran.dg/gomp/omp_get_num_devices_initial_device.f90: New test. Co-authored-by: Sandra Loosemore <sloosemore@baylibre.com> (cherry picked from commit 387209938d2c476a67966c6ddbdbf817626f24a2)
-rw-r--r--gcc/fortran/f95-lang.cc3
-rw-r--r--gcc/fortran/gfortran.h6
-rw-r--r--gcc/fortran/options.cc4
-rw-r--r--gcc/fortran/trans-expr.cc10
-rw-r--r--gcc/gimple-fold.cc40
-rw-r--r--gcc/omp-builtins.def9
-rw-r--r--gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device-2.c29
-rw-r--r--gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device.c32
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device-2.f9021
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device.f9024
-rw-r--r--libgomp/libgomp.texi14
11 files changed, 186 insertions, 6 deletions
diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc
index 3808fed..3b6610e 100644
--- a/gcc/fortran/f95-lang.cc
+++ b/gcc/fortran/f95-lang.cc
@@ -571,7 +571,7 @@ gfc_builtin_function (tree decl)
return decl;
}
-/* So far we need just these 10 attribute types. */
+/* So far we need just these 12 attribute types. */
#define ATTR_NULL 0
#define ATTR_LEAF_LIST (ECF_LEAF)
#define ATTR_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF)
@@ -587,6 +587,7 @@ gfc_builtin_function (tree decl)
#define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
(ECF_COLD | ECF_NORETURN | \
ECF_NOTHROW | ECF_LEAF)
+#define ATTR_PURE_NOTHROW_LIST (ECF_PURE | ECF_NOTHROW)
static void
gfc_define_builtin (const char *name, tree type, enum built_in_function code,
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 903712a..aa44571 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3338,8 +3338,10 @@ typedef struct
int flag_init_logical;
int flag_init_character;
char flag_init_character_value;
- bool disable_omp_is_initial_device;
- bool disable_acc_on_device;
+ bool disable_omp_is_initial_device:1;
+ bool disable_omp_get_initial_device:1;
+ bool disable_omp_get_num_devices:1;
+ bool disable_acc_on_device:1;
int fpe;
int fpe_summary;
diff --git a/gcc/fortran/options.cc b/gcc/fortran/options.cc
index ddddc1c..d3c9066 100644
--- a/gcc/fortran/options.cc
+++ b/gcc/fortran/options.cc
@@ -883,6 +883,10 @@ gfc_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
return false; /* Not supported. */
if (!strcmp ("omp_is_initial_device", arg))
gfc_option.disable_omp_is_initial_device = true;
+ else if (!strcmp ("omp_get_initial_device", arg))
+ gfc_option.disable_omp_get_initial_device = true;
+ else if (!strcmp ("omp_get_num_devices", arg))
+ gfc_option.disable_omp_get_num_devices = true;
else if (!strcmp ("acc_on_device", arg))
gfc_option.disable_acc_on_device = true;
else
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 7031a829..d72545e 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -4627,6 +4627,16 @@ get_builtin_fn (gfc_symbol * sym)
&& !strcmp (sym->name, "omp_is_initial_device"))
return builtin_decl_explicit (BUILT_IN_OMP_IS_INITIAL_DEVICE);
+ if (!gfc_option.disable_omp_get_initial_device
+ && flag_openmp && sym->attr.function && sym->ts.type == BT_INTEGER
+ && !strcmp (sym->name, "omp_get_initial_device"))
+ return builtin_decl_explicit (BUILT_IN_OMP_GET_INITIAL_DEVICE);
+
+ if (!gfc_option.disable_omp_get_num_devices
+ && flag_openmp && sym->attr.function && sym->ts.type == BT_INTEGER
+ && !strcmp (sym->name, "omp_get_num_devices"))
+ return builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_DEVICES);
+
if (!gfc_option.disable_acc_on_device
&& flag_openacc && sym->attr.function && sym->ts.type == BT_LOGICAL
&& !strcmp (sym->name, "acc_on_device_h"))
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index a64922a..b867d66 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -4224,6 +4224,40 @@ gimple_fold_builtin_omp_is_initial_device (gimple_stmt_iterator *gsi)
return false;
}
+/* omp_get_initial_device was in OpenMP 5.0/5.1 explicitly and in
+ 5.0 implicitly the same as omp_get_num_devices; since 6.0 it is
+ unspecified whether -1 or omp_get_num_devices() is returned. For
+ better backward compatibility, use omp_get_num_devices() on the
+ host - and -1 on the device (where the result is unspecified). */
+
+static bool
+gimple_fold_builtin_omp_get_initial_device (gimple_stmt_iterator *gsi)
+{
+#if ACCEL_COMPILER
+ replace_call_with_value (gsi, build_int_cst (integer_type_node, -1));
+#else
+ if (!ENABLE_OFFLOADING)
+ replace_call_with_value (gsi, integer_zero_node);
+ else
+ {
+ tree fn = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_DEVICES);
+ gcall *repl = gimple_build_call (fn, 0);
+ replace_call_with_call_and_fold (gsi, repl);
+ }
+#endif
+ return true;
+}
+
+static bool
+gimple_fold_builtin_omp_get_num_devices (gimple_stmt_iterator *gsi)
+{
+ if (!ENABLE_OFFLOADING)
+ {
+ replace_call_with_value (gsi, integer_zero_node);
+ return true;
+ }
+ return false;
+}
/* Fold a call to __builtin_acc_on_device. */
@@ -5468,6 +5502,12 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
case BUILT_IN_OMP_IS_INITIAL_DEVICE:
return gimple_fold_builtin_omp_is_initial_device (gsi);
+ case BUILT_IN_OMP_GET_INITIAL_DEVICE:
+ return gimple_fold_builtin_omp_get_initial_device (gsi);
+
+ case BUILT_IN_OMP_GET_NUM_DEVICES:
+ return gimple_fold_builtin_omp_get_num_devices (gsi);
+
case BUILT_IN_REALLOC:
return gimple_fold_builtin_realloc (gsi);
diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
index 97e8b6a..cfc2fd8 100644
--- a/gcc/omp-builtins.def
+++ b/gcc/omp-builtins.def
@@ -71,7 +71,12 @@ DEF_GOACC_BUILTIN_ONLY (BUILT_IN_GOACC_SINGLE_COPY_END, "GOACC_single_copy_end",
DEF_GOMP_BUILTIN_COMPILER (BUILT_IN_OMP_IS_INITIAL_DEVICE,
"omp_is_initial_device", BT_FN_INT,
- ATTR_CONST_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LIST)
+DEF_GOMP_BUILTIN_COMPILER (BUILT_IN_OMP_GET_INITIAL_DEVICE,
+ "omp_get_initial_device", BT_FN_INT,
+ ATTR_PURE_NOTHROW_LIST)
+DEF_GOMP_BUILTIN_COMPILER (BUILT_IN_OMP_GET_NUM_DEVICES, "omp_get_num_devices",
+ BT_FN_INT, ATTR_PURE_NOTHROW_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_THREAD_NUM, "omp_get_thread_num",
BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads",
@@ -88,8 +93,6 @@ DEF_GOMP_BUILTIN (BUILT_IN_OMP_SET_DEFAULT_DEVICE, "omp_set_default_device",
BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_INTEROP_INT, "omp_get_interop_int",
BT_FN_PTRMODE_PTR_INT_PTR, ATTR_NOTHROW_LEAF_LIST)
-DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_DEVICES, "omp_get_num_devices",
- BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_OMP_INIT_ALLOCATOR, "omp_init_allocator",
BT_FN_PTRMODE_PTRMODE_INT_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_OMP_DESTROY_ALLOCATOR, "omp_destroy_allocator",
diff --git a/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device-2.c b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device-2.c
new file mode 100644
index 0000000..891f5cf
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device-2.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O1 -fdump-tree-optimized -fno-builtin-omp_get_num_devices -fno-builtin-omp_get_initial_device" } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int omp_get_initial_device ();
+extern int omp_get_num_devices ();
+#ifdef __cplusplus
+}
+#endif
+
+int f()
+{
+/* The following assumes that omp_get_initial_device () will not return
+ omp_initial_device (== -1), which is also permitted since OpenMP 6.0. */
+ if (omp_get_initial_device () != omp_get_num_devices ()) __builtin_abort ();
+
+ if (omp_get_num_devices () != omp_get_num_devices ()) __builtin_abort ();
+
+ if (omp_get_initial_device () != omp_get_initial_device ()) __builtin_abort ();
+
+ return omp_get_num_devices ();
+}
+
+/* { dg-final { scan-tree-dump-times "abort" 3 "optimized" } } */
+
+/* { dg-final { scan-tree-dump-times "omp_get_num_devices" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "omp_get_initial_device" 3 "optimized" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device.c b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device.c
new file mode 100644
index 0000000..4b17143
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O1 -fdump-tree-optimized" } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int omp_get_initial_device ();
+extern int omp_get_num_devices ();
+#ifdef __cplusplus
+}
+#endif
+
+int f()
+{
+/* The following assumes that omp_get_initial_device () will not return
+ omp_initial_device (== -1), which is also permitted since OpenMP 6.0. */
+ if (omp_get_initial_device () != omp_get_num_devices ()) __builtin_abort ();
+
+ if (omp_get_num_devices () != omp_get_num_devices ()) __builtin_abort ();
+
+ if (omp_get_initial_device () != omp_get_initial_device ()) __builtin_abort ();
+
+ return omp_get_num_devices ();
+}
+
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
+
+/* { dg-final { scan-tree-dump-not "omp_get_num_devices;" "optimized" { target { ! offloading_enabled } } } } */
+/* { dg-final { scan-tree-dump "return 0;" "optimized" { target { ! offloading_enabled } } } } */
+
+/* { dg-final { scan-tree-dump-times "omp_get_num_devices;" 1 "optimized" { target offloading_enabled } } } */
+/* { dg-final { scan-tree-dump "_1 = __builtin_omp_get_num_devices \\(\\);\[\\r\\n\]+\[ \]+return _1;" "optimized" { target offloading_enabled } } } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device-2.f90 b/gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device-2.f90
new file mode 100644
index 0000000..18613d4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device-2.f90
@@ -0,0 +1,21 @@
+! { dg-do compile }
+! { dg-additional-options "-O1 -fdump-tree-optimized -fno-builtin-omp_get_num_devices -fno-builtin-omp_get_initial_device" }
+integer function f() result(ret)
+ interface
+ integer function omp_get_initial_device (); end
+ integer function omp_get_num_devices (); end
+ end interface
+
+ if (omp_get_initial_device () /= omp_get_num_devices ()) error stop
+
+ if (omp_get_num_devices () /= omp_get_num_devices ()) error stop
+
+ if (omp_get_initial_device () /= omp_get_initial_device ()) error stop
+
+ ret = omp_get_num_devices ()
+end
+
+! { dg-final { scan-tree-dump-times "error_stop" 3 "optimized" } }
+
+! { dg-final { scan-tree-dump-times "omp_get_num_devices" 4 "optimized" } }
+! { dg-final { scan-tree-dump-times "omp_get_initial_device" 3 "optimized" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device.f90 b/gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device.f90
new file mode 100644
index 0000000..5409f12
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/omp_get_num_devices_initial_device.f90
@@ -0,0 +1,24 @@
+! { dg-do compile }
+! { dg-additional-options "-O1 -fdump-tree-optimized" }
+integer function f() result(ret)
+ interface
+ integer function omp_get_initial_device (); end
+ integer function omp_get_num_devices (); end
+ end interface
+
+ if (omp_get_initial_device () /= omp_get_num_devices ()) error stop
+
+ if (omp_get_num_devices () /= omp_get_num_devices ()) error stop
+
+ if (omp_get_initial_device () /= omp_get_initial_device ()) error stop
+
+ ret = omp_get_num_devices ()
+end
+
+! { dg-final { scan-tree-dump-not "error_stop" "optimized" } }
+
+! { dg-final { scan-tree-dump-not "omp_get_num_devices;" "optimized" { target { ! offloading_enabled } } } }
+! { dg-final { scan-tree-dump "return 0;" "optimized" { target { ! offloading_enabled } } } }
+
+! { dg-final { scan-tree-dump-times "omp_get_num_devices;" 1 "optimized" { target offloading_enabled } } }
+! { dg-final { scan-tree-dump "_1 = __builtin_omp_get_num_devices \\(\\);\[\\r\\n\]+\[ \]+return _1;" "optimized" { target offloading_enabled } } }
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index e1b70b0..5e5500f 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -1802,6 +1802,11 @@ Returns the number of available non-host devices.
The effect of running this routine in a @code{target} region is unspecified.
+Note that in GCC the function is marked pure, i.e. as returning always the
+same number. When GCC was not configured to support offloading, it is replaced
+by zero; compile with @option{-fno-builtin-omp_get_num_devices} if a run-time
+function is desired.
+
@item @emph{C/C++}:
@multitable @columnfractions .20 .80
@item @emph{Prototype}: @tab @code{int omp_get_num_devices(void);}
@@ -1812,6 +1817,9 @@ The effect of running this routine in a @code{target} region is unspecified.
@item @emph{Interface}: @tab @code{integer function omp_get_num_devices()}
@end multitable
+@item @emph{See also}:
+@ref{omp_get_initial_device}
+
@item @emph{Reference}:
@uref{https://www.openmp.org, OpenMP specification v4.5}, Section 3.2.31.
@end table
@@ -1950,6 +1958,12 @@ the value of @code{omp_initial_device}.
The effect of running this routine in a @code{target} region is unspecified.
+Note that GCC inlines this function unless you compile with
+@option{-fno-builtin-omp_get_initial_device}. If GCC was not configured to
+support offloading, it expands to constant zero; in non-host code it expands
+to @code{omp_initial_device}; and otherwise it is replaced with a call to
+@code{omp_get_num_devices}.
+
@item @emph{C/C++}
@multitable @columnfractions .20 .80
@item @emph{Prototype}: @tab @code{int omp_get_initial_device(void);}