aboutsummaryrefslogtreecommitdiffstats
path: root/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h
blob: 6a4762217399ee237539aea22cc00eb1c1a78af0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//===------ IRCompileLayer.h -- Eagerly compile IR for JIT ------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Contains the definition for a basic, eagerly compiling layer of the JIT.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H
#define LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H

#include "JITSymbol.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/Object/ObjectFile.h"
#include <memory>

namespace llvm {
namespace orc {

/// @brief Eager IR compiling layer.
///
///   This layer accepts sets of LLVM IR Modules (via addModuleSet). It
/// immediately compiles each IR module to an object file (each IR Module is
/// compiled separately). The resulting set of object files is then added to
/// the layer below, which must implement the object layer concept.
template <typename BaseLayerT> class IRCompileLayer {
public:
  typedef std::function<object::OwningBinary<object::ObjectFile>(Module &)>
      CompileFtor;

private:
  typedef typename BaseLayerT::ObjSetHandleT ObjSetHandleT;

  typedef std::vector<std::unique_ptr<object::ObjectFile>> OwningObjectVec;
  typedef std::vector<std::unique_ptr<MemoryBuffer>> OwningBufferVec;

public:
  /// @brief Handle to a set of compiled modules.
  typedef ObjSetHandleT ModuleSetHandleT;

  /// @brief Construct an IRCompileLayer with the given BaseLayer, which must
  ///        implement the ObjectLayer concept.
  IRCompileLayer(BaseLayerT &BaseLayer, CompileFtor Compile)
      : BaseLayer(BaseLayer), Compile(std::move(Compile)), ObjCache(nullptr) {}

  /// @brief Set an ObjectCache to query before compiling.
  void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; }

  /// @brief Compile each module in the given module set, then then add the
  ///        resulting set of objects to the base layer, along with the memory
  //         manager MM.
  ///
  /// @return A handle for the added modules.
  template <typename ModuleSetT>
  ModuleSetHandleT addModuleSet(ModuleSetT Ms,
                                std::unique_ptr<RTDyldMemoryManager> MM) {
    OwningObjectVec Objects;
    OwningBufferVec Buffers;

    for (const auto &M : Ms) {
      std::unique_ptr<object::ObjectFile> Object;
      std::unique_ptr<MemoryBuffer> Buffer;

      if (ObjCache)
        std::tie(Object, Buffer) = tryToLoadFromObjectCache(*M).takeBinary();

      if (!Object) {
        std::tie(Object, Buffer) = Compile(*M).takeBinary();
        if (ObjCache)
          ObjCache->notifyObjectCompiled(&*M, Buffer->getMemBufferRef());
      }

      Objects.push_back(std::move(Object));
      Buffers.push_back(std::move(Buffer));
    }

    ModuleSetHandleT H =
      BaseLayer.addObjectSet(Objects, std::move(MM));

    BaseLayer.takeOwnershipOfBuffers(H, std::move(Buffers));

    return H;
  }

  /// @brief Remove the module set associated with the handle H.
  void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeObjectSet(H); }

  /// @brief Search for the given named symbol.
  /// @param Name The name of the symbol to search for.
  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
  /// @return A handle for the given named symbol, if it exists.
  JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
    return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
  }

  /// @brief Get the address of the given symbol in the context of the set of
  ///        compiled modules represented by the handle H. This call is
  ///        forwarded to the base layer's implementation.
  /// @param H The handle for the module set to search in.
  /// @param Name The name of the symbol to search for.
  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
  /// @return A handle for the given named symbol, if it is found in the
  ///         given module set.
  JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
                         bool ExportedSymbolsOnly) {
    return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
  }

  /// @brief Immediately emit and finalize the moduleOB set represented by the
  ///        given handle.
  /// @param H Handle for module set to emit/finalize.
  void emitAndFinalize(ModuleSetHandleT H) {
    BaseLayer.emitAndFinalize(H);
  }

private:
  object::OwningBinary<object::ObjectFile>
  tryToLoadFromObjectCache(const Module &M) {
    std::unique_ptr<MemoryBuffer> ObjBuffer = ObjCache->getObject(&M);
    if (!ObjBuffer)
      return object::OwningBinary<object::ObjectFile>();

    ErrorOr<std::unique_ptr<object::ObjectFile>> Obj =
        object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
    if (!Obj)
      return object::OwningBinary<object::ObjectFile>();

    return object::OwningBinary<object::ObjectFile>(std::move(*Obj),
                                                    std::move(ObjBuffer));
  }

  BaseLayerT &BaseLayer;
  CompileFtor Compile;
  ObjectCache *ObjCache;
};

} // End namespace orc.
} // End namespace llvm.

#endif // LLVM_EXECUTIONENGINE_ORC_IRCOMPILINGLAYER_H