IndirectionUtils.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. //===-- IndirectionUtils.h - Utilities for adding indirections --*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // Contains utilities for adding indirections and breaking up modules.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
  14. #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
  15. #include "JITSymbol.h"
  16. #include "LambdaResolver.h"
  17. #include "llvm/ADT/DenseSet.h"
  18. #include "llvm/ExecutionEngine/RuntimeDyld.h"
  19. #include "llvm/IR/IRBuilder.h"
  20. #include "llvm/IR/Mangler.h"
  21. #include "llvm/IR/Module.h"
  22. #include "llvm/Transforms/Utils/ValueMapper.h"
  23. #include <sstream>
  24. namespace llvm {
  25. namespace orc {
  26. /// @brief Base class for JITLayer independent aspects of
  27. /// JITCompileCallbackManager.
  28. class JITCompileCallbackManagerBase {
  29. public:
  30. typedef std::function<TargetAddress()> CompileFtor;
  31. /// @brief Handle to a newly created compile callback. Can be used to get an
  32. /// IR constant representing the address of the trampoline, and to set
  33. /// the compile action for the callback.
  34. class CompileCallbackInfo {
  35. public:
  36. CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile)
  37. : Addr(Addr), Compile(Compile) {}
  38. TargetAddress getAddress() const { return Addr; }
  39. void setCompileAction(CompileFtor Compile) {
  40. this->Compile = std::move(Compile);
  41. }
  42. private:
  43. TargetAddress Addr;
  44. CompileFtor &Compile;
  45. };
  46. /// @brief Construct a JITCompileCallbackManagerBase.
  47. /// @param ErrorHandlerAddress The address of an error handler in the target
  48. /// process to be used if a compile callback fails.
  49. /// @param NumTrampolinesPerBlock Number of trampolines to emit if there is no
  50. /// available trampoline when getCompileCallback is
  51. /// called.
  52. JITCompileCallbackManagerBase(TargetAddress ErrorHandlerAddress,
  53. unsigned NumTrampolinesPerBlock)
  54. : ErrorHandlerAddress(ErrorHandlerAddress),
  55. NumTrampolinesPerBlock(NumTrampolinesPerBlock) {}
  56. virtual ~JITCompileCallbackManagerBase() {}
  57. /// @brief Execute the callback for the given trampoline id. Called by the JIT
  58. /// to compile functions on demand.
  59. TargetAddress executeCompileCallback(TargetAddress TrampolineAddr) {
  60. auto I = ActiveTrampolines.find(TrampolineAddr);
  61. // FIXME: Also raise an error in the Orc error-handler when we finally have
  62. // one.
  63. if (I == ActiveTrampolines.end())
  64. return ErrorHandlerAddress;
  65. // Found a callback handler. Yank this trampoline out of the active list and
  66. // put it back in the available trampolines list, then try to run the
  67. // handler's compile and update actions.
  68. // Moving the trampoline ID back to the available list first means there's at
  69. // least one available trampoline if the compile action triggers a request for
  70. // a new one.
  71. auto Compile = std::move(I->second);
  72. ActiveTrampolines.erase(I);
  73. AvailableTrampolines.push_back(TrampolineAddr);
  74. if (auto Addr = Compile())
  75. return Addr;
  76. return ErrorHandlerAddress;
  77. }
  78. /// @brief Reserve a compile callback.
  79. virtual CompileCallbackInfo getCompileCallback(LLVMContext &Context) = 0;
  80. /// @brief Get a CompileCallbackInfo for an existing callback.
  81. CompileCallbackInfo getCompileCallbackInfo(TargetAddress TrampolineAddr) {
  82. auto I = ActiveTrampolines.find(TrampolineAddr);
  83. assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
  84. return CompileCallbackInfo(I->first, I->second);
  85. }
  86. /// @brief Release a compile callback.
  87. ///
  88. /// Note: Callbacks are auto-released after they execute. This method should
  89. /// only be called to manually release a callback that is not going to
  90. /// execute.
  91. void releaseCompileCallback(TargetAddress TrampolineAddr) {
  92. auto I = ActiveTrampolines.find(TrampolineAddr);
  93. assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
  94. ActiveTrampolines.erase(I);
  95. AvailableTrampolines.push_back(TrampolineAddr);
  96. }
  97. protected:
  98. TargetAddress ErrorHandlerAddress;
  99. unsigned NumTrampolinesPerBlock;
  100. typedef std::map<TargetAddress, CompileFtor> TrampolineMapT;
  101. TrampolineMapT ActiveTrampolines;
  102. std::vector<TargetAddress> AvailableTrampolines;
  103. };
  104. /// @brief Manage compile callbacks.
  105. template <typename JITLayerT, typename TargetT>
  106. class JITCompileCallbackManager : public JITCompileCallbackManagerBase {
  107. public:
  108. /// @brief Construct a JITCompileCallbackManager.
  109. /// @param JIT JIT layer to emit callback trampolines, etc. into.
  110. /// @param Context LLVMContext to use for trampoline & resolve block modules.
  111. /// @param ErrorHandlerAddress The address of an error handler in the target
  112. /// process to be used if a compile callback fails.
  113. /// @param NumTrampolinesPerBlock Number of trampolines to allocate whenever
  114. /// there is no existing callback trampoline.
  115. /// (Trampolines are allocated in blocks for
  116. /// efficiency.)
  117. JITCompileCallbackManager(JITLayerT &JIT, RuntimeDyld::MemoryManager &MemMgr,
  118. LLVMContext &Context,
  119. TargetAddress ErrorHandlerAddress,
  120. unsigned NumTrampolinesPerBlock)
  121. : JITCompileCallbackManagerBase(ErrorHandlerAddress,
  122. NumTrampolinesPerBlock),
  123. JIT(JIT), MemMgr(MemMgr) {
  124. emitResolverBlock(Context);
  125. }
  126. /// @brief Get/create a compile callback with the given signature.
  127. CompileCallbackInfo getCompileCallback(LLVMContext &Context) final {
  128. TargetAddress TrampolineAddr = getAvailableTrampolineAddr(Context);
  129. auto &Compile = this->ActiveTrampolines[TrampolineAddr];
  130. return CompileCallbackInfo(TrampolineAddr, Compile);
  131. }
  132. private:
  133. std::vector<std::unique_ptr<Module>>
  134. SingletonSet(std::unique_ptr<Module> M) {
  135. std::vector<std::unique_ptr<Module>> Ms;
  136. Ms.push_back(std::move(M));
  137. return Ms;
  138. }
  139. void emitResolverBlock(LLVMContext &Context) {
  140. std::unique_ptr<Module> M(new Module("resolver_block_module",
  141. Context));
  142. TargetT::insertResolverBlock(*M, *this);
  143. auto NonResolver =
  144. createLambdaResolver(
  145. [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
  146. llvm_unreachable("External symbols in resolver block?");
  147. },
  148. [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
  149. llvm_unreachable("Dylib symbols in resolver block?");
  150. });
  151. auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr,
  152. std::move(NonResolver));
  153. JIT.emitAndFinalize(H);
  154. auto ResolverBlockSymbol =
  155. JIT.findSymbolIn(H, TargetT::ResolverBlockName, false);
  156. assert(ResolverBlockSymbol && "Failed to insert resolver block");
  157. ResolverBlockAddr = ResolverBlockSymbol.getAddress();
  158. }
  159. TargetAddress getAvailableTrampolineAddr(LLVMContext &Context) {
  160. if (this->AvailableTrampolines.empty())
  161. grow(Context);
  162. assert(!this->AvailableTrampolines.empty() &&
  163. "Failed to grow available trampolines.");
  164. TargetAddress TrampolineAddr = this->AvailableTrampolines.back();
  165. this->AvailableTrampolines.pop_back();
  166. return TrampolineAddr;
  167. }
  168. void grow(LLVMContext &Context) {
  169. assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
  170. std::unique_ptr<Module> M(new Module("trampoline_block", Context));
  171. auto GetLabelName =
  172. TargetT::insertCompileCallbackTrampolines(*M, ResolverBlockAddr,
  173. this->NumTrampolinesPerBlock,
  174. this->ActiveTrampolines.size());
  175. auto NonResolver =
  176. createLambdaResolver(
  177. [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
  178. llvm_unreachable("External symbols in trampoline block?");
  179. },
  180. [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
  181. llvm_unreachable("Dylib symbols in trampoline block?");
  182. });
  183. auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr,
  184. std::move(NonResolver));
  185. JIT.emitAndFinalize(H);
  186. for (unsigned I = 0; I < this->NumTrampolinesPerBlock; ++I) {
  187. std::string Name = GetLabelName(I);
  188. auto TrampolineSymbol = JIT.findSymbolIn(H, Name, false);
  189. assert(TrampolineSymbol && "Failed to emit trampoline.");
  190. this->AvailableTrampolines.push_back(TrampolineSymbol.getAddress());
  191. }
  192. }
  193. JITLayerT &JIT;
  194. RuntimeDyld::MemoryManager &MemMgr;
  195. TargetAddress ResolverBlockAddr;
  196. };
  197. /// @brief Build a function pointer of FunctionType with the given constant
  198. /// address.
  199. ///
  200. /// Usage example: Turn a trampoline address into a function pointer constant
  201. /// for use in a stub.
  202. Constant* createIRTypedAddress(FunctionType &FT, TargetAddress Addr);
  203. /// @brief Create a function pointer with the given type, name, and initializer
  204. /// in the given Module.
  205. GlobalVariable* createImplPointer(PointerType &PT, Module &M,
  206. const Twine &Name, Constant *Initializer);
  207. /// @brief Turn a function declaration into a stub function that makes an
  208. /// indirect call using the given function pointer.
  209. void makeStub(Function &F, GlobalVariable &ImplPointer);
  210. /// @brief Raise linkage types and rename as necessary to ensure that all
  211. /// symbols are accessible for other modules.
  212. ///
  213. /// This should be called before partitioning a module to ensure that the
  214. /// partitions retain access to each other's symbols.
  215. void makeAllSymbolsExternallyAccessible(Module &M);
  216. /// @brief Clone a function declaration into a new module.
  217. ///
  218. /// This function can be used as the first step towards creating a callback
  219. /// stub (see makeStub), or moving a function body (see moveFunctionBody).
  220. ///
  221. /// If the VMap argument is non-null, a mapping will be added between F and
  222. /// the new declaration, and between each of F's arguments and the new
  223. /// declaration's arguments. This map can then be passed in to moveFunction to
  224. /// move the function body if required. Note: When moving functions between
  225. /// modules with these utilities, all decls should be cloned (and added to a
  226. /// single VMap) before any bodies are moved. This will ensure that references
  227. /// between functions all refer to the versions in the new module.
  228. Function* cloneFunctionDecl(Module &Dst, const Function &F,
  229. ValueToValueMapTy *VMap = nullptr);
  230. /// @brief Move the body of function 'F' to a cloned function declaration in a
  231. /// different module (See related cloneFunctionDecl).
  232. ///
  233. /// If the target function declaration is not supplied via the NewF parameter
  234. /// then it will be looked up via the VMap.
  235. ///
  236. /// This will delete the body of function 'F' from its original parent module,
  237. /// but leave its declaration.
  238. void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
  239. ValueMaterializer *Materializer = nullptr,
  240. Function *NewF = nullptr);
  241. /// @brief Clone a global variable declaration into a new module.
  242. GlobalVariable* cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
  243. ValueToValueMapTy *VMap = nullptr);
  244. /// @brief Move global variable GV from its parent module to cloned global
  245. /// declaration in a different module.
  246. ///
  247. /// If the target global declaration is not supplied via the NewGV parameter
  248. /// then it will be looked up via the VMap.
  249. ///
  250. /// This will delete the initializer of GV from its original parent module,
  251. /// but leave its declaration.
  252. void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
  253. ValueToValueMapTy &VMap,
  254. ValueMaterializer *Materializer = nullptr,
  255. GlobalVariable *NewGV = nullptr);
  256. } // End namespace orc.
  257. } // End namespace llvm.
  258. #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H