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