From 3c14034c55a296306ad0ea4990f0f1b34e9e5d6e Mon Sep 17 00:00:00 2001 From: Amit Tiwari Date: Tue, 28 Apr 2026 21:31:04 +0530 Subject: [PATCH] [Flang][OpenMP] Validate `omp_initial_device` `omp_invalid_device` as device IDs (#193669) As per OpenMP 5.2/6.0 the below are valid device values in a `#pragma omp target` directive: omp_initial_device (-1) -> refers to the host CPU. omp_invalid_device (-2) -> an intentionally invalid device, used to trigger a runtime error. For the 2 values discussed above flang fails with: ``` error: The device expression of the DEVICE clause must be a positive integer expression !$OMP TARGET DEVICE(-1) error: Must have INTEGER type, but is REAL(4) !$OMP TARGET DEVICE(OMP_INVALID_DEVICE) ``` Issue: https://github.com/llvm/llvm-project/issues/192989 --- flang/lib/Semantics/check-omp-structure.cpp | 16 +++- .../Semantics/OpenMP/device-constructs.f90 | 18 +++- .../OpenMP/device-omp-initial-invalid.f90 | 82 +++++++++++++++++++ flang/test/Semantics/OpenMP/device-pre-52.f90 | 36 ++++++++ openmp/module/omp_lib.F90.var | 3 + openmp/module/omp_lib.h.var | 5 ++ 6 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 flang/test/Semantics/OpenMP/device-omp-initial-invalid.f90 create mode 100644 flang/test/Semantics/OpenMP/device-pre-52.f90 diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 713e1d02e21c..114a098da15f 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -4735,8 +4735,20 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) { const parser::OmpDeviceClause &deviceClause{x.v}; const auto &device{std::get(deviceClause.t)}; unsigned version{context_.langOptions().OpenMPVersion}; - RequiresPositiveParameter( - llvm::omp::Clause::OMPC_device, device, "device expression"); + // The predefined identifiers omp_initial_device (-1) and omp_invalid_device + // (-2) were introduced in OpenMP 5.2. Under earlier versions the device + // expression must be a non-negative integer. + if (version >= 52) { + if (const auto v{GetIntValue(device)}) { + if (*v < -2) { + context_.Say(GetContext().clauseSource, + "The device expression of the DEVICE clause must be a non-negative integer expression, 'omp_initial_device' (-1), or 'omp_invalid_device' (-2)"_err_en_US); + } + } + } else { + RequiresPositiveParameter( + llvm::omp::Clause::OMPC_device, device, "device expression"); + } llvm::omp::Directive dir{GetContext().directive}; if (OmpVerifyModifiers(deviceClause, llvm::omp::OMPC_device, diff --git a/flang/test/Semantics/OpenMP/device-constructs.f90 b/flang/test/Semantics/OpenMP/device-constructs.f90 index a41c461874b9..db04e7db155a 100644 --- a/flang/test/Semantics/OpenMP/device-constructs.f90 +++ b/flang/test/Semantics/OpenMP/device-constructs.f90 @@ -1,4 +1,4 @@ -! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51 +! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52 ! Check OpenMP clause validity for the following directives: ! 2.10 Device constructs program main @@ -151,12 +151,24 @@ program main enddo !$omp end target data - !ERROR: The device expression of the DEVICE clause must be a positive integer expression + ! -2 is the reserved value omp_invalid_device (OpenMP 5.2+), so it is valid. !$omp target enter data map(alloc:A) device(-2) - !ERROR: The device expression of the DEVICE clause must be a positive integer expression + ! -2 is the reserved value omp_invalid_device (OpenMP 5.2+), so it is valid. !$omp target exit data map(delete:A) device(-2) + ! -1 is the reserved value omp_initial_device (OpenMP 5.2+), so it is valid. + !$omp target enter data map(alloc:A) device(-1) + + ! -1 is the reserved value omp_initial_device (OpenMP 5.2+), so it is valid. + !$omp target exit data map(delete:A) device(-1) + + !ERROR: The device expression of the DEVICE clause must be a non-negative integer expression, 'omp_initial_device' (-1), or 'omp_invalid_device' (-2) + !$omp target enter data map(alloc:A) device(-3) + + !ERROR: The device expression of the DEVICE clause must be a non-negative integer expression, 'omp_initial_device' (-1), or 'omp_invalid_device' (-2) + !$omp target exit data map(delete:A) device(-3) + !ERROR: At most one IF clause can appear on the TARGET ENTER DATA directive !$omp target enter data map(to:a) if(.true.) if(.false.) diff --git a/flang/test/Semantics/OpenMP/device-omp-initial-invalid.f90 b/flang/test/Semantics/OpenMP/device-omp-initial-invalid.f90 new file mode 100644 index 000000000000..6b76265bd96f --- /dev/null +++ b/flang/test/Semantics/OpenMP/device-omp-initial-invalid.f90 @@ -0,0 +1,82 @@ +! The predefined identifiers omp_initial_device (-1) and omp_invalid_device +! (-2) from the OpenMP 5.2+ specification must be accepted as valid device +! numbers in the DEVICE clause of target constructs. + +! REQUIRES: openmp_runtime + +! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=52 +! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=60 + +program main + use omp_lib + + real(8) :: arrayA(256) + integer :: N, dev + arrayA = 1.414d0 + N = 256 + + ! Literal values allowed by the OpenMP 5.2 / 6.0 specification. + !$omp target device(-1) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + !$omp target device(-2) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + !$omp target device(0) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + ! Using the predefined identifiers from the omp_lib module. + !$omp target device(omp_initial_device) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + !$omp target device(omp_invalid_device) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + ! Also accepted on target data and its data motion variants. + !$omp target data map(to: arrayA) device(omp_initial_device) + !$omp end target data + + !$omp target data map(to: arrayA) device(omp_invalid_device) + !$omp end target data + + !$omp target enter data map(alloc: arrayA) device(omp_initial_device) + !$omp target enter data map(alloc: arrayA) device(omp_invalid_device) + + !$omp target exit data map(delete: arrayA) device(omp_initial_device) + !$omp target exit data map(delete: arrayA) device(omp_invalid_device) + + !$omp target update to(arrayA) device(omp_initial_device) + !$omp target update to(arrayA) device(omp_invalid_device) + + ! Runtime-determined values pass the semantic check. + dev = -1 + !$omp target device(dev) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + ! Values below -2 are still rejected. + !ERROR: The device expression of the DEVICE clause must be a non-negative integer expression, 'omp_initial_device' (-1), or 'omp_invalid_device' (-2) + !$omp target device(-3) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + +end program main diff --git a/flang/test/Semantics/OpenMP/device-pre-52.f90 b/flang/test/Semantics/OpenMP/device-pre-52.f90 new file mode 100644 index 000000000000..f5356e80a0ba --- /dev/null +++ b/flang/test/Semantics/OpenMP/device-pre-52.f90 @@ -0,0 +1,36 @@ +! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=50 +! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51 + +program main + real(8) :: arrayA(256) + integer :: N + arrayA = 1.414d0 + N = 256 + + !ERROR: The device expression of the DEVICE clause must be a positive integer expression + !$omp target device(-1) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + !ERROR: The device expression of the DEVICE clause must be a positive integer expression + !$omp target device(-2) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + !ERROR: The device expression of the DEVICE clause must be a positive integer expression + !$omp target device(-3) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target + + !$omp target device(0) + do i = 1, N + arrayA(i) = 3.14d0 + enddo + !$omp end target +end program main diff --git a/openmp/module/omp_lib.F90.var b/openmp/module/omp_lib.F90.var index 90d7e49ebf54..464056847ab9 100644 --- a/openmp/module/omp_lib.F90.var +++ b/openmp/module/omp_lib.F90.var @@ -102,6 +102,9 @@ integer(kind=omp_sched_kind), parameter, public :: omp_sched_auto = 4 integer(kind=omp_sched_kind), parameter, public :: omp_sched_monotonic = int(Z'80000000', kind=omp_sched_kind) + integer (kind=omp_integer_kind), parameter, public :: omp_initial_device = -1 + integer (kind=omp_integer_kind), parameter, public :: omp_invalid_device = -2 + integer (kind=omp_proc_bind_kind), parameter, public :: omp_proc_bind_false = 0 integer (kind=omp_proc_bind_kind), parameter, public :: omp_proc_bind_true = 1 integer (kind=omp_proc_bind_kind), parameter, public :: omp_proc_bind_master = 2 diff --git a/openmp/module/omp_lib.h.var b/openmp/module/omp_lib.h.var index a50bb018c7cc..e515c9434f12 100644 --- a/openmp/module/omp_lib.h.var +++ b/openmp/module/omp_lib.h.var @@ -79,6 +79,11 @@ integer(kind=omp_sched_kind)omp_sched_monotonic parameter(omp_sched_monotonic=Z'80000000') + integer(kind=omp_integer_kind)omp_initial_device + parameter(omp_initial_device=-1) + integer(kind=omp_integer_kind)omp_invalid_device + parameter(omp_invalid_device=-2) + integer(kind=omp_proc_bind_kind)omp_proc_bind_false parameter(omp_proc_bind_false=0) integer(kind=omp_proc_bind_kind)omp_proc_bind_true