[Orc] It's not valid to pass a null resolver to addModuleSet. Use a no-op
[oota-llvm.git] / include / llvm / ExecutionEngine / Orc / IndirectionUtils.h
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
14 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
16
17 #include "JITSymbol.h"
18 #include "LambdaResolver.h"
19 #include "llvm/ADT/DenseSet.h"
20 #include "llvm/ExecutionEngine/RuntimeDyld.h"
21 #include "llvm/IR/IRBuilder.h"
22 #include "llvm/IR/Mangler.h"
23 #include "llvm/IR/Module.h"
24 #include <sstream>
25
26 namespace llvm {
27 namespace orc {
28
29 /// @brief Base class for JITLayer independent aspects of
30 ///        JITCompileCallbackManager.
31 class JITCompileCallbackManagerBase {
32 public:
33
34   typedef std::function<TargetAddress()> CompileFtor;
35   typedef std::function<void(TargetAddress)> UpdateFtor;
36
37   /// @brief Handle to a newly created compile callback. Can be used to get an
38   ///        IR constant representing the address of the trampoline, and to set
39   ///        the compile and update actions for the callback.
40   class CompileCallbackInfo {
41   public:
42     CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile,
43                         UpdateFtor &Update)
44       : Addr(Addr), Compile(Compile), Update(Update) {}
45
46     TargetAddress getAddress() const { return Addr; }
47     void setCompileAction(CompileFtor Compile) {
48       this->Compile = std::move(Compile);
49     }
50     void setUpdateAction(UpdateFtor Update) {
51       this->Update = std::move(Update);
52     }
53   private:
54     TargetAddress Addr;
55     CompileFtor &Compile;
56     UpdateFtor &Update;
57   };
58
59   /// @brief Construct a JITCompileCallbackManagerBase.
60   /// @param ErrorHandlerAddress The address of an error handler in the target
61   ///                            process to be used if a compile callback fails.
62   /// @param NumTrampolinesPerBlock Number of trampolines to emit if there is no
63   ///                             available trampoline when getCompileCallback is
64   ///                             called.
65   JITCompileCallbackManagerBase(TargetAddress ErrorHandlerAddress,
66                                 unsigned NumTrampolinesPerBlock)
67     : ErrorHandlerAddress(ErrorHandlerAddress),
68       NumTrampolinesPerBlock(NumTrampolinesPerBlock) {}
69
70   virtual ~JITCompileCallbackManagerBase() {}
71
72   /// @brief Execute the callback for the given trampoline id. Called by the JIT
73   ///        to compile functions on demand.
74   TargetAddress executeCompileCallback(TargetAddress TrampolineID) {
75     TrampolineMapT::iterator I = ActiveTrampolines.find(TrampolineID);
76     // FIXME: Also raise an error in the Orc error-handler when we finally have
77     //        one.
78     if (I == ActiveTrampolines.end())
79       return ErrorHandlerAddress;
80
81     // Found a callback handler. Yank this trampoline out of the active list and
82     // put it back in the available trampolines list, then try to run the
83     // handler's compile and update actions.
84     // Moving the trampoline ID back to the available list first means there's at
85     // least one available trampoline if the compile action triggers a request for
86     // a new one.
87     AvailableTrampolines.push_back(I->first);
88     auto CallbackHandler = std::move(I->second);
89     ActiveTrampolines.erase(I);
90
91     if (auto Addr = CallbackHandler.Compile()) {
92       CallbackHandler.Update(Addr);
93       return Addr;
94     }
95     return ErrorHandlerAddress;
96   }
97
98   /// @brief Get/create a compile callback with the given signature.
99   virtual CompileCallbackInfo getCompileCallback(LLVMContext &Context) = 0;
100
101 protected:
102
103   struct CallbackHandler {
104     CompileFtor Compile;
105     UpdateFtor Update;
106   };
107
108   TargetAddress ErrorHandlerAddress;
109   unsigned NumTrampolinesPerBlock;
110
111   typedef std::map<TargetAddress, CallbackHandler> TrampolineMapT;
112   TrampolineMapT ActiveTrampolines;
113   std::vector<TargetAddress> AvailableTrampolines;
114 };
115
116 /// @brief Manage compile callbacks.
117 template <typename JITLayerT, typename TargetT>
118 class JITCompileCallbackManager : public JITCompileCallbackManagerBase {
119 public:
120
121   /// @brief Construct a JITCompileCallbackManager.
122   /// @param JIT JIT layer to emit callback trampolines, etc. into.
123   /// @param Context LLVMContext to use for trampoline & resolve block modules.
124   /// @param ErrorHandlerAddress The address of an error handler in the target
125   ///                            process to be used if a compile callback fails.
126   /// @param NumTrampolinesPerBlock Number of trampolines to allocate whenever
127   ///                               there is no existing callback trampoline.
128   ///                               (Trampolines are allocated in blocks for
129   ///                               efficiency.)
130   JITCompileCallbackManager(JITLayerT &JIT, RuntimeDyld::MemoryManager &MemMgr,
131                             LLVMContext &Context,
132                             TargetAddress ErrorHandlerAddress,
133                             unsigned NumTrampolinesPerBlock)
134     : JITCompileCallbackManagerBase(ErrorHandlerAddress,
135                                     NumTrampolinesPerBlock),
136       JIT(JIT), MemMgr(MemMgr) {
137     emitResolverBlock(Context);
138   }
139
140   /// @brief Get/create a compile callback with the given signature.
141   CompileCallbackInfo getCompileCallback(LLVMContext &Context) final {
142     TargetAddress TrampolineAddr = getAvailableTrampolineAddr(Context);
143     auto &CallbackHandler =
144       this->ActiveTrampolines[TrampolineAddr];
145
146     return CompileCallbackInfo(TrampolineAddr, CallbackHandler.Compile,
147                                CallbackHandler.Update);
148   }
149
150 private:
151
152   std::vector<std::unique_ptr<Module>>
153   SingletonSet(std::unique_ptr<Module> M) {
154     std::vector<std::unique_ptr<Module>> Ms;
155     Ms.push_back(std::move(M));
156     return Ms;
157   }
158
159   void emitResolverBlock(LLVMContext &Context) {
160     std::unique_ptr<Module> M(new Module("resolver_block_module",
161                                          Context));
162     TargetT::insertResolverBlock(*M, *this);
163     auto NonResolver =
164       createLambdaResolver(
165           [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
166             llvm_unreachable("External symbols in resolver block?");
167           },
168           [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
169             llvm_unreachable("Dylib symbols in resolver block?");
170           });
171     auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr,
172                               std::move(NonResolver));
173     JIT.emitAndFinalize(H);
174     auto ResolverBlockSymbol =
175       JIT.findSymbolIn(H, TargetT::ResolverBlockName, false);
176     assert(ResolverBlockSymbol && "Failed to insert resolver block");
177     ResolverBlockAddr = ResolverBlockSymbol.getAddress();
178   }
179
180   TargetAddress getAvailableTrampolineAddr(LLVMContext &Context) {
181     if (this->AvailableTrampolines.empty())
182       grow(Context);
183     assert(!this->AvailableTrampolines.empty() &&
184            "Failed to grow available trampolines.");
185     TargetAddress TrampolineAddr = this->AvailableTrampolines.back();
186     this->AvailableTrampolines.pop_back();
187     return TrampolineAddr;
188   }
189
190   void grow(LLVMContext &Context) {
191     assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
192     std::unique_ptr<Module> M(new Module("trampoline_block", Context));
193     auto GetLabelName =
194       TargetT::insertCompileCallbackTrampolines(*M, ResolverBlockAddr,
195                                                 this->NumTrampolinesPerBlock,
196                                                 this->ActiveTrampolines.size());
197     auto NonResolver =
198       createLambdaResolver(
199           [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
200             llvm_unreachable("External symbols in trampoline block?");
201           },
202           [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
203             llvm_unreachable("Dylib symbols in trampoline block?");
204           });
205     auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr,
206                               std::move(NonResolver));
207     JIT.emitAndFinalize(H);
208     for (unsigned I = 0; I < this->NumTrampolinesPerBlock; ++I) {
209       std::string Name = GetLabelName(I);
210       auto TrampolineSymbol = JIT.findSymbolIn(H, Name, false);
211       assert(TrampolineSymbol && "Failed to emit trampoline.");
212       this->AvailableTrampolines.push_back(TrampolineSymbol.getAddress());
213     }
214   }
215
216   JITLayerT &JIT;
217   RuntimeDyld::MemoryManager &MemMgr;
218   TargetAddress ResolverBlockAddr;
219 };
220
221 /// @brief Get an update functor that updates the value of a named function
222 ///        pointer.
223 template <typename JITLayerT>
224 JITCompileCallbackManagerBase::UpdateFtor
225 getLocalFPUpdater(JITLayerT &JIT, typename JITLayerT::ModuleSetHandleT H,
226                   std::string Name) {
227     // FIXME: Move-capture Name once we can use C++14.
228     return [=,&JIT](TargetAddress Addr) {
229       auto FPSym = JIT.findSymbolIn(H, Name, true);
230       assert(FPSym && "Cannot find function pointer to update.");
231       void *FPAddr = reinterpret_cast<void*>(
232                        static_cast<uintptr_t>(FPSym.getAddress()));
233       memcpy(FPAddr, &Addr, sizeof(uintptr_t));
234     };
235   }
236
237 /// @brief Build a function pointer of FunctionType with the given constant
238 ///        address.
239 ///
240 ///   Usage example: Turn a trampoline address into a function pointer constant
241 /// for use in a stub.
242 Constant* createIRTypedAddress(FunctionType &FT, TargetAddress Addr);
243
244 /// @brief Create a function pointer with the given type, name, and initializer
245 ///        in the given Module.
246 GlobalVariable* createImplPointer(PointerType &PT, Module &M,
247                                   const Twine &Name, Constant *Initializer);
248
249 /// @brief Turn a function declaration into a stub function that makes an
250 ///        indirect call using the given function pointer.
251 void makeStub(Function &F, GlobalVariable &ImplPointer);
252
253 typedef std::map<Module*, DenseSet<const GlobalValue*>> ModulePartitionMap;
254
255 /// @brief Extract subsections of a Module into the given Module according to
256 ///        the given ModulePartitionMap.
257 void partition(Module &M, const ModulePartitionMap &PMap);
258
259 /// @brief Struct for trivial "complete" partitioning of a module.
260 class FullyPartitionedModule {
261 public:
262   std::unique_ptr<Module> GlobalVars;
263   std::unique_ptr<Module> Commons;
264   std::vector<std::unique_ptr<Module>> Functions;
265
266   FullyPartitionedModule() = default;
267   FullyPartitionedModule(FullyPartitionedModule &&S)
268       : GlobalVars(std::move(S.GlobalVars)), Commons(std::move(S.Commons)),
269         Functions(std::move(S.Functions)) {}
270 };
271
272 /// @brief Extract every function in M into a separate module.
273 FullyPartitionedModule fullyPartition(Module &M);
274
275 } // End namespace orc.
276 } // End namespace llvm.
277
278 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H