xref: /llvm-project/offload/plugins-nextgen/common/include/DLWrap.h (revision 330d8983d25d08580fc1642fea48b2473f47a9da)
1 //===-- Shared/DLWrap.h - Convenience wrapper for dlopen/dlsym --*- 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 // The openmp plugins depend on extern libraries. These can be used via:
10 //  - bitcode file statically linked
11 //  - (relocatable) object file statically linked
12 //  - static library
13 //  - dynamic library, linked at build time
14 //  - dynamic library, loaded at application run time by dlopen
15 //
16 // This file factors out most boilerplate for using a dlopened library.
17 // - Function symbols are generated that are statically linked against
18 // - The dlopen can be done implicitly when initializing the library
19 // - dlsym lookups are done once and cached
20 // - The abstraction is very thin to permit varied uses of the library
21 //
22 // Given int foo(char, double, void*);, writing DLWRAP(foo, 3) will expand to:
23 // int foo(char x0, double x1, void* x2) {
24 //   constexpr size_t index = id();
25 //   void * dlsymResult = pointer(index);
26 //   return ((int (*)(char, double, void*))dlsymResult)(x0, x1, x2);
27 // }
28 //
29 // Multiple calls to DLWRAP(symbol_name, arity) with bespoke
30 // initialization code that can use the thin abstraction:
31 // namespace dlwrap {
32 //   static size_t size();
33 //   static const char *symbol(size_t);
34 //   static void **pointer(size_t);
35 // }
36 // will compile to an object file that only exposes the symbols that the
37 // dynamic library would do, with the right function types.
38 //
39 //===----------------------------------------------------------------------===//
40 
41 #ifndef OMPTARGET_SHARED_DLWRAP_H
42 #define OMPTARGET_SHARED_DLWRAP_H
43 
44 #include <array>
45 #include <cstddef>
46 #include <tuple>
47 #include <type_traits>
48 
49 // Where symbol is a function, these expand to some book keeping and an
50 // implementation of that function
51 #define DLWRAP(SYMBOL, ARITY) DLWRAP_IMPL(SYMBOL, ARITY)
52 #define DLWRAP_INTERNAL(SYMBOL, ARITY) DLWRAP_INTERNAL_IMPL(SYMBOL, ARITY)
53 
54 // For example, given a prototype:
55 // int foo(char, double);
56 //
57 // DLWRAP(foo, 2) expands to:
58 //
59 // namespace dlwrap {
60 // struct foo_Trait : public dlwrap::trait<decltype(&foo)> {
61 //   using T = dlwrap::trait<decltype(&foo)>;
62 //   static T::FunctionType get() {
63 //     constexpr size_t Index = getIndex();
64 //     void *P = *dlwrap::pointer(Index);
65 //     return reinterpret_cast<T::FunctionType>(P);
66 //   }
67 // };
68 // }
69 // int foo(char x0, double x1) { return dlwrap::foo_Trait::get()(x0, x1); }
70 //
71 // DLWRAP_INTERNAL is similar, except the function it expands to is:
72 // static int dlwrap_foo(char x0, double x1) { ... }
73 // so that the function pointer call can be wrapped in library-specific code
74 //
75 // DLWRAP_INITIALIZE() declares static functions:
76 #define DLWRAP_INITIALIZE()                                                    \
77   namespace dlwrap {                                                           \
78   static size_t size();                                                        \
79   static const char *symbol(size_t); /* get symbol name in [0, size()) */      \
80   static void **                                                               \
81       pointer(size_t); /* get pointer to function pointer in [0, size()) */    \
82   }
83 
84 // DLWRAP_FINALIZE() implements the functions from DLWRAP_INITIALIZE
85 #define DLWRAP_FINALIZE() DLWRAP_FINALIZE_IMPL()
86 
87 // Implementation details follow.
88 
89 namespace dlwrap {
90 
91 // Extract return / argument types from address of function symbol
92 template <typename F> struct trait;
93 template <typename R, typename... Ts> struct trait<R (*)(Ts...)> {
94   constexpr static const size_t nargs = sizeof...(Ts);
95   typedef R ReturnType;
96   template <size_t i> struct arg {
97     typedef typename std::tuple_element<i, std::tuple<Ts...>>::type type;
98   };
99 
100   typedef R (*FunctionType)(Ts...);
101 };
102 
103 namespace type {
104 // Book keeping is by type specialization
105 
106 template <size_t S> struct count {
107   static constexpr size_t N = count<S - 1>::N;
108 };
109 
110 template <> struct count<0> { static constexpr size_t N = 0; };
111 
112 // Get a constexpr size_t ID, starts at zero
113 #define DLWRAP_ID() (dlwrap::type::count<__LINE__>::N)
114 
115 // Increment value returned by DLWRAP_ID
116 #define DLWRAP_INC()                                                           \
117   template <> struct dlwrap::type::count<__LINE__> {                           \
118     static constexpr size_t N = 1 + dlwrap::type::count<__LINE__ - 1>::N;      \
119   }
120 
121 template <size_t N> struct symbol;
122 #define DLWRAP_SYMBOL(SYMBOL, ID)                                              \
123   template <> struct dlwrap::type::symbol<ID> {                                \
124     static constexpr const char *call() { return #SYMBOL; }                    \
125   }
126 } // namespace type
127 
128 template <size_t N, size_t... Is>
129 constexpr std::array<const char *, N> static getSymbolArray(
130     std::index_sequence<Is...>) {
131   return {{dlwrap::type::symbol<Is>::call()...}};
132 }
133 
134 template <size_t Requested, size_t Required> constexpr void verboseAssert() {
135   static_assert(Requested == Required, "Arity Error");
136 }
137 
138 } // namespace dlwrap
139 
140 #define DLWRAP_INSTANTIATE(SYM_DEF, SYM_USE, ARITY)                            \
141   DLWRAP_INSTANTIATE_##ARITY(SYM_DEF, SYM_USE,                                 \
142                              dlwrap::trait<decltype(&SYM_USE)>)
143 
144 #define DLWRAP_FINALIZE_IMPL()                                                 \
145   static size_t dlwrap::size() { return DLWRAP_ID(); }                         \
146   static const char *dlwrap::symbol(size_t i) {                                \
147     static constexpr const std::array<const char *, DLWRAP_ID()>               \
148         dlwrap_symbols = getSymbolArray<DLWRAP_ID()>(                          \
149             std::make_index_sequence<DLWRAP_ID()>());                          \
150     return dlwrap_symbols[i];                                                  \
151   }                                                                            \
152   static void **dlwrap::pointer(size_t i) {                                    \
153     static std::array<void *, DLWRAP_ID()> dlwrap_pointers;                    \
154     return &dlwrap_pointers.data()[i];                                         \
155   }
156 
157 #define DLWRAP_COMMON(SYMBOL, ARITY)                                           \
158   DLWRAP_INC();                                                                \
159   DLWRAP_SYMBOL(SYMBOL, DLWRAP_ID() - 1);                                      \
160   namespace dlwrap {                                                           \
161   struct SYMBOL##_Trait : public dlwrap::trait<decltype(&SYMBOL)> {            \
162     using T = dlwrap::trait<decltype(&SYMBOL)>;                                \
163     static T::FunctionType get() {                                             \
164       verboseAssert<ARITY, trait<decltype(&SYMBOL)>::nargs>();                 \
165       constexpr size_t Index = DLWRAP_ID() - 1;                                \
166       void *P = *dlwrap::pointer(Index);                                       \
167       return reinterpret_cast<T::FunctionType>(P);                             \
168     }                                                                          \
169   };                                                                           \
170   }
171 
172 #define DLWRAP_IMPL(SYMBOL, ARITY)                                             \
173   DLWRAP_COMMON(SYMBOL, ARITY)                                                 \
174   DLWRAP_INSTANTIATE(SYMBOL, SYMBOL, ARITY)
175 
176 #define DLWRAP_INTERNAL_IMPL(SYMBOL, ARITY)                                    \
177   DLWRAP_COMMON(SYMBOL, ARITY)                                                 \
178   static DLWRAP_INSTANTIATE(dlwrap_##SYMBOL, SYMBOL, ARITY)
179 
180 #define DLWRAP_INSTANTIATE_0(SYM_DEF, SYM_USE, T)                              \
181   T::ReturnType SYM_DEF() { return dlwrap::SYM_USE##_Trait::get()(); }
182 #define DLWRAP_INSTANTIATE_1(SYM_DEF, SYM_USE, T)                              \
183   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0) {                \
184     return dlwrap::SYM_USE##_Trait::get()(x0);                                 \
185   }
186 #define DLWRAP_INSTANTIATE_2(SYM_DEF, SYM_USE, T)                              \
187   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
188                         typename T::template arg<1>::type x1) {                \
189     return dlwrap::SYM_USE##_Trait::get()(x0, x1);                             \
190   }
191 #define DLWRAP_INSTANTIATE_3(SYM_DEF, SYM_USE, T)                              \
192   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
193                         typename T::template arg<1>::type x1,                  \
194                         typename T::template arg<2>::type x2) {                \
195     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2);                         \
196   }
197 #define DLWRAP_INSTANTIATE_4(SYM_DEF, SYM_USE, T)                              \
198   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
199                         typename T::template arg<1>::type x1,                  \
200                         typename T::template arg<2>::type x2,                  \
201                         typename T::template arg<3>::type x3) {                \
202     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3);                     \
203   }
204 #define DLWRAP_INSTANTIATE_5(SYM_DEF, SYM_USE, T)                              \
205   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
206                         typename T::template arg<1>::type x1,                  \
207                         typename T::template arg<2>::type x2,                  \
208                         typename T::template arg<3>::type x3,                  \
209                         typename T::template arg<4>::type x4) {                \
210     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3, x4);                 \
211   }
212 #define DLWRAP_INSTANTIATE_6(SYM_DEF, SYM_USE, T)                              \
213   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
214                         typename T::template arg<1>::type x1,                  \
215                         typename T::template arg<2>::type x2,                  \
216                         typename T::template arg<3>::type x3,                  \
217                         typename T::template arg<4>::type x4,                  \
218                         typename T::template arg<5>::type x5) {                \
219     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3, x4, x5);             \
220   }
221 
222 #define DLWRAP_INSTANTIATE_7(SYM_DEF, SYM_USE, T)                              \
223   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
224                         typename T::template arg<1>::type x1,                  \
225                         typename T::template arg<2>::type x2,                  \
226                         typename T::template arg<3>::type x3,                  \
227                         typename T::template arg<4>::type x4,                  \
228                         typename T::template arg<5>::type x5,                  \
229                         typename T::template arg<6>::type x6) {                \
230     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3, x4, x5, x6);         \
231   }
232 
233 #define DLWRAP_INSTANTIATE_8(SYM_DEF, SYM_USE, T)                              \
234   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
235                         typename T::template arg<1>::type x1,                  \
236                         typename T::template arg<2>::type x2,                  \
237                         typename T::template arg<3>::type x3,                  \
238                         typename T::template arg<4>::type x4,                  \
239                         typename T::template arg<5>::type x5,                  \
240                         typename T::template arg<6>::type x6,                  \
241                         typename T::template arg<7>::type x7) {                \
242     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3, x4, x5, x6, x7);     \
243   }
244 #define DLWRAP_INSTANTIATE_9(SYM_DEF, SYM_USE, T)                              \
245   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
246                         typename T::template arg<1>::type x1,                  \
247                         typename T::template arg<2>::type x2,                  \
248                         typename T::template arg<3>::type x3,                  \
249                         typename T::template arg<4>::type x4,                  \
250                         typename T::template arg<5>::type x5,                  \
251                         typename T::template arg<6>::type x6,                  \
252                         typename T::template arg<7>::type x7,                  \
253                         typename T::template arg<8>::type x8) {                \
254     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3, x4, x5, x6, x7, x8); \
255   }
256 #define DLWRAP_INSTANTIATE_10(SYM_DEF, SYM_USE, T)                             \
257   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
258                         typename T::template arg<1>::type x1,                  \
259                         typename T::template arg<2>::type x2,                  \
260                         typename T::template arg<3>::type x3,                  \
261                         typename T::template arg<4>::type x4,                  \
262                         typename T::template arg<5>::type x5,                  \
263                         typename T::template arg<6>::type x6,                  \
264                         typename T::template arg<7>::type x7,                  \
265                         typename T::template arg<8>::type x8,                  \
266                         typename T::template arg<9>::type x9) {                \
267     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3, x4, x5, x6, x7, x8,  \
268                                           x9);                                 \
269   }
270 #define DLWRAP_INSTANTIATE_11(SYM_DEF, SYM_USE, T)                             \
271   T::ReturnType SYM_DEF(typename T::template arg<0>::type x0,                  \
272                         typename T::template arg<1>::type x1,                  \
273                         typename T::template arg<2>::type x2,                  \
274                         typename T::template arg<3>::type x3,                  \
275                         typename T::template arg<4>::type x4,                  \
276                         typename T::template arg<5>::type x5,                  \
277                         typename T::template arg<6>::type x6,                  \
278                         typename T::template arg<7>::type x7,                  \
279                         typename T::template arg<8>::type x8,                  \
280                         typename T::template arg<9>::type x9,                  \
281                         typename T::template arg<10>::type x10) {              \
282     return dlwrap::SYM_USE##_Trait::get()(x0, x1, x2, x3, x4, x5, x6, x7, x8,  \
283                                           x9, x10);                            \
284   }
285 
286 #endif // OMPTARGET_SHARED_DLWRAP_H
287