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
getAsString(SyncScope S)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:
~AtomicScopeModel()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
AtomicScopeOpenCLModel()122 AtomicScopeOpenCLModel() {}
123
map(unsigned S)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
isValid(unsigned S)138 bool isValid(unsigned S) const override {
139 return S >= static_cast<unsigned>(WorkGroup) &&
140 S <= static_cast<unsigned>(Last);
141 }
142
getRuntimeValues()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::ArrayRef(Scopes);
149 }
150
getFallBackValue()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
AtomicScopeHIPModel()171 AtomicScopeHIPModel() {}
172
map(unsigned S)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
isValid(unsigned S)189 bool isValid(unsigned S) const override {
190 return S >= static_cast<unsigned>(SingleThread) &&
191 S <= static_cast<unsigned>(Last);
192 }
193
getRuntimeValues()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::ArrayRef(Scopes);
201 }
202
getFallBackValue()203 unsigned getFallBackValue() const override {
204 return static_cast<unsigned>(System);
205 }
206 };
207
208 inline std::unique_ptr<AtomicScopeModel>
create(AtomicScopeModelKind K)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