//===-- OpenMP/Requirements.h - User required requirements -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Handling of the `omp requires` directive, e.g., requiring unified shared // memory. // //===----------------------------------------------------------------------===// #ifndef OMPTARGET_OPENMP_REQUIREMENTS_H #define OMPTARGET_OPENMP_REQUIREMENTS_H #include "Shared/Debug.h" #include "llvm/ADT/StringRef.h" #include #include enum OpenMPOffloadingRequiresDirFlags : int64_t { /// flag undefined. OMP_REQ_UNDEFINED = 0x000, /// no requires directive present. OMP_REQ_NONE = 0x001, /// reverse_offload clause. OMP_REQ_REVERSE_OFFLOAD = 0x002, /// unified_address clause. OMP_REQ_UNIFIED_ADDRESS = 0x004, /// unified_shared_memory clause. OMP_REQ_UNIFIED_SHARED_MEMORY = 0x008, /// dynamic_allocators clause. OMP_REQ_DYNAMIC_ALLOCATORS = 0x010, /// Auto zero-copy extension: /// when running on an APU, the GPU plugin may decide to /// run in zero-copy even though the user did not program /// their application with unified_shared_memory requirement. OMPX_REQ_AUTO_ZERO_COPY = 0x020 }; class RequirementCollection { int64_t SetFlags = OMP_REQ_UNDEFINED; /// Check consistency between different requires flags (from different /// translation units). void checkConsistency(int64_t NewFlags, int64_t SetFlags, OpenMPOffloadingRequiresDirFlags Flag, llvm::StringRef Clause) { if ((SetFlags & Flag) != (NewFlags & Flag)) { FATAL_MESSAGE(2, "'#pragma omp requires %s' not used consistently!", Clause.data()); } } public: /// Register \p NewFlags as part of the user requirements. void addRequirements(int64_t NewFlags) { // TODO: add more elaborate check. // Minimal check: only set requires flags if previous value // is undefined. This ensures that only the first call to this // function will set the requires flags. All subsequent calls // will be checked for compatibility. assert(NewFlags != OMP_REQ_UNDEFINED && "illegal undefined flag for requires directive!"); if (SetFlags == OMP_REQ_UNDEFINED) { SetFlags = NewFlags; return; } // Auto zero-copy is only valid when no other requirement has been set // and it is computed at device initialization time, after the requirement // flag has already been set to OMP_REQ_NONE. if (SetFlags == OMP_REQ_NONE && NewFlags == OMPX_REQ_AUTO_ZERO_COPY) { SetFlags = NewFlags; return; } // If multiple compilation units are present enforce // consistency across all of them for require clauses: // - reverse_offload // - unified_address // - unified_shared_memory // - dynamic_allocators checkConsistency(NewFlags, SetFlags, OMP_REQ_REVERSE_OFFLOAD, "reverse_offload"); checkConsistency(NewFlags, SetFlags, OMP_REQ_UNIFIED_ADDRESS, "unified_address"); checkConsistency(NewFlags, SetFlags, OMP_REQ_UNIFIED_SHARED_MEMORY, "unified_shared_memory"); checkConsistency(NewFlags, SetFlags, OMP_REQ_DYNAMIC_ALLOCATORS, "dynamic_allocators"); } /// Return the user provided requirements. int64_t getRequirements() const { return SetFlags; } }; #endif // OMPTARGET_OPENMP_DEVICE_REQUIREMENTS_H