1 //===-- OpenMP/Requirements.h - User required requirements -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Handling of the `omp requires` directive, e.g., requiring unified shared 10 // memory. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef OMPTARGET_OPENMP_REQUIREMENTS_H 15 #define OMPTARGET_OPENMP_REQUIREMENTS_H 16 17 #include "Shared/Debug.h" 18 19 #include "llvm/ADT/StringRef.h" 20 21 #include <cassert> 22 #include <cstdint> 23 24 enum OpenMPOffloadingRequiresDirFlags : int64_t { 25 /// flag undefined. 26 OMP_REQ_UNDEFINED = 0x000, 27 /// no requires directive present. 28 OMP_REQ_NONE = 0x001, 29 /// reverse_offload clause. 30 OMP_REQ_REVERSE_OFFLOAD = 0x002, 31 /// unified_address clause. 32 OMP_REQ_UNIFIED_ADDRESS = 0x004, 33 /// unified_shared_memory clause. 34 OMP_REQ_UNIFIED_SHARED_MEMORY = 0x008, 35 /// dynamic_allocators clause. 36 OMP_REQ_DYNAMIC_ALLOCATORS = 0x010, 37 /// Auto zero-copy extension: 38 /// when running on an APU, the GPU plugin may decide to 39 /// run in zero-copy even though the user did not program 40 /// their application with unified_shared_memory requirement. 41 OMPX_REQ_AUTO_ZERO_COPY = 0x020 42 }; 43 44 class RequirementCollection { 45 int64_t SetFlags = OMP_REQ_UNDEFINED; 46 47 /// Check consistency between different requires flags (from different 48 /// translation units). checkConsistency(int64_t NewFlags,int64_t SetFlags,OpenMPOffloadingRequiresDirFlags Flag,llvm::StringRef Clause)49 void checkConsistency(int64_t NewFlags, int64_t SetFlags, 50 OpenMPOffloadingRequiresDirFlags Flag, 51 llvm::StringRef Clause) { 52 if ((SetFlags & Flag) != (NewFlags & Flag)) { 53 FATAL_MESSAGE(2, "'#pragma omp requires %s' not used consistently!", 54 Clause.data()); 55 } 56 } 57 58 public: 59 /// Register \p NewFlags as part of the user requirements. addRequirements(int64_t NewFlags)60 void addRequirements(int64_t NewFlags) { 61 // TODO: add more elaborate check. 62 // Minimal check: only set requires flags if previous value 63 // is undefined. This ensures that only the first call to this 64 // function will set the requires flags. All subsequent calls 65 // will be checked for compatibility. 66 assert(NewFlags != OMP_REQ_UNDEFINED && 67 "illegal undefined flag for requires directive!"); 68 if (SetFlags == OMP_REQ_UNDEFINED) { 69 SetFlags = NewFlags; 70 return; 71 } 72 73 // Auto zero-copy is only valid when no other requirement has been set 74 // and it is computed at device initialization time, after the requirement 75 // flag has already been set to OMP_REQ_NONE. 76 if (SetFlags == OMP_REQ_NONE && NewFlags == OMPX_REQ_AUTO_ZERO_COPY) { 77 SetFlags = NewFlags; 78 return; 79 } 80 81 // If multiple compilation units are present enforce 82 // consistency across all of them for require clauses: 83 // - reverse_offload 84 // - unified_address 85 // - unified_shared_memory 86 // - dynamic_allocators 87 checkConsistency(NewFlags, SetFlags, OMP_REQ_REVERSE_OFFLOAD, 88 "reverse_offload"); 89 checkConsistency(NewFlags, SetFlags, OMP_REQ_UNIFIED_ADDRESS, 90 "unified_address"); 91 checkConsistency(NewFlags, SetFlags, OMP_REQ_UNIFIED_SHARED_MEMORY, 92 "unified_shared_memory"); 93 checkConsistency(NewFlags, SetFlags, OMP_REQ_DYNAMIC_ALLOCATORS, 94 "dynamic_allocators"); 95 } 96 97 /// Return the user provided requirements. getRequirements()98 int64_t getRequirements() const { return SetFlags; } 99 }; 100 101 #endif // OMPTARGET_OPENMP_DEVICE_REQUIREMENTS_H 102