1 //===--- SyncScope.h - Atomic synchronization scopes ------------*- 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 /// \file 10 /// Provides definitions for the atomic synchronization scopes. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H 15 #define LLVM_CLANG_BASIC_SYNCSCOPE_H 16 17 #include "clang/Basic/LangOptions.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/StringRef.h" 20 #include <memory> 21 22 namespace clang { 23 24 /// Defines synch scope values used internally by clang. 25 /// 26 /// The enum values start from 0 and are contiguous. They are mainly used for 27 /// enumerating all supported synch scope values and mapping them to LLVM 28 /// synch scopes. Their numerical values may be different from the corresponding 29 /// synch scope enums used in source languages. 30 /// 31 /// In atomic builtin and expressions, language-specific synch scope enums are 32 /// used. Currently only OpenCL memory scope enums are supported and assumed 33 /// to be used by all languages. However, in the future, other languages may 34 /// define their own set of synch scope enums. The language-specific synch scope 35 /// values are represented by class AtomicScopeModel and its derived classes. 36 /// 37 /// To add a new enum value: 38 /// Add the enum value to enum class SyncScope. 39 /// Update enum value Last if necessary. 40 /// Update getAsString. 41 /// 42 enum class SyncScope { 43 HIPSingleThread, 44 HIPWavefront, 45 HIPWorkgroup, 46 HIPAgent, 47 HIPSystem, 48 OpenCLWorkGroup, 49 OpenCLDevice, 50 OpenCLAllSVMDevices, 51 OpenCLSubGroup, 52 Last = OpenCLSubGroup 53 }; 54 55 inline llvm::StringRef getAsString(SyncScope S) { 56 switch (S) { 57 case SyncScope::HIPSingleThread: 58 return "hip_singlethread"; 59 case SyncScope::HIPWavefront: 60 return "hip_wavefront"; 61 case SyncScope::HIPWorkgroup: 62 return "hip_workgroup"; 63 case SyncScope::HIPAgent: 64 return "hip_agent"; 65 case SyncScope::HIPSystem: 66 return "hip_system"; 67 case SyncScope::OpenCLWorkGroup: 68 return "opencl_workgroup"; 69 case SyncScope::OpenCLDevice: 70 return "opencl_device"; 71 case SyncScope::OpenCLAllSVMDevices: 72 return "opencl_allsvmdevices"; 73 case SyncScope::OpenCLSubGroup: 74 return "opencl_subgroup"; 75 } 76 llvm_unreachable("Invalid synch scope"); 77 } 78 79 /// Defines the kind of atomic scope models. 80 enum class AtomicScopeModelKind { None, OpenCL, HIP }; 81 82 /// Defines the interface for synch scope model. 83 class AtomicScopeModel { 84 public: 85 virtual ~AtomicScopeModel() {} 86 /// Maps language specific synch scope values to internal 87 /// SyncScope enum. 88 virtual SyncScope map(unsigned S) const = 0; 89 90 /// Check if the compile-time constant synch scope value 91 /// is valid. 92 virtual bool isValid(unsigned S) const = 0; 93 94 /// Get all possible synch scope values that might be 95 /// encountered at runtime for the current language. 96 virtual ArrayRef<unsigned> getRuntimeValues() const = 0; 97 98 /// If atomic builtin function is called with invalid 99 /// synch scope value at runtime, it will fall back to a valid 100 /// synch scope value returned by this function. 101 virtual unsigned getFallBackValue() const = 0; 102 103 /// Create an atomic scope model by AtomicScopeModelKind. 104 /// \return an empty std::unique_ptr for AtomicScopeModelKind::None. 105 static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K); 106 }; 107 108 /// Defines the synch scope model for OpenCL. 109 class AtomicScopeOpenCLModel : public AtomicScopeModel { 110 public: 111 /// The enum values match the pre-defined macros 112 /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_* 113 /// enums in opencl-c-base.h. 114 enum ID { 115 WorkGroup = 1, 116 Device = 2, 117 AllSVMDevices = 3, 118 SubGroup = 4, 119 Last = SubGroup 120 }; 121 122 AtomicScopeOpenCLModel() {} 123 124 SyncScope map(unsigned S) const override { 125 switch (static_cast<ID>(S)) { 126 case WorkGroup: 127 return SyncScope::OpenCLWorkGroup; 128 case Device: 129 return SyncScope::OpenCLDevice; 130 case AllSVMDevices: 131 return SyncScope::OpenCLAllSVMDevices; 132 case SubGroup: 133 return SyncScope::OpenCLSubGroup; 134 } 135 llvm_unreachable("Invalid language synch scope value"); 136 } 137 138 bool isValid(unsigned S) const override { 139 return S >= static_cast<unsigned>(WorkGroup) && 140 S <= static_cast<unsigned>(Last); 141 } 142 143 ArrayRef<unsigned> getRuntimeValues() const override { 144 static_assert(Last == SubGroup, "Does not include all synch scopes"); 145 static const unsigned Scopes[] = { 146 static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device), 147 static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)}; 148 return llvm::makeArrayRef(Scopes); 149 } 150 151 unsigned getFallBackValue() const override { 152 return static_cast<unsigned>(AllSVMDevices); 153 } 154 }; 155 156 /// Defines the synch scope model for HIP. 157 class AtomicScopeHIPModel : public AtomicScopeModel { 158 public: 159 /// The enum values match the pre-defined macros 160 /// __HIP_MEMORY_SCOPE_*, which are used to define memory_scope_* 161 /// enums in hip-c.h. 162 enum ID { 163 SingleThread = 1, 164 Wavefront = 2, 165 Workgroup = 3, 166 Agent = 4, 167 System = 5, 168 Last = System 169 }; 170 171 AtomicScopeHIPModel() {} 172 173 SyncScope map(unsigned S) const override { 174 switch (static_cast<ID>(S)) { 175 case SingleThread: 176 return SyncScope::HIPSingleThread; 177 case Wavefront: 178 return SyncScope::HIPWavefront; 179 case Workgroup: 180 return SyncScope::HIPWorkgroup; 181 case Agent: 182 return SyncScope::HIPAgent; 183 case System: 184 return SyncScope::HIPSystem; 185 } 186 llvm_unreachable("Invalid language synch scope value"); 187 } 188 189 bool isValid(unsigned S) const override { 190 return S >= static_cast<unsigned>(SingleThread) && 191 S <= static_cast<unsigned>(Last); 192 } 193 194 ArrayRef<unsigned> getRuntimeValues() const override { 195 static_assert(Last == System, "Does not include all synch scopes"); 196 static const unsigned Scopes[] = { 197 static_cast<unsigned>(SingleThread), static_cast<unsigned>(Wavefront), 198 static_cast<unsigned>(Workgroup), static_cast<unsigned>(Agent), 199 static_cast<unsigned>(System)}; 200 return llvm::makeArrayRef(Scopes); 201 } 202 203 unsigned getFallBackValue() const override { 204 return static_cast<unsigned>(System); 205 } 206 }; 207 208 inline std::unique_ptr<AtomicScopeModel> 209 AtomicScopeModel::create(AtomicScopeModelKind K) { 210 switch (K) { 211 case AtomicScopeModelKind::None: 212 return std::unique_ptr<AtomicScopeModel>{}; 213 case AtomicScopeModelKind::OpenCL: 214 return std::make_unique<AtomicScopeOpenCLModel>(); 215 case AtomicScopeModelKind::HIP: 216 return std::make_unique<AtomicScopeHIPModel>(); 217 } 218 llvm_unreachable("Invalid atomic scope model kind"); 219 } 220 } // namespace clang 221 222 #endif 223