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 SystemScope, 44 DeviceScope, 45 WorkgroupScope, 46 WavefrontScope, 47 SingleScope, 48 HIPSingleThread, 49 HIPWavefront, 50 HIPWorkgroup, 51 HIPAgent, 52 HIPSystem, 53 OpenCLWorkGroup, 54 OpenCLDevice, 55 OpenCLAllSVMDevices, 56 OpenCLSubGroup, 57 Last = OpenCLSubGroup 58 }; 59 60 inline llvm::StringRef getAsString(SyncScope S) { 61 switch (S) { 62 case SyncScope::SystemScope: 63 return "system_scope"; 64 case SyncScope::DeviceScope: 65 return "device_scope"; 66 case SyncScope::WorkgroupScope: 67 return "workgroup_scope"; 68 case SyncScope::WavefrontScope: 69 return "wavefront_scope"; 70 case SyncScope::SingleScope: 71 return "single_scope"; 72 case SyncScope::HIPSingleThread: 73 return "hip_singlethread"; 74 case SyncScope::HIPWavefront: 75 return "hip_wavefront"; 76 case SyncScope::HIPWorkgroup: 77 return "hip_workgroup"; 78 case SyncScope::HIPAgent: 79 return "hip_agent"; 80 case SyncScope::HIPSystem: 81 return "hip_system"; 82 case SyncScope::OpenCLWorkGroup: 83 return "opencl_workgroup"; 84 case SyncScope::OpenCLDevice: 85 return "opencl_device"; 86 case SyncScope::OpenCLAllSVMDevices: 87 return "opencl_allsvmdevices"; 88 case SyncScope::OpenCLSubGroup: 89 return "opencl_subgroup"; 90 } 91 llvm_unreachable("Invalid synch scope"); 92 } 93 94 /// Defines the kind of atomic scope models. 95 enum class AtomicScopeModelKind { None, OpenCL, HIP, Generic }; 96 97 /// Defines the interface for synch scope model. 98 class AtomicScopeModel { 99 public: 100 virtual ~AtomicScopeModel() {} 101 /// Maps language specific synch scope values to internal 102 /// SyncScope enum. 103 virtual SyncScope map(unsigned S) const = 0; 104 105 /// Check if the compile-time constant synch scope value 106 /// is valid. 107 virtual bool isValid(unsigned S) const = 0; 108 109 /// Get all possible synch scope values that might be 110 /// encountered at runtime for the current language. 111 virtual ArrayRef<unsigned> getRuntimeValues() const = 0; 112 113 /// If atomic builtin function is called with invalid 114 /// synch scope value at runtime, it will fall back to a valid 115 /// synch scope value returned by this function. 116 virtual unsigned getFallBackValue() const = 0; 117 118 /// Create an atomic scope model by AtomicScopeModelKind. 119 /// \return an empty std::unique_ptr for AtomicScopeModelKind::None. 120 static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K); 121 }; 122 123 /// Defines the synch scope model for OpenCL. 124 class AtomicScopeOpenCLModel : public AtomicScopeModel { 125 public: 126 /// The enum values match the pre-defined macros 127 /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_* 128 /// enums in opencl-c-base.h. 129 enum ID { 130 WorkGroup = 1, 131 Device = 2, 132 AllSVMDevices = 3, 133 SubGroup = 4, 134 Last = SubGroup 135 }; 136 137 AtomicScopeOpenCLModel() {} 138 139 SyncScope map(unsigned S) const override { 140 switch (static_cast<ID>(S)) { 141 case WorkGroup: 142 return SyncScope::OpenCLWorkGroup; 143 case Device: 144 return SyncScope::OpenCLDevice; 145 case AllSVMDevices: 146 return SyncScope::OpenCLAllSVMDevices; 147 case SubGroup: 148 return SyncScope::OpenCLSubGroup; 149 } 150 llvm_unreachable("Invalid language synch scope value"); 151 } 152 153 bool isValid(unsigned S) const override { 154 return S >= static_cast<unsigned>(WorkGroup) && 155 S <= static_cast<unsigned>(Last); 156 } 157 158 ArrayRef<unsigned> getRuntimeValues() const override { 159 static_assert(Last == SubGroup, "Does not include all synch scopes"); 160 static const unsigned Scopes[] = { 161 static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device), 162 static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)}; 163 return llvm::ArrayRef(Scopes); 164 } 165 166 unsigned getFallBackValue() const override { 167 return static_cast<unsigned>(AllSVMDevices); 168 } 169 }; 170 171 /// Defines the synch scope model for HIP. 172 class AtomicScopeHIPModel : public AtomicScopeModel { 173 public: 174 /// The enum values match the pre-defined macros 175 /// __HIP_MEMORY_SCOPE_*, which are used to define memory_scope_* 176 /// enums in hip-c.h. 177 enum ID { 178 SingleThread = 1, 179 Wavefront = 2, 180 Workgroup = 3, 181 Agent = 4, 182 System = 5, 183 Last = System 184 }; 185 186 AtomicScopeHIPModel() {} 187 188 SyncScope map(unsigned S) const override { 189 switch (static_cast<ID>(S)) { 190 case SingleThread: 191 return SyncScope::HIPSingleThread; 192 case Wavefront: 193 return SyncScope::HIPWavefront; 194 case Workgroup: 195 return SyncScope::HIPWorkgroup; 196 case Agent: 197 return SyncScope::HIPAgent; 198 case System: 199 return SyncScope::HIPSystem; 200 } 201 llvm_unreachable("Invalid language synch scope value"); 202 } 203 204 bool isValid(unsigned S) const override { 205 return S >= static_cast<unsigned>(SingleThread) && 206 S <= static_cast<unsigned>(Last); 207 } 208 209 ArrayRef<unsigned> getRuntimeValues() const override { 210 static_assert(Last == System, "Does not include all synch scopes"); 211 static const unsigned Scopes[] = { 212 static_cast<unsigned>(SingleThread), static_cast<unsigned>(Wavefront), 213 static_cast<unsigned>(Workgroup), static_cast<unsigned>(Agent), 214 static_cast<unsigned>(System)}; 215 return llvm::ArrayRef(Scopes); 216 } 217 218 unsigned getFallBackValue() const override { 219 return static_cast<unsigned>(System); 220 } 221 }; 222 223 /// Defines the generic atomic scope model. 224 class AtomicScopeGenericModel : public AtomicScopeModel { 225 public: 226 /// The enum values match predefined built-in macros __ATOMIC_SCOPE_*. 227 enum ID { 228 System = 0, 229 Device = 1, 230 Workgroup = 2, 231 Wavefront = 3, 232 Single = 4, 233 Last = Single 234 }; 235 236 AtomicScopeGenericModel() = default; 237 238 SyncScope map(unsigned S) const override { 239 switch (static_cast<ID>(S)) { 240 case Device: 241 return SyncScope::DeviceScope; 242 case System: 243 return SyncScope::SystemScope; 244 case Workgroup: 245 return SyncScope::WorkgroupScope; 246 case Wavefront: 247 return SyncScope::WavefrontScope; 248 case Single: 249 return SyncScope::SingleScope; 250 } 251 llvm_unreachable("Invalid language sync scope value"); 252 } 253 254 bool isValid(unsigned S) const override { 255 return S <= static_cast<unsigned>(Last); 256 } 257 258 ArrayRef<unsigned> getRuntimeValues() const override { 259 static_assert(Last == Single, "Does not include all sync scopes"); 260 static const unsigned Scopes[] = { 261 static_cast<unsigned>(Device), static_cast<unsigned>(System), 262 static_cast<unsigned>(Workgroup), static_cast<unsigned>(Wavefront), 263 static_cast<unsigned>(Single)}; 264 return llvm::ArrayRef(Scopes); 265 } 266 267 unsigned getFallBackValue() const override { 268 return static_cast<unsigned>(System); 269 } 270 }; 271 272 inline std::unique_ptr<AtomicScopeModel> 273 AtomicScopeModel::create(AtomicScopeModelKind K) { 274 switch (K) { 275 case AtomicScopeModelKind::None: 276 return std::unique_ptr<AtomicScopeModel>{}; 277 case AtomicScopeModelKind::OpenCL: 278 return std::make_unique<AtomicScopeOpenCLModel>(); 279 case AtomicScopeModelKind::HIP: 280 return std::make_unique<AtomicScopeHIPModel>(); 281 case AtomicScopeModelKind::Generic: 282 return std::make_unique<AtomicScopeGenericModel>(); 283 } 284 llvm_unreachable("Invalid atomic scope model kind"); 285 } 286 } // namespace clang 287 288 #endif 289