1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Provides definitions for the atomic synchronization scopes.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H
#define LLVM_CLANG_BASIC_SYNCSCOPE_H
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
namespace clang {
/// Defines synch scope values used internally by clang.
///
/// The enum values start from 0 and are contiguous. They are mainly used for
/// enumerating all supported synch scope values and mapping them to LLVM
/// synch scopes. Their numerical values may be different from the corresponding
/// synch scope enums used in source languages.
///
/// In atomic builtin and expressions, language-specific synch scope enums are
/// used. Currently only OpenCL memory scope enums are supported and assumed
/// to be used by all languages. However, in the future, other languages may
/// define their own set of synch scope enums. The language-specific synch scope
/// values are represented by class AtomicScopeModel and its derived classes.
///
/// To add a new enum value:
/// Add the enum value to enum class SyncScope.
/// Update enum value Last if necessary.
/// Update getAsString.
///
enum class SyncScope {
HIPSingleThread,
HIPWavefront,
HIPWorkgroup,
HIPAgent,
HIPSystem,
OpenCLWorkGroup,
OpenCLDevice,
OpenCLAllSVMDevices,
OpenCLSubGroup,
Last = OpenCLSubGroup
};
inline llvm::StringRef getAsString(SyncScope S) {
switch (S) {
case SyncScope::HIPSingleThread:
return "hip_singlethread";
case SyncScope::HIPWavefront:
return "hip_wavefront";
case SyncScope::HIPWorkgroup:
return "hip_workgroup";
case SyncScope::HIPAgent:
return "hip_agent";
case SyncScope::HIPSystem:
return "hip_system";
case SyncScope::OpenCLWorkGroup:
return "opencl_workgroup";
case SyncScope::OpenCLDevice:
return "opencl_device";
case SyncScope::OpenCLAllSVMDevices:
return "opencl_allsvmdevices";
case SyncScope::OpenCLSubGroup:
return "opencl_subgroup";
}
llvm_unreachable("Invalid synch scope");
}
/// Defines the kind of atomic scope models.
enum class AtomicScopeModelKind { None, OpenCL, HIP };
/// Defines the interface for synch scope model.
class AtomicScopeModel {
public:
virtual ~AtomicScopeModel() {}
/// Maps language specific synch scope values to internal
/// SyncScope enum.
virtual SyncScope map(unsigned S) const = 0;
/// Check if the compile-time constant synch scope value
/// is valid.
virtual bool isValid(unsigned S) const = 0;
/// Get all possible synch scope values that might be
/// encountered at runtime for the current language.
virtual ArrayRef<unsigned> getRuntimeValues() const = 0;
/// If atomic builtin function is called with invalid
/// synch scope value at runtime, it will fall back to a valid
/// synch scope value returned by this function.
virtual unsigned getFallBackValue() const = 0;
/// Create an atomic scope model by AtomicScopeModelKind.
/// \return an empty std::unique_ptr for AtomicScopeModelKind::None.
static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K);
};
/// Defines the synch scope model for OpenCL.
class AtomicScopeOpenCLModel : public AtomicScopeModel {
public:
/// The enum values match the pre-defined macros
/// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_*
/// enums in opencl-c-base.h.
enum ID {
WorkGroup = 1,
Device = 2,
AllSVMDevices = 3,
SubGroup = 4,
Last = SubGroup
};
AtomicScopeOpenCLModel() {}
SyncScope map(unsigned S) const override {
switch (static_cast<ID>(S)) {
case WorkGroup:
return SyncScope::OpenCLWorkGroup;
case Device:
return SyncScope::OpenCLDevice;
case AllSVMDevices:
return SyncScope::OpenCLAllSVMDevices;
case SubGroup:
return SyncScope::OpenCLSubGroup;
}
llvm_unreachable("Invalid language synch scope value");
}
bool isValid(unsigned S) const override {
return S >= static_cast<unsigned>(WorkGroup) &&
S <= static_cast<unsigned>(Last);
}
ArrayRef<unsigned> getRuntimeValues() const override {
static_assert(Last == SubGroup, "Does not include all synch scopes");
static const unsigned Scopes[] = {
static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device),
static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)};
return llvm::makeArrayRef(Scopes);
}
unsigned getFallBackValue() const override {
return static_cast<unsigned>(AllSVMDevices);
}
};
/// Defines the synch scope model for HIP.
class AtomicScopeHIPModel : public AtomicScopeModel {
public:
/// The enum values match the pre-defined macros
/// __HIP_MEMORY_SCOPE_*, which are used to define memory_scope_*
/// enums in hip-c.h.
enum ID {
SingleThread = 1,
Wavefront = 2,
Workgroup = 3,
Agent = 4,
System = 5,
Last = System
};
AtomicScopeHIPModel() {}
SyncScope map(unsigned S) const override {
switch (static_cast<ID>(S)) {
case SingleThread:
return SyncScope::HIPSingleThread;
case Wavefront:
return SyncScope::HIPWavefront;
case Workgroup:
return SyncScope::HIPWorkgroup;
case Agent:
return SyncScope::HIPAgent;
case System:
return SyncScope::HIPSystem;
}
llvm_unreachable("Invalid language synch scope value");
}
bool isValid(unsigned S) const override {
return S >= static_cast<unsigned>(SingleThread) &&
S <= static_cast<unsigned>(Last);
}
ArrayRef<unsigned> getRuntimeValues() const override {
static_assert(Last == System, "Does not include all synch scopes");
static const unsigned Scopes[] = {
static_cast<unsigned>(SingleThread), static_cast<unsigned>(Wavefront),
static_cast<unsigned>(Workgroup), static_cast<unsigned>(Agent),
static_cast<unsigned>(System)};
return llvm::makeArrayRef(Scopes);
}
unsigned getFallBackValue() const override {
return static_cast<unsigned>(System);
}
};
inline std::unique_ptr<AtomicScopeModel>
AtomicScopeModel::create(AtomicScopeModelKind K) {
switch (K) {
case AtomicScopeModelKind::None:
return std::unique_ptr<AtomicScopeModel>{};
case AtomicScopeModelKind::OpenCL:
return std::make_unique<AtomicScopeOpenCLModel>();
case AtomicScopeModelKind::HIP:
return std::make_unique<AtomicScopeHIPModel>();
}
llvm_unreachable("Invalid atomic scope model kind");
}
} // namespace clang
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|