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

source code of clang/include/clang/Basic/SyncScope.h