LLVM 23.0.0git
Registry.h
Go to the documentation of this file.
1//=== Registry.h - Linker-supported plugin registries -----------*- 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// Defines a registry template for discovering pluggable modules.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_SUPPORT_REGISTRY_H
14#define LLVM_SUPPORT_REGISTRY_H
15
16#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/StringRef.h"
22#include <memory>
23
24namespace llvm {
25/// A simple registry entry which provides only a name, description, and
26/// an `CtorParamTypes&&` variadic parameterized constructor.
27template <typename T, typename... CtorParamTypes> class SimpleRegistryEntry {
28 using FactoryFnRef = function_ref<std::unique_ptr<T>(CtorParamTypes &&...)>;
29 StringRef Name, Desc;
30 FactoryFnRef Ctor;
31
32public:
34 : Name(N), Desc(D), Ctor(C) {}
35
36 StringRef getName() const { return Name; }
37 StringRef getDesc() const { return Desc; }
38 std::unique_ptr<T> instantiate(CtorParamTypes &&...Params) const {
39 return Ctor(std::forward<CtorParamTypes>(Params)...);
40 }
41};
42
43template <typename T, typename... CtorParamTypes> class Registry;
44namespace detail {
45template <typename R> struct IsRegistryType : std::false_type {};
46template <typename T, typename... CtorParamTypes>
47struct IsRegistryType<Registry<T, CtorParamTypes...>> : std::true_type {};
48
49/// The endpoint to the instance to hold registered components by a linked list.
50///
51/// This is split out from `Registry<T>` to guard against absence of or error in
52/// an explicit instantiation, which causes an implicit instantiation.
53/// Such instantiation breaks dylib buils on Windows because a reference to a
54/// non dllimport-ed implicitly instantiated global variable can't be shared
55/// across a DLL boundary.
56template <typename R> struct RegistryLinkListStorage {
57 typename R::node *Head;
58 typename R::node *Tail;
59};
60
61/// The accessor to the endpoint.
62///
63/// ATTENTION: Be careful when attempting to "refactor" or "simplify" this.
64///
65/// - This shall not be a member of `RegistryLinkList`, to control instantiation
66/// timing separately.
67///
68/// - The body also shall not be inlined here; otherwise, the guard from a
69/// missed explicit instantiation definition won't work.
70///
71/// - Use an accessor function that returns a reference to a function-local
72/// static variable, rather than using a variable template or a static member
73/// variable in a class template directly since functions can be imported
74/// without the `dllimport` annotation.
76
77/// Utility to guard against missing declarations or mismatched use of
78/// `LLVM_DECLARE_REGISTRY` and `LLVM_INSTANTIATE_REGISTRY`.
79template <typename R>
80struct RegistryLinkListDeclarationMarker : std::false_type {};
81} // namespace detail
82
83/// A global registry used in conjunction with static constructors to make
84/// pluggable components (like targets or garbage collectors) "just work" when
85/// linked with an executable.
86///
87/// To provide a Registry interface, follow these steps:
88///
89/// 1. Define your plugin base interface. The interface must have a virtual
90/// destructor and the appropriate dllexport/dllimport/visibility annotation.
91///
92/// namespace your_ns {
93/// class YOURLIB_ABI SomethingPluginBase {
94/// virtual ~SomethingPluginBase() = default;
95/// virtual void TheInterface() = 0;
96/// };
97/// }
98///
99/// 2. Declare an alias to your `Registry` for convenience.
100///
101/// namespace your_ns {
102/// using YourRegistry = llvm::Registry<SomethingPluginBase>;
103/// }
104///
105/// 3. Declare the specialization of the `Registry` with `LLVM_DECLARE_REGISTRY`
106/// in the global namespace. The declaration must be placed before any use of
107/// the `YourRegistry`.
108///
109/// LLVM_DECLARE_REGISTRY(your_ns::YourRegistry)
110///
111/// 4. In a .cpp file, define the specialization with `LLVM_DEFINE_REGISTRY`
112/// in the global namespace.
113///
114/// LLVM_DEFINE_REGISTRY(your_ns::YourRegistry)
115///
116template <typename T, typename... CtorParamTypes> class Registry {
117 static_assert(
119 "Trying to instantiate a wrong specialization 'Registry<Registry<...>>'");
120
121public:
122 using type = T;
123 using entry = SimpleRegistryEntry<T, CtorParamTypes...>;
124 static constexpr bool HasCtorParamTypes = sizeof...(CtorParamTypes) != 0;
125
126 class node;
127 class iterator;
128
129private:
130 Registry() = delete;
131
132 friend class node;
133
134public:
135 /// Node in linked list of entries.
136 ///
137 class node {
138 friend class iterator;
139 friend Registry<T, CtorParamTypes...>;
140
141 node *Next;
142 const entry &Val;
143
144 public:
145 node(const entry &V) : Next(nullptr), Val(V) {}
146 };
147
148 /// Add a node to the Registry: this is the interface between the plugin and
149 /// the executable.
150 ///
151 static void add_node(node *N) {
153 if (Tail)
154 Tail->Next = N;
155 else
156 Head = N;
157 Tail = N;
158 }
159
160 /// Iterators for registry entries.
161 ///
163 : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
164 const entry> {
165 const node *Cur;
166
167 public:
168 explicit iterator(const node *N) : Cur(N) {}
169
170 bool operator==(const iterator &That) const { return Cur == That.Cur; }
172 Cur = Cur->Next;
173 return *this;
174 }
175 const entry &operator*() const { return Cur->Val; }
176 };
177
178 static iterator begin() {
179 return iterator(detail::getRegistryLinkListInstance<Registry>().Head);
180 }
181 static iterator end() { return iterator(nullptr); }
182
184 return make_range(begin(), end());
185 }
186
187 /// A static registration template. Use like such:
188 ///
189 /// Registry<Collector>::Add<FancyGC>
190 /// X("fancy-gc", "Newfangled garbage collector.");
191 ///
192 template <typename V> class Add {
193 entry Entry;
194 node Node;
195
196 static std::unique_ptr<T> CtorFn(CtorParamTypes &&...Params) {
197 static_assert(std::has_virtual_destructor_v<T>);
198 return std::make_unique<V>(std::forward<CtorParamTypes>(Params)...);
199 }
200
201 public:
203 : Entry(Name, Desc, CtorFn), Node(Entry) {
204 add_node(&Node);
205 }
206 };
207};
208
209} // end namespace llvm
210
211/// Helper macro to declare registry class.
212///
213/// The `LLVM_ABI_EXPORT` (i.e. __delcpsec(dllexport) on Win32) attached to the
214/// declaration is mandatory since MSVC disallows adding dllexport after the
215/// first non-exported specialization declaration, and it is generally safe. All
216/// of link.exe, ld.bfd, and lld-link will attempt to import undefined symbols
217/// (including template specializations) from DLLs, even if the symbol is
218/// declared with dllexport, just like non-imported symbols. The dllimport
219/// attribute is not eligible here, since the specialization may or may not be
220/// defined in the same object, a static library, or an import library.
221#define LLVM_DECLARE_REGISTRY(REGISTRY_CLASS) \
222 namespace llvm::detail { \
223 template <> \
224 struct RegistryLinkListDeclarationMarker<REGISTRY_CLASS> : std::true_type { \
225 }; \
226 template <> \
227 LLVM_ABI_EXPORT RegistryLinkListStorage<REGISTRY_CLASS> & \
228 getRegistryLinkListInstance<REGISTRY_CLASS>(); \
229 }
230
231/// Helper macro to define registry class.
232///
233/// Technically, these macros don't instantiate `Registry` despite the name.
234/// They handle underlying storage that used by `Registry` indirectly, enforcing
235/// proper declarations/definitions by compilers or linkers. If you forget to
236/// place `LLVM_DEFINE_REGISTRY`, your linker will complain about a missing
237/// `getRegistryLinkListInstance` definiton.
238#define LLVM_DEFINE_REGISTRY(REGISTRY_CLASS) \
239 namespace llvm::detail { \
240 static_assert(RegistryLinkListDeclarationMarker<REGISTRY_CLASS>::value, \
241 "Missing matching registry delcaration of " #REGISTRY_CLASS \
242 ". Place `LLVM_DECLARE_REGISTRY(" #REGISTRY_CLASS \
243 ")` in a header."); \
244 template <> \
245 LLVM_ABI_EXPORT RegistryLinkListStorage<REGISTRY_CLASS> & \
246 getRegistryLinkListInstance<REGISTRY_CLASS>() { \
247 static RegistryLinkListStorage<REGISTRY_CLASS> Instance; \
248 return Instance; \
249 } \
250 }
251
252#define LLVM_DETAIL_INSTANTIATE_REGISTRY_1(ABITAG, REGISTRY_CLASS) \
253 LLVM_DECLARE_REGISTRY(REGISTRY_CLASS) \
254 LLVM_DEFINE_REGISTRY(REGISTRY_CLASS) \
255 namespace llvm { \
256 template class ABITAG Registry<REGISTRY_CLASS::type>; \
257 static_assert(!REGISTRY_CLASS::HasCtorParamTypes, \
258 "LLVM_INSTANTIATE_REGISTRY can't be used with extra " \
259 "constructor parameter types. Use " \
260 "LLVM_DECLARE/DEFINE_REGISTRY istead."); \
261 }
262
263/// Old style helper macro to instantiate registry class.
264///
265#ifdef _WIN32
266#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
267 LLVM_DETAIL_INSTANTIATE_REGISTRY_1(LLVM_ABI_EXPORT, REGISTRY_CLASS)
268#else
269#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
270 LLVM_DETAIL_INSTANTIATE_REGISTRY_1(, REGISTRY_CLASS)
271#endif
272
273#endif // LLVM_SUPPORT_REGISTRY_H
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define T
This file contains some templates that are useful if you are working with the STL at all.
Add(StringRef Name, StringRef Desc)
Definition Registry.h:202
const entry & operator*() const
Definition Registry.h:175
iterator(const node *N)
Definition Registry.h:168
iterator & operator++()
Definition Registry.h:171
bool operator==(const iterator &That) const
Definition Registry.h:170
Node in linked list of entries.
Definition Registry.h:137
friend class iterator
Definition Registry.h:138
node(const entry &V)
Definition Registry.h:145
A global registry used in conjunction with static constructors to make pluggable components (like tar...
Definition Registry.h:116
SimpleRegistryEntry< GCMetadataPrinter, CtorParamTypes... > entry
Definition Registry.h:123
static iterator begin()
Definition Registry.h:178
static constexpr bool HasCtorParamTypes
Definition Registry.h:124
static iterator_range< iterator > entries()
Definition Registry.h:183
static void add_node(node *N)
Add a node to the Registry: this is the interface between the plugin and the executable.
Definition Registry.h:151
static iterator end()
Definition Registry.h:181
A simple registry entry which provides only a name, description, and an CtorParamTypes&& variadic par...
Definition Registry.h:27
StringRef getName() const
Definition Registry.h:36
std::unique_ptr< T > instantiate(CtorParamTypes &&...Params) const
Definition Registry.h:38
StringRef getDesc() const
Definition Registry.h:37
SimpleRegistryEntry(StringRef N, StringRef D, FactoryFnRef C)
Definition Registry.h:33
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
An efficient, type-erasing, non-owning reference to a callable.
CRTP base class which implements the entire standard iterator facade in terms of a minimal subset of ...
Definition iterator.h:80
A range adaptor for a pair of iterators.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
Definition CallingConv.h:76
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
RegistryLinkListStorage< R > & getRegistryLinkListInstance()
The accessor to the endpoint.
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Op::Description Desc
MachinePassRegistry< typename RegisterRegAllocBase< T >::FunctionPassCtor > RegisterRegAllocBase< T >::Registry
RegisterRegAlloc's global Registry tracks allocator registration.
#define N
Utility to guard against missing declarations or mismatched use of LLVM_DECLARE_REGISTRY and LLVM_INS...
Definition Registry.h:80
The endpoint to the instance to hold registered components by a linked list.
Definition Registry.h:56