1//===------ IRCompileLayer.h -- Eagerly compile IR for JIT ------*- 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 the definition for a basic, eagerly compiling layer of the JIT.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H
15#define LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H
16
17#include "JITSymbol.h"
18#include "llvm/ExecutionEngine/ObjectCache.h"
19#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
20#include "llvm/Object/ObjectFile.h"
21#include <memory>
22
23namespace llvm {
24namespace orc {
25
26/// @brief Eager IR compiling layer.
27///
28///   This layer accepts sets of LLVM IR Modules (via addModuleSet). It
29/// immediately compiles each IR module to an object file (each IR Module is
30/// compiled separately). The resulting set of object files is then added to
31/// the layer below, which must implement the object layer concept.
32template <typename BaseLayerT> class IRCompileLayer {
33public:
34  typedef std::function<object::OwningBinary<object::ObjectFile>(Module &)>
35      CompileFtor;
36
37private:
38  typedef typename BaseLayerT::ObjSetHandleT ObjSetHandleT;
39
40  typedef std::vector<std::unique_ptr<object::ObjectFile>> OwningObjectVec;
41  typedef std::vector<std::unique_ptr<MemoryBuffer>> OwningBufferVec;
42
43public:
44  /// @brief Handle to a set of compiled modules.
45  typedef ObjSetHandleT ModuleSetHandleT;
46
47  /// @brief Construct an IRCompileLayer with the given BaseLayer, which must
48  ///        implement the ObjectLayer concept.
49  IRCompileLayer(BaseLayerT &BaseLayer, CompileFtor Compile)
50      : BaseLayer(BaseLayer), Compile(std::move(Compile)), ObjCache(nullptr) {}
51
52  /// @brief Set an ObjectCache to query before compiling.
53  void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; }
54
55  /// @brief Compile each module in the given module set, then add the resulting
56  ///        set of objects to the base layer along with the memory manager and
57  ///        symbol resolver.
58  ///
59  /// @return A handle for the added modules.
60  template <typename ModuleSetT, typename MemoryManagerPtrT,
61            typename SymbolResolverPtrT>
62  ModuleSetHandleT addModuleSet(ModuleSetT Ms,
63                                MemoryManagerPtrT MemMgr,
64                                SymbolResolverPtrT Resolver) {
65    OwningObjectVec Objects;
66    OwningBufferVec Buffers;
67
68    for (const auto &M : Ms) {
69      std::unique_ptr<object::ObjectFile> Object;
70      std::unique_ptr<MemoryBuffer> Buffer;
71
72      if (ObjCache)
73        std::tie(Object, Buffer) = tryToLoadFromObjectCache(*M).takeBinary();
74
75      if (!Object) {
76        std::tie(Object, Buffer) = Compile(*M).takeBinary();
77        if (ObjCache)
78          ObjCache->notifyObjectCompiled(&*M, Buffer->getMemBufferRef());
79      }
80
81      Objects.push_back(std::move(Object));
82      Buffers.push_back(std::move(Buffer));
83    }
84
85    ModuleSetHandleT H =
86      BaseLayer.addObjectSet(Objects, std::move(MemMgr), std::move(Resolver));
87
88    return H;
89  }
90
91  /// @brief Remove the module set associated with the handle H.
92  void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeObjectSet(H); }
93
94  /// @brief Search for the given named symbol.
95  /// @param Name The name of the symbol to search for.
96  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
97  /// @return A handle for the given named symbol, if it exists.
98  JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
99    return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
100  }
101
102  /// @brief Get the address of the given symbol in the context of the set of
103  ///        compiled modules represented by the handle H. This call is
104  ///        forwarded to the base layer's implementation.
105  /// @param H The handle for the module set to search in.
106  /// @param Name The name of the symbol to search for.
107  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
108  /// @return A handle for the given named symbol, if it is found in the
109  ///         given module set.
110  JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
111                         bool ExportedSymbolsOnly) {
112    return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
113  }
114
115  /// @brief Immediately emit and finalize the moduleOB set represented by the
116  ///        given handle.
117  /// @param H Handle for module set to emit/finalize.
118  void emitAndFinalize(ModuleSetHandleT H) {
119    BaseLayer.emitAndFinalize(H);
120  }
121
122private:
123  object::OwningBinary<object::ObjectFile>
124  tryToLoadFromObjectCache(const Module &M) {
125    std::unique_ptr<MemoryBuffer> ObjBuffer = ObjCache->getObject(&M);
126    if (!ObjBuffer)
127      return object::OwningBinary<object::ObjectFile>();
128
129    ErrorOr<std::unique_ptr<object::ObjectFile>> Obj =
130        object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
131    if (!Obj)
132      return object::OwningBinary<object::ObjectFile>();
133
134    return object::OwningBinary<object::ObjectFile>(std::move(*Obj),
135                                                    std::move(ObjBuffer));
136  }
137
138  BaseLayerT &BaseLayer;
139  CompileFtor Compile;
140  ObjectCache *ObjCache;
141};
142
143} // End namespace orc.
144} // End namespace llvm.
145
146#endif // LLVM_EXECUTIONENGINE_ORC_IRCOMPILINGLAYER_H
147