This came up when looking at some context selectors that use 'target_device', but is largely unrelated to it. (target_device has its own special casing).
Namely, it makes omp_get_initial_device and omp_get_num_devices PURE, which attributes don't permit for Fortran - based on the state that the number of devices cannot change after startup. I am not sure whether "LEAF" is true here (and elsewhere) as the check whether the devices setup has been to run. [Q:] Is that's an issue? Caveat: Using -std=c++XX will disable all OpenMP builtins, unless -fbuiltin-... or -fnonansi-builtins. I wonder whether [RFC 1] we should do something about this ... [RFC 1] - Does this patch make sense or not? - Do the simplifications make sense or not? - Is the documentation fine or overly complex? Tobias
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/f95-lang.cc | 3 +- gcc/fortran/gfortran.h | 6 ++-- gcc/fortran/options.cc | 4 +++ gcc/fortran/trans-expr.cc | 10 ++++++ gcc/gimple-fold.cc | 40 ++++++++++++++++++++++ gcc/omp-builtins.def | 9 +++-- .../gomp/omp_get_num_devices_initial_device-2.c | 33 ++++++++++++++++++ .../gomp/omp_get_num_devices_initial_device.c | 36 +++++++++++++++++++ .../gomp/omp_get_num_devices_initial_device-2.f90 | 21 ++++++++++++ .../gomp/omp_get_num_devices_initial_device.f90 | 24 +++++++++++++ libgomp/libgomp.texi | 14 ++++++++ 11 files changed, 194 insertions(+), 6 deletions(-) diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc index 1f09553142d..bb4ce6d8288 100644 --- a/gcc/fortran/f95-lang.cc +++ b/gcc/fortran/f95-lang.cc @@ -564,7 +564,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) @@ -580,6 +580,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 e461aa68470..f73b5f9c23f 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3302,8 +3302,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 ddddc1c2833..d3c9066630b 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 74d4265f27d..c8a207609e4 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -4635,6 +4635,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 185f9db69d8..41e32677c9f 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -4097,6 +4097,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. */ @@ -5341,6 +5375,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 f73fb7b9dd8..db1ec963841 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_CONST_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_GOMP_ATOMIC_START, "GOMP_atomic_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) 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 00000000000..29e0da2b6c2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device-2.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ + +/* The test suite cycles through -std=c++* which do not include + non-ansi builtins, contrary to -std=gnu++*. */ +/* { dg-additional-options "-fnonansi-builtins" { target c++ } } */ +/* { 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 00000000000..3b5dd639721 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ + +/* The test suite cycles through -std=c++* which do not include + non-ansi builtins, contrary to -std=gnu++*. */ +/* { dg-additional-options "-fnonansi-builtins" { target c++ } } */ +/* { 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 00000000000..18613d458b1 --- /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 00000000000..5409f12f464 --- /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 7116fcda13f..bd7cf7cb811 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 in GCC this function call is already folded to at compile time: +To the value @code{omp_initial_device} in non-host code, to zero if GCC +was not configured to support offloading, or otherwise to a call to +@code{omp_get_num_devices}; compile with +@option{-fno-builtin-omp_get_initial_device} if a run-time function is desired. + @item @emph{C/C++} @multitable @columnfractions .20 .80 @item @emph{Prototype}: @tab @code{int omp_get_initial_device(void);} gcc/fortran/f95-lang.cc | 3 +- gcc/fortran/gfortran.h | 6 ++-- gcc/fortran/options.cc | 4 +++ gcc/fortran/trans-expr.cc | 10 ++++++ gcc/gimple-fold.cc | 40 ++++++++++++++++++++++ gcc/omp-builtins.def | 9 +++-- .../gomp/omp_get_num_devices_initial_device-2.c | 33 ++++++++++++++++++ .../gomp/omp_get_num_devices_initial_device.c | 36 +++++++++++++++++++ .../gomp/omp_get_num_devices_initial_device-2.f90 | 21 ++++++++++++ .../gomp/omp_get_num_devices_initial_device.f90 | 24 +++++++++++++ libgomp/libgomp.texi | 14 ++++++++ 11 files changed, 194 insertions(+), 6 deletions(-) diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc index 1f09553142d..bb4ce6d8288 100644 --- a/gcc/fortran/f95-lang.cc +++ b/gcc/fortran/f95-lang.cc @@ -564,7 +564,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) @@ -580,6 +580,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 e461aa68470..f73b5f9c23f 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3302,8 +3302,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 ddddc1c2833..d3c9066630b 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 74d4265f27d..c8a207609e4 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -4635,6 +4635,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 185f9db69d8..41e32677c9f 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -4097,6 +4097,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. */ @@ -5341,6 +5375,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 f73fb7b9dd8..db1ec963841 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_CONST_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_GOMP_ATOMIC_START, "GOMP_atomic_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) 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 00000000000..29e0da2b6c2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device-2.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ + +/* The test suite cycles through -std=c++* which do not include + non-ansi builtins, contrary to -std=gnu++*. */ +/* { dg-additional-options "-fnonansi-builtins" { target c++ } } */ +/* { 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 00000000000..3b5dd639721 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/omp_get_num_devices_initial_device.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ + +/* The test suite cycles through -std=c++* which do not include + non-ansi builtins, contrary to -std=gnu++*. */ +/* { dg-additional-options "-fnonansi-builtins" { target c++ } } */ +/* { 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 00000000000..18613d458b1 --- /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 00000000000..5409f12f464 --- /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 7116fcda13f..bd7cf7cb811 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 in GCC this function call is already folded to at compile time: +To the value @code{omp_initial_device} in non-host code, to zero if GCC +was not configured to support offloading, or otherwise to a call to +@code{omp_get_num_devices}; compile with +@option{-fno-builtin-omp_get_initial_device} if a run-time function is desired. + @item @emph{C/C++} @multitable @columnfractions .20 .80 @item @emph{Prototype}: @tab @code{int omp_get_initial_device(void);}