287 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// The openmp plugins depend on extern libraries. These can be used via:10// - bitcode file statically linked11// - (relocatable) object file statically linked12// - static library13// - dynamic library, linked at build time14// - dynamic library, loaded at application run time by dlopen15//16// This file factors out most boilerplate for using a dlopened library.17// - Function symbols are generated that are statically linked against18// - The dlopen can be done implicitly when initializing the library19// - dlsym lookups are done once and cached20// - The abstraction is very thin to permit varied uses of the library21//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 bespoke30// 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 the37// dynamic library would do, with the right function types.38//39//===----------------------------------------------------------------------===//40 41#ifndef OMPTARGET_SHARED_DLWRAP_H42#define OMPTARGET_SHARED_DLWRAP_H43 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 an50// implementation of that function51#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 code74//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_INITIALIZE85#define DLWRAP_FINALIZE() DLWRAP_FINALIZE_IMPL()86 87// Implementation details follow.88 89namespace dlwrap {90 91// Extract return / argument types from address of function symbol92template <typename F> struct trait;93template <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 103namespace type {104// Book keeping is by type specialization105 106template <size_t S> struct count {107 static constexpr size_t N = count<S - 1>::N;108};109 110template <> struct count<0> { static constexpr size_t N = 0; };111 112// Get a constexpr size_t ID, starts at zero113#define DLWRAP_ID() (dlwrap::type::count<__LINE__>::N)114 115// Increment value returned by DLWRAP_ID116#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 121template <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 type127 128template <size_t N, size_t... Is>129constexpr std::array<const char *, N> static getSymbolArray(130 std::index_sequence<Is...>) {131 return {{dlwrap::type::symbol<Is>::call()...}};132}133 134template <size_t Requested, size_t Required> constexpr void verboseAssert() {135 static_assert(Requested == Required, "Arity Error");136}137 138} // namespace dlwrap139 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_H287