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 OpenCLWorkGroup,
44 OpenCLDevice,
45 OpenCLAllSVMDevices,
46 OpenCLSubGroup,
47 Last = OpenCLSubGroup
48 };
49
getAsString(SyncScope S)50 inline llvm::StringRef getAsString(SyncScope S) {
51 switch (S) {
52 case SyncScope::OpenCLWorkGroup:
53 return "opencl_workgroup";
54 case SyncScope::OpenCLDevice:
55 return "opencl_device";
56 case SyncScope::OpenCLAllSVMDevices:
57 return "opencl_allsvmdevices";
58 case SyncScope::OpenCLSubGroup:
59 return "opencl_subgroup";
60 }
61 llvm_unreachable("Invalid synch scope");
62 }
63
64 /// Defines the kind of atomic scope models.
65 enum class AtomicScopeModelKind { None, OpenCL };
66
67 /// Defines the interface for synch scope model.
68 class AtomicScopeModel {
69 public:
~AtomicScopeModel()70 virtual ~AtomicScopeModel() {}
71 /// Maps language specific synch scope values to internal
72 /// SyncScope enum.
73 virtual SyncScope map(unsigned S) const = 0;
74
75 /// Check if the compile-time constant synch scope value
76 /// is valid.
77 virtual bool isValid(unsigned S) const = 0;
78
79 /// Get all possible synch scope values that might be
80 /// encountered at runtime for the current language.
81 virtual ArrayRef<unsigned> getRuntimeValues() const = 0;
82
83 /// If atomic builtin function is called with invalid
84 /// synch scope value at runtime, it will fall back to a valid
85 /// synch scope value returned by this function.
86 virtual unsigned getFallBackValue() const = 0;
87
88 /// Create an atomic scope model by AtomicScopeModelKind.
89 /// \return an empty std::unique_ptr for AtomicScopeModelKind::None.
90 static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K);
91 };
92
93 /// Defines the synch scope model for OpenCL.
94 class AtomicScopeOpenCLModel : public AtomicScopeModel {
95 public:
96 /// The enum values match the pre-defined macros
97 /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_*
98 /// enums in opencl-c-base.h.
99 enum ID {
100 WorkGroup = 1,
101 Device = 2,
102 AllSVMDevices = 3,
103 SubGroup = 4,
104 Last = SubGroup
105 };
106
AtomicScopeOpenCLModel()107 AtomicScopeOpenCLModel() {}
108
map(unsigned S)109 SyncScope map(unsigned S) const override {
110 switch (static_cast<ID>(S)) {
111 case WorkGroup:
112 return SyncScope::OpenCLWorkGroup;
113 case Device:
114 return SyncScope::OpenCLDevice;
115 case AllSVMDevices:
116 return SyncScope::OpenCLAllSVMDevices;
117 case SubGroup:
118 return SyncScope::OpenCLSubGroup;
119 }
120 llvm_unreachable("Invalid language synch scope value");
121 }
122
isValid(unsigned S)123 bool isValid(unsigned S) const override {
124 return S >= static_cast<unsigned>(WorkGroup) &&
125 S <= static_cast<unsigned>(Last);
126 }
127
getRuntimeValues()128 ArrayRef<unsigned> getRuntimeValues() const override {
129 static_assert(Last == SubGroup, "Does not include all synch scopes");
130 static const unsigned Scopes[] = {
131 static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device),
132 static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)};
133 return llvm::makeArrayRef(Scopes);
134 }
135
getFallBackValue()136 unsigned getFallBackValue() const override {
137 return static_cast<unsigned>(AllSVMDevices);
138 }
139 };
140
141 inline std::unique_ptr<AtomicScopeModel>
create(AtomicScopeModelKind K)142 AtomicScopeModel::create(AtomicScopeModelKind K) {
143 switch (K) {
144 case AtomicScopeModelKind::None:
145 return std::unique_ptr<AtomicScopeModel>{};
146 case AtomicScopeModelKind::OpenCL:
147 return std::make_unique<AtomicScopeOpenCLModel>();
148 }
149 llvm_unreachable("Invalid atomic scope model kind");
150 }
151 }
152
153 #endif
154