annotate docs/tutorial/BuildingAJIT2.rst @ 144:488dcfcac50b

Added tag current for changeset 7859b39d8905
author mir3636
date Tue, 03 Apr 2018 19:13:59 +0900
parents 3a76565eade5
children c2174574ed3a
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1 =====================================================================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
2 Building a JIT: Adding Optimizations -- An introduction to ORC Layers
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
3 =====================================================================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
5 .. contents::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
6 :local:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
7
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
8 **This tutorial is under active development. It is incomplete and details may
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
9 change frequently.** Nonetheless we invite you to try it out as it stands, and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
10 we welcome any feedback.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
11
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
12 Chapter 2 Introduction
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
13 ======================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
14
134
3a76565eade5 update 5.0.1
mir3636
parents: 121
diff changeset
15 **Warning: This text is currently out of date due to ORC API updates.**
3a76565eade5 update 5.0.1
mir3636
parents: 121
diff changeset
16
3a76565eade5 update 5.0.1
mir3636
parents: 121
diff changeset
17 **The example code has been updated and can be used. The text will be updated
3a76565eade5 update 5.0.1
mir3636
parents: 121
diff changeset
18 once the API churn dies down.**
3a76565eade5 update 5.0.1
mir3636
parents: 121
diff changeset
19
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
20 Welcome to Chapter 2 of the "Building an ORC-based JIT in LLVM" tutorial. In
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
21 `Chapter 1 <BuildingAJIT1.html>`_ of this series we examined a basic JIT
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
22 class, KaleidoscopeJIT, that could take LLVM IR modules as input and produce
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
23 executable code in memory. KaleidoscopeJIT was able to do this with relatively
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
24 little code by composing two off-the-shelf *ORC layers*: IRCompileLayer and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
25 ObjectLinkingLayer, to do much of the heavy lifting.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
26
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
27 In this layer we'll learn more about the ORC layer concept by using a new layer,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
28 IRTransformLayer, to add IR optimization support to KaleidoscopeJIT.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
29
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
30 Optimizing Modules using the IRTransformLayer
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
31 =============================================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
32
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
33 In `Chapter 4 <LangImpl04.html>`_ of the "Implementing a language with LLVM"
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
34 tutorial series the llvm *FunctionPassManager* is introduced as a means for
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
35 optimizing LLVM IR. Interested readers may read that chapter for details, but
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
36 in short: to optimize a Module we create an llvm::FunctionPassManager
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
37 instance, configure it with a set of optimizations, then run the PassManager on
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
38 a Module to mutate it into a (hopefully) more optimized but semantically
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
39 equivalent form. In the original tutorial series the FunctionPassManager was
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
40 created outside the KaleidoscopeJIT and modules were optimized before being
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
41 added to it. In this Chapter we will make optimization a phase of our JIT
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
42 instead. For now this will provide us a motivation to learn more about ORC
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
43 layers, but in the long term making optimization part of our JIT will yield an
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
44 important benefit: When we begin lazily compiling code (i.e. deferring
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
45 compilation of each function until the first time it's run), having
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
46 optimization managed by our JIT will allow us to optimize lazily too, rather
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
47 than having to do all our optimization up-front.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
48
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
49 To add optimization support to our JIT we will take the KaleidoscopeJIT from
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
50 Chapter 1 and compose an ORC *IRTransformLayer* on top. We will look at how the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
51 IRTransformLayer works in more detail below, but the interface is simple: the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
52 constructor for this layer takes a reference to the layer below (as all layers
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
53 do) plus an *IR optimization function* that it will apply to each Module that
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
54 is added via addModule:
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
55
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
56 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
57
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
58 class KaleidoscopeJIT {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
59 private:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
60 std::unique_ptr<TargetMachine> TM;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
61 const DataLayout DL;
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
62 RTDyldObjectLinkingLayer<> ObjectLayer;
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
63 IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
64
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
65 using OptimizeFunction =
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
66 std::function<std::shared_ptr<Module>(std::shared_ptr<Module>)>;
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
67
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
68 IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
69
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
70 public:
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
71 using ModuleHandle = decltype(OptimizeLayer)::ModuleHandleT;
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
72
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
73 KaleidoscopeJIT()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
74 : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
75 ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
76 CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
77 OptimizeLayer(CompileLayer,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
78 [this](std::unique_ptr<Module> M) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
79 return optimizeModule(std::move(M));
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
80 }) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
81 llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
82 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
83
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
84 Our extended KaleidoscopeJIT class starts out the same as it did in Chapter 1,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
85 but after the CompileLayer we introduce a typedef for our optimization function.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
86 In this case we use a std::function (a handy wrapper for "function-like" things)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
87 from a single unique_ptr<Module> input to a std::unique_ptr<Module> output. With
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
88 our optimization function typedef in place we can declare our OptimizeLayer,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
89 which sits on top of our CompileLayer.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
90
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
91 To initialize our OptimizeLayer we pass it a reference to the CompileLayer
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
92 below (standard practice for layers), and we initialize the OptimizeFunction
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
93 using a lambda that calls out to an "optimizeModule" function that we will
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
94 define below.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
95
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
96 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
97
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
98 // ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
99 auto Resolver = createLambdaResolver(
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
100 [&](const std::string &Name) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
101 if (auto Sym = OptimizeLayer.findSymbol(Name, false))
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
102 return Sym;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
103 return JITSymbol(nullptr);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
104 },
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
105 // ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
106
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
107 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
108
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
109 // ...
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
110 return cantFail(OptimizeLayer.addModule(std::move(M),
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
111 std::move(Resolver)));
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
112 // ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
113
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
114 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
115
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
116 // ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
117 return OptimizeLayer.findSymbol(MangledNameStream.str(), true);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
118 // ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
119
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
120 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
121
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
122 // ...
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
123 cantFail(OptimizeLayer.removeModule(H));
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
124 // ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
125
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
126 Next we need to replace references to 'CompileLayer' with references to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
127 OptimizeLayer in our key methods: addModule, findSymbol, and removeModule. In
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
128 addModule we need to be careful to replace both references: the findSymbol call
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
129 inside our resolver, and the call through to addModule.
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
130
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
131 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
132
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
133 std::shared_ptr<Module> optimizeModule(std::shared_ptr<Module> M) {
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
134 // Create a function pass manager.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
135 auto FPM = llvm::make_unique<legacy::FunctionPassManager>(M.get());
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
136
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
137 // Add some optimizations.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
138 FPM->add(createInstructionCombiningPass());
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
139 FPM->add(createReassociatePass());
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
140 FPM->add(createGVNPass());
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
141 FPM->add(createCFGSimplificationPass());
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
142 FPM->doInitialization();
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
143
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
144 // Run the optimizations over all functions in the module being added to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
145 // the JIT.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
146 for (auto &F : *M)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
147 FPM->run(F);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
148
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
149 return M;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
150 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
151
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
152 At the bottom of our JIT we add a private method to do the actual optimization:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
153 *optimizeModule*. This function sets up a FunctionPassManager, adds some passes
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
154 to it, runs it over every function in the module, and then returns the mutated
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
155 module. The specific optimizations are the same ones used in
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
156 `Chapter 4 <LangImpl04.html>`_ of the "Implementing a language with LLVM"
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
157 tutorial series. Readers may visit that chapter for a more in-depth
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
158 discussion of these, and of IR optimization in general.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
159
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
160 And that's it in terms of changes to KaleidoscopeJIT: When a module is added via
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
161 addModule the OptimizeLayer will call our optimizeModule function before passing
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
162 the transformed module on to the CompileLayer below. Of course, we could have
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
163 called optimizeModule directly in our addModule function and not gone to the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
164 bother of using the IRTransformLayer, but doing so gives us another opportunity
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
165 to see how layers compose. It also provides a neat entry point to the *layer*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
166 concept itself, because IRTransformLayer turns out to be one of the simplest
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
167 implementations of the layer concept that can be devised:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
168
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
169 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
170
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
171 template <typename BaseLayerT, typename TransformFtor>
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
172 class IRTransformLayer {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
173 public:
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
174 using ModuleHandleT = typename BaseLayerT::ModuleHandleT;
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
175
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
176 IRTransformLayer(BaseLayerT &BaseLayer,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
177 TransformFtor Transform = TransformFtor())
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
178 : BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
179
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
180 Expected<ModuleHandleT>
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
181 addModule(std::shared_ptr<Module> M,
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
182 std::shared_ptr<JITSymbolResolver> Resolver) {
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
183 return BaseLayer.addModule(Transform(std::move(M)), std::move(Resolver));
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
184 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
185
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
186 void removeModule(ModuleHandleT H) { BaseLayer.removeModule(H); }
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
187
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
188 JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
189 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
190 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
191
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
192 JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name,
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
193 bool ExportedSymbolsOnly) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
194 return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
195 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
196
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
197 void emitAndFinalize(ModuleHandleT H) {
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
198 BaseLayer.emitAndFinalize(H);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
199 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
200
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
201 TransformFtor& getTransform() { return Transform; }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
202
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
203 const TransformFtor& getTransform() const { return Transform; }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
204
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
205 private:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
206 BaseLayerT &BaseLayer;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
207 TransformFtor Transform;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
208 };
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
209
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
210 This is the whole definition of IRTransformLayer, from
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
211 ``llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h``, stripped of its
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
212 comments. It is a template class with two template arguments: ``BaesLayerT`` and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
213 ``TransformFtor`` that provide the type of the base layer and the type of the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
214 "transform functor" (in our case a std::function) respectively. This class is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
215 concerned with two very simple jobs: (1) Running every IR Module that is added
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
216 with addModule through the transform functor, and (2) conforming to the ORC
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
217 layer interface. The interface consists of one typedef and five methods:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
218
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
219 +------------------+-----------------------------------------------------------+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
220 | Interface | Description |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
221 +==================+===========================================================+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
222 | | Provides a handle that can be used to identify a module |
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
223 | ModuleHandleT | set when calling findSymbolIn, removeModule, or |
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
224 | | emitAndFinalize. |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
225 +------------------+-----------------------------------------------------------+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
226 | | Takes a given set of Modules and makes them "available |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
227 | | for execution. This means that symbols in those modules |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
228 | | should be searchable via findSymbol and findSymbolIn, and |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
229 | | the address of the symbols should be read/writable (for |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
230 | | data symbols), or executable (for function symbols) after |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
231 | | JITSymbol::getAddress() is called. Note: This means that |
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
232 | addModule | addModule doesn't have to compile (or do any other |
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
233 | | work) up-front. It *can*, like IRCompileLayer, act |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
234 | | eagerly, but it can also simply record the module and |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
235 | | take no further action until somebody calls |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
236 | | JITSymbol::getAddress(). In IRTransformLayer's case |
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
237 | | addModule eagerly applies the transform functor to |
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
238 | | each module in the set, then passes the resulting set |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
239 | | of mutated modules down to the layer below. |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
240 +------------------+-----------------------------------------------------------+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
241 | | Removes a set of modules from the JIT. Code or data |
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
242 | removeModule | defined in these modules will no longer be available, and |
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
243 | | the memory holding the JIT'd definitions will be freed. |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
244 +------------------+-----------------------------------------------------------+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
245 | | Searches for the named symbol in all modules that have |
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
246 | | previously been added via addModule (and not yet |
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
247 | findSymbol | removed by a call to removeModule). In |
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
248 | | IRTransformLayer we just pass the query on to the layer |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
249 | | below. In our REPL this is our default way to search for |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
250 | | function definitions. |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
251 +------------------+-----------------------------------------------------------+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
252 | | Searches for the named symbol in the module set indicated |
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
253 | | by the given ModuleHandleT. This is just an optimized |
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
254 | | search, better for lookup-speed when you know exactly |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
255 | | a symbol definition should be found. In IRTransformLayer |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
256 | findSymbolIn | we just pass this query on to the layer below. In our |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
257 | | REPL we use this method to search for functions |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
258 | | representing top-level expressions, since we know exactly |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
259 | | where we'll find them: in the top-level expression module |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
260 | | we just added. |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
261 +------------------+-----------------------------------------------------------+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
262 | | Forces all of the actions required to make the code and |
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
263 | | data in a module set (represented by a ModuleHandleT) |
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
264 | | accessible. Behaves as if some symbol in the set had been |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
265 | | searched for and JITSymbol::getSymbolAddress called. This |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
266 | emitAndFinalize | is rarely needed, but can be useful when dealing with |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
267 | | layers that usually behave lazily if the user wants to |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
268 | | trigger early compilation (for example, to use idle CPU |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
269 | | time to eagerly compile code in the background). |
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
270 +------------------+-----------------------------------------------------------+
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
271
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
272 This interface attempts to capture the natural operations of a JIT (with some
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
273 wrinkles like emitAndFinalize for performance), similar to the basic JIT API
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
274 operations we identified in Chapter 1. Conforming to the layer concept allows
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
275 classes to compose neatly by implementing their behaviors in terms of the these
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
276 same operations, carried out on the layer below. For example, an eager layer
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
277 (like IRTransformLayer) can implement addModule by running each module in the
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
278 set through its transform up-front and immediately passing the result to the
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
279 layer below. A lazy layer, by contrast, could implement addModule by
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
280 squirreling away the modules doing no other up-front work, but applying the
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
281 transform (and calling addModule on the layer below) when the client calls
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
282 findSymbol instead. The JIT'd program behavior will be the same either way, but
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
283 these choices will have different performance characteristics: Doing work
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
284 eagerly means the JIT takes longer up-front, but proceeds smoothly once this is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
285 done. Deferring work allows the JIT to get up-and-running quickly, but will
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
286 force the JIT to pause and wait whenever some code or data is needed that hasn't
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
287 already been processed.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
288
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
289 Our current REPL is eager: Each function definition is optimized and compiled as
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
290 soon as it's typed in. If we were to make the transform layer lazy (but not
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
291 change things otherwise) we could defer optimization until the first time we
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
292 reference a function in a top-level expression (see if you can figure out why,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
293 then check out the answer below [1]_). In the next chapter, however we'll
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
294 introduce fully lazy compilation, in which function's aren't compiled until
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
295 they're first called at run-time. At this point the trade-offs get much more
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
296 interesting: the lazier we are, the quicker we can start executing the first
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
297 function, but the more often we'll have to pause to compile newly encountered
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
298 functions. If we only code-gen lazily, but optimize eagerly, we'll have a slow
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
299 startup (which everything is optimized) but relatively short pauses as each
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
300 function just passes through code-gen. If we both optimize and code-gen lazily
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
301 we can start executing the first function more quickly, but we'll have longer
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
302 pauses as each function has to be both optimized and code-gen'd when it's first
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
303 executed. Things become even more interesting if we consider interproceedural
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
304 optimizations like inlining, which must be performed eagerly. These are
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
305 complex trade-offs, and there is no one-size-fits all solution to them, but by
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
306 providing composable layers we leave the decisions to the person implementing
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
307 the JIT, and make it easy for them to experiment with different configurations.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
308
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
309 `Next: Adding Per-function Lazy Compilation <BuildingAJIT3.html>`_
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
310
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
311 Full Code Listing
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
312 =================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
313
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
314 Here is the complete code listing for our running example with an
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
315 IRTransformLayer added to enable optimization. To build this example, use:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
316
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
317 .. code-block:: bash
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
318
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
319 # Compile
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
320 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
321 # Run
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
322 ./toy
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
323
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
324 Here is the code:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
325
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
326 .. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
327 :language: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
328
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
329 .. [1] When we add our top-level expression to the JIT, any calls to functions
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
330 that we defined earlier will appear to the RTDyldObjectLinkingLayer as
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
331 external symbols. The RTDyldObjectLinkingLayer will call the SymbolResolver
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
332 that we defined in addModule, which in turn calls findSymbol on the
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
333 OptimizeLayer, at which point even a lazy transform layer will have to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
334 do its work.