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