| //===-- 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 <cassert> | |
| #include <cstdint> | |
| 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 |