1 /*
2 * Copyright 2010-2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "bcc/Compiler.h"
18
19 #include <llvm/Analysis/Passes.h>
20 #include <llvm/CodeGen/RegAllocRegistry.h>
21 #include <llvm/IR/Module.h>
22 #include <llvm/PassManager.h>
23 #include <llvm/Support/TargetRegistry.h>
24 #include <llvm/Support/raw_ostream.h>
25 #include <llvm/IR/DataLayout.h>
26 #include <llvm/Target/TargetMachine.h>
27 #include <llvm/Transforms/IPO.h>
28 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
29 #include <llvm/Transforms/Scalar.h>
30
31 #include "bcc/Script.h"
32 #include "bcc/Source.h"
33 #include "bcc/Support/CompilerConfig.h"
34 #include "bcc/Support/Log.h"
35 #include "bcc/Support/OutputFile.h"
36
37 #include <string>
38
39 using namespace bcc;
40
GetErrorString(enum ErrorCode pErrCode)41 const char *Compiler::GetErrorString(enum ErrorCode pErrCode) {
42 switch (pErrCode) {
43 case kSuccess:
44 return "Successfully compiled.";
45 case kInvalidConfigNoTarget:
46 return "Invalid compiler config supplied (getTarget() returns NULL.) "
47 "(missing call to CompilerConfig::initialize()?)";
48 case kErrCreateTargetMachine:
49 return "Failed to create llvm::TargetMachine.";
50 case kErrSwitchTargetMachine:
51 return "Failed to switch llvm::TargetMachine.";
52 case kErrNoTargetMachine:
53 return "Failed to compile the script since there's no available "
54 "TargetMachine. (missing call to Compiler::config()?)";
55 case kErrDataLayoutNoMemory:
56 return "Out of memory when create DataLayout during compilation.";
57 case kErrMaterialization:
58 return "Failed to materialize the module.";
59 case kErrInvalidOutputFileState:
60 return "Supplied output file was invalid (in the error state.)";
61 case kErrPrepareOutput:
62 return "Failed to prepare file for output.";
63 case kPrepareCodeGenPass:
64 return "Failed to construct pass list for code-generation.";
65 case kErrHookBeforeAddLTOPasses:
66 return "Error occurred during beforeAddLTOPasses() in subclass.";
67 case kErrHookAfterAddLTOPasses:
68 return "Error occurred during afterAddLTOPasses() in subclass.";
69 case kErrHookAfterExecuteLTOPasses:
70 return "Error occurred during afterExecuteLTOPasses() in subclass.";
71 case kErrHookBeforeAddCodeGenPasses:
72 return "Error occurred during beforeAddCodeGenPasses() in subclass.";
73 case kErrHookAfterAddCodeGenPasses:
74 return "Error occurred during afterAddCodeGenPasses() in subclass.";
75 case kErrHookBeforeExecuteCodeGenPasses:
76 return "Error occurred during beforeExecuteCodeGenPasses() in subclass.";
77 case kErrHookAfterExecuteCodeGenPasses:
78 return "Error occurred during afterExecuteCodeGenPasses() in subclass.";
79 case kErrInvalidSource:
80 return "Error loading input bitcode";
81 }
82
83 // This assert should never be reached as the compiler verifies that the
84 // above switch coveres all enum values.
85 assert(false && "Unknown error code encountered");
86 return "";
87 }
88
89 //===----------------------------------------------------------------------===//
90 // Instance Methods
91 //===----------------------------------------------------------------------===//
Compiler()92 Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) {
93 return;
94 }
95
Compiler(const CompilerConfig & pConfig)96 Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(NULL),
97 mEnableLTO(true) {
98 const std::string &triple = pConfig.getTriple();
99
100 enum ErrorCode err = config(pConfig);
101 if (err != kSuccess) {
102 ALOGE("%s (%s, features: %s)", GetErrorString(err),
103 triple.c_str(), pConfig.getFeatureString().c_str());
104 return;
105 }
106
107 return;
108 }
109
config(const CompilerConfig & pConfig)110 enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) {
111 if (pConfig.getTarget() == NULL) {
112 return kInvalidConfigNoTarget;
113 }
114
115 llvm::TargetMachine *new_target =
116 (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(),
117 pConfig.getCPU(),
118 pConfig.getFeatureString(),
119 pConfig.getTargetOptions(),
120 pConfig.getRelocationModel(),
121 pConfig.getCodeModel(),
122 pConfig.getOptimizationLevel());
123
124 if (new_target == NULL) {
125 return ((mTarget != NULL) ? kErrSwitchTargetMachine :
126 kErrCreateTargetMachine);
127 }
128
129 // Replace the old TargetMachine.
130 delete mTarget;
131 mTarget = new_target;
132
133 // Adjust register allocation policy according to the optimization level.
134 // createFastRegisterAllocator: fast but bad quality
135 // createLinearScanRegisterAllocator: not so fast but good quality
136 if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) {
137 llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator);
138 } else {
139 llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator);
140 }
141
142 return kSuccess;
143 }
144
~Compiler()145 Compiler::~Compiler() {
146 delete mTarget;
147 }
148
runLTO(Script & pScript)149 enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) {
150 llvm::DataLayoutPass *data_layout_pass = NULL;
151
152 // Pass manager for link-time optimization
153 llvm::PassManager lto_passes;
154
155 // Prepare DataLayout target data from Module
156 data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout());
157 if (data_layout_pass == NULL) {
158 return kErrDataLayoutNoMemory;
159 }
160
161 // Add DataLayout to the pass manager.
162 lto_passes.add(data_layout_pass);
163
164 // Invoke "beforeAddLTOPasses" before adding the first pass.
165 if (!beforeAddLTOPasses(pScript, lto_passes)) {
166 return kErrHookBeforeAddLTOPasses;
167 }
168
169 if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
170 lto_passes.add(llvm::createGlobalOptimizerPass());
171 lto_passes.add(llvm::createConstantMergePass());
172 } else {
173 // FIXME: Figure out which passes should be executed.
174 llvm::PassManagerBuilder Builder;
175 Builder.populateLTOPassManager(lto_passes, /*Internalize*/false,
176 /*RunInliner*/true);
177 }
178
179 // Invoke "afterAddLTOPasses" after pass manager finished its
180 // construction.
181 if (!afterAddLTOPasses(pScript, lto_passes)) {
182 return kErrHookAfterAddLTOPasses;
183 }
184
185 lto_passes.run(pScript.getSource().getModule());
186
187 // Invoke "afterExecuteLTOPasses" before returning.
188 if (!afterExecuteLTOPasses(pScript)) {
189 return kErrHookAfterExecuteLTOPasses;
190 }
191
192 return kSuccess;
193 }
194
runCodeGen(Script & pScript,llvm::raw_ostream & pResult)195 enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript,
196 llvm::raw_ostream &pResult) {
197 llvm::DataLayoutPass *data_layout_pass;
198 llvm::MCContext *mc_context = NULL;
199
200 // Create pass manager for MC code generation.
201 llvm::PassManager codegen_passes;
202
203 // Prepare DataLayout target data from Module
204 data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout());
205 if (data_layout_pass == NULL) {
206 return kErrDataLayoutNoMemory;
207 }
208
209 // Add DataLayout to the pass manager.
210 codegen_passes.add(data_layout_pass);
211
212 // Invokde "beforeAddCodeGenPasses" before adding the first pass.
213 if (!beforeAddCodeGenPasses(pScript, codegen_passes)) {
214 return kErrHookBeforeAddCodeGenPasses;
215 }
216
217 // Add passes to the pass manager to emit machine code through MC layer.
218 if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult,
219 /* DisableVerify */false)) {
220 return kPrepareCodeGenPass;
221 }
222
223 // Invokde "afterAddCodeGenPasses" after pass manager finished its
224 // construction.
225 if (!afterAddCodeGenPasses(pScript, codegen_passes)) {
226 return kErrHookAfterAddCodeGenPasses;
227 }
228
229 // Invokde "beforeExecuteCodeGenPasses" before executing the passes.
230 if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) {
231 return kErrHookBeforeExecuteCodeGenPasses;
232 }
233
234 // Execute the pass.
235 codegen_passes.run(pScript.getSource().getModule());
236
237 // Invokde "afterExecuteCodeGenPasses" before returning.
238 if (!afterExecuteCodeGenPasses(pScript)) {
239 return kErrHookAfterExecuteCodeGenPasses;
240 }
241
242 return kSuccess;
243 }
244
compile(Script & pScript,llvm::raw_ostream & pResult,llvm::raw_ostream * IRStream)245 enum Compiler::ErrorCode Compiler::compile(Script &pScript,
246 llvm::raw_ostream &pResult,
247 llvm::raw_ostream *IRStream) {
248 llvm::Module &module = pScript.getSource().getModule();
249 enum ErrorCode err;
250
251 if (mTarget == NULL) {
252 return kErrNoTargetMachine;
253 }
254
255 const std::string &triple = module.getTargetTriple();
256 const llvm::DataLayout *dl = getTargetMachine().getDataLayout();
257 unsigned int pointerSize = dl->getPointerSizeInBits();
258 if (triple == "armv7-none-linux-gnueabi") {
259 if (pointerSize != 32) {
260 return kErrInvalidSource;
261 }
262 } else if (triple == "aarch64-none-linux-gnueabi") {
263 if (pointerSize != 64) {
264 return kErrInvalidSource;
265 }
266 } else {
267 return kErrInvalidSource;
268 }
269
270 // Materialize the bitcode module.
271 if (module.getMaterializer() != NULL) {
272 // A module with non-null materializer means that it is a lazy-load module.
273 // Materialize it now via invoking MaterializeAllPermanently(). This
274 // function returns false when the materialization is successful.
275 std::error_code ec = module.materializeAllPermanently();
276 if (ec) {
277 ALOGE("Failed to materialize the module `%s'! (%s)",
278 module.getModuleIdentifier().c_str(), ec.message().c_str());
279 return kErrMaterialization;
280 }
281 }
282
283 if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) {
284 return err;
285 }
286
287 if (IRStream)
288 *IRStream << module;
289
290 if ((err = runCodeGen(pScript, pResult)) != kSuccess) {
291 return err;
292 }
293
294 return kSuccess;
295 }
296
compile(Script & pScript,OutputFile & pResult,llvm::raw_ostream * IRStream)297 enum Compiler::ErrorCode Compiler::compile(Script &pScript,
298 OutputFile &pResult,
299 llvm::raw_ostream *IRStream) {
300 // Check the state of the specified output file.
301 if (pResult.hasError()) {
302 return kErrInvalidOutputFileState;
303 }
304
305 // Open the output file decorated in llvm::raw_ostream.
306 llvm::raw_ostream *out = pResult.dup();
307 if (out == NULL) {
308 return kErrPrepareOutput;
309 }
310
311 // Delegate the request.
312 enum Compiler::ErrorCode err = compile(pScript, *out, IRStream);
313
314 // Close the output before return.
315 delete out;
316
317 return err;
318 }
319