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 | |