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 22namespace 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/// 42enum 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 60inline 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. 95enum class AtomicScopeModelKind { None, OpenCL, HIP, Generic }; 96 97/// Defines the interface for synch scope model. 98class AtomicScopeModel { 99public: 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. 124class AtomicScopeOpenCLModel : public AtomicScopeModel { 125public: 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. 172class AtomicScopeHIPModel : public AtomicScopeModel { 173public: 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. 224class AtomicScopeGenericModel : public AtomicScopeModel { 225public: 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>(System) && 256 S <= static_cast<unsigned>(Last); 257 } 258 259 ArrayRef<unsigned> getRuntimeValues() const override { 260 static_assert(Last == Single, "Does not include all sync scopes"); 261 static const unsigned Scopes[] = { 262 static_cast<unsigned>(Device), static_cast<unsigned>(System), 263 static_cast<unsigned>(Workgroup), static_cast<unsigned>(Wavefront), 264 static_cast<unsigned>(Single)}; 265 return llvm::ArrayRef(Scopes); 266 } 267 268 unsigned getFallBackValue() const override { 269 return static_cast<unsigned>(System); 270 } 271}; 272 273inline std::unique_ptr<AtomicScopeModel> 274AtomicScopeModel::create(AtomicScopeModelKind K) { 275 switch (K) { 276 case AtomicScopeModelKind::None: 277 return std::unique_ptr<AtomicScopeModel>{}; 278 case AtomicScopeModelKind::OpenCL: 279 return std::make_unique<AtomicScopeOpenCLModel>(); 280 case AtomicScopeModelKind::HIP: 281 return std::make_unique<AtomicScopeHIPModel>(); 282 case AtomicScopeModelKind::Generic: 283 return std::make_unique<AtomicScopeGenericModel>(); 284 } 285 llvm_unreachable("Invalid atomic scope model kind"); 286} 287} // namespace clang 288 289#endif 290