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/Module.h>
22 #include <llvm/PassManager.h>
23 #include <llvm/Support/TargetRegistry.h>
24 #include <llvm/Support/raw_ostream.h>
25 #include <llvm/Target/TargetData.h>
26 #include <llvm/Target/TargetMachine.h>
27 #include <llvm/Transforms/IPO.h>
28 #include <llvm/Transforms/Scalar.h>
29
30 #include "bcc/Script.h"
31 #include "bcc/Source.h"
32 #include "bcc/Support/CompilerConfig.h"
33 #include "bcc/Support/Log.h"
34 #include "bcc/Support/OutputFile.h"
35
36 using namespace bcc;
37
GetErrorString(enum ErrorCode pErrCode)38 const char *Compiler::GetErrorString(enum ErrorCode pErrCode) {
39 static const char *ErrorString[] = {
40 /* kSuccess */
41 "Successfully compiled.",
42 /* kInvalidConfigNoTarget */
43 "Invalid compiler config supplied (getTarget() returns NULL.) "
44 "(missing call to CompilerConfig::initialize()?)",
45 /* kErrCreateTargetMachine */
46 "Failed to create llvm::TargetMachine.",
47 /* kErrSwitchTargetMachine */
48 "Failed to switch llvm::TargetMachine.",
49 /* kErrNoTargetMachine */
50 "Failed to compile the script since there's no available TargetMachine."
51 " (missing call to Compiler::config()?)",
52 /* kErrTargetDataNoMemory */
53 "Out of memory when create TargetData during compilation.",
54 /* kErrMaterialization */
55 "Failed to materialize the module.",
56 /* kErrInvalidOutputFileState */
57 "Supplied output file was invalid (in the error state.)",
58 /* kErrPrepareOutput */
59 "Failed to prepare file for output.",
60 /* kPrepareCodeGenPass */
61 "Failed to construct pass list for code-generation.",
62
63 /* kErrHookBeforeAddLTOPasses */
64 "Error occurred during beforeAddLTOPasses() in subclass.",
65 /* kErrHookAfterAddLTOPasses */
66 "Error occurred during afterAddLTOPasses() in subclass.",
67 /* kErrHookBeforeExecuteLTOPasses */
68 "Error occurred during beforeExecuteLTOPasses() in subclass.",
69 /* kErrHookAfterExecuteLTOPasses */
70 "Error occurred during afterExecuteLTOPasses() in subclass.",
71
72 /* kErrHookBeforeAddCodeGenPasses */
73 "Error occurred during beforeAddCodeGenPasses() in subclass.",
74 /* kErrHookAfterAddCodeGenPasses */
75 "Error occurred during afterAddCodeGenPasses() in subclass.",
76 /* kErrHookBeforeExecuteCodeGenPasses */
77 "Error occurred during beforeExecuteCodeGenPasses() in subclass.",
78 /* kErrHookAfterExecuteCodeGenPasses */
79 "Error occurred during afterExecuteCodeGenPasses() in subclass.",
80
81 /* kMaxErrorCode */
82 "(Unknown error code)"
83 };
84
85 if (pErrCode > kMaxErrorCode) {
86 pErrCode = kMaxErrorCode;
87 }
88
89 return ErrorString[ static_cast<size_t>(pErrCode) ];
90 }
91
92 //===----------------------------------------------------------------------===//
93 // Instance Methods
94 //===----------------------------------------------------------------------===//
Compiler()95 Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) {
96 return;
97 }
98
Compiler(const CompilerConfig & pConfig)99 Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(NULL),
100 mEnableLTO(true) {
101 const std::string &triple = pConfig.getTriple();
102
103 enum ErrorCode err = config(pConfig);
104 if (err != kSuccess) {
105 ALOGE("%s (%s, features: %s)", GetErrorString(err),
106 triple.c_str(), pConfig.getFeatureString().c_str());
107 return;
108 }
109
110 return;
111 }
112
config(const CompilerConfig & pConfig)113 enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) {
114 if (pConfig.getTarget() == NULL) {
115 return kInvalidConfigNoTarget;
116 }
117
118 llvm::TargetMachine *new_target =
119 (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(),
120 pConfig.getCPU(),
121 pConfig.getFeatureString(),
122 pConfig.getTargetOptions(),
123 pConfig.getRelocationModel(),
124 pConfig.getCodeModel(),
125 pConfig.getOptimizationLevel());
126
127 if (new_target == NULL) {
128 return ((mTarget != NULL) ? kErrSwitchTargetMachine :
129 kErrCreateTargetMachine);
130 }
131
132 // Replace the old TargetMachine.
133 delete mTarget;
134 mTarget = new_target;
135
136 // Adjust register allocation policy according to the optimization level.
137 // createFastRegisterAllocator: fast but bad quality
138 // createLinearScanRegisterAllocator: not so fast but good quality
139 if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) {
140 llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator);
141 } else {
142 llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator);
143 }
144
145 // Relax all machine instructions.
146 mTarget->setMCRelaxAll(true);
147
148 return kSuccess;
149 }
150
~Compiler()151 Compiler::~Compiler() {
152 delete mTarget;
153 }
154
runLTO(Script & pScript)155 enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) {
156 llvm::TargetData *target_data = NULL;
157
158 // Pass manager for link-time optimization
159 llvm::PassManager lto_passes;
160
161 // Prepare TargetData target data from Module
162 target_data = new (std::nothrow) llvm::TargetData(*mTarget->getTargetData());
163 if (target_data == NULL) {
164 return kErrTargetDataNoMemory;
165 }
166
167 // Add TargetData to the pass manager.
168 lto_passes.add(target_data);
169
170 // Invokde "beforeAddLTOPasses" before adding the first pass.
171 if (!beforeAddLTOPasses(pScript, lto_passes)) {
172 return kErrHookBeforeAddLTOPasses;
173 }
174
175 // We now create passes list performing LTO. These are copied from
176 // (including comments) llvm::PassManagerBuilder::populateLTOPassManager().
177 // Only a subset of these LTO passes are enabled in optimization level 0 as
178 // they interfere with interactive debugging.
179 //
180 // FIXME: Figure out which passes (if any) makes sense for levels 1 and 2.
181 //if ( != llvm::CodeGenOpt::None) {
182 if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
183 lto_passes.add(llvm::createGlobalOptimizerPass());
184 lto_passes.add(llvm::createConstantMergePass());
185 } else {
186 // Propagate constants at call sites into the functions they call. This
187 // opens opportunities for globalopt (and inlining) by substituting
188 // function pointers passed as arguments to direct uses of functions.
189 lto_passes.add(llvm::createIPSCCPPass());
190
191 // Now that we internalized some globals, see if we can hack on them!
192 lto_passes.add(llvm::createGlobalOptimizerPass());
193
194 // Linking modules together can lead to duplicated global constants, only
195 // keep one copy of each constant...
196 lto_passes.add(llvm::createConstantMergePass());
197
198 // Remove unused arguments from functions...
199 lto_passes.add(llvm::createDeadArgEliminationPass());
200
201 // Reduce the code after globalopt and ipsccp. Both can open up
202 // significant simplification opportunities, and both can propagate
203 // functions through function pointers. When this happens, we often have
204 // to resolve varargs calls, etc, so let instcombine do this.
205 lto_passes.add(llvm::createInstructionCombiningPass());
206
207 // Inline small functions
208 lto_passes.add(llvm::createFunctionInliningPass());
209
210 // Remove dead EH info.
211 lto_passes.add(llvm::createPruneEHPass());
212
213 // Internalize the globals again after inlining
214 lto_passes.add(llvm::createGlobalOptimizerPass());
215
216 // Remove dead functions.
217 lto_passes.add(llvm::createGlobalDCEPass());
218
219 // If we didn't decide to inline a function, check to see if we can
220 // transform it to pass arguments by value instead of by reference.
221 lto_passes.add(llvm::createArgumentPromotionPass());
222
223 // The IPO passes may leave cruft around. Clean up after them.
224 lto_passes.add(llvm::createInstructionCombiningPass());
225 lto_passes.add(llvm::createJumpThreadingPass());
226
227 // Break up allocas
228 lto_passes.add(llvm::createScalarReplAggregatesPass());
229
230 // Run a few AA driven optimizations here and now, to cleanup the code.
231 lto_passes.add(llvm::createFunctionAttrsPass()); // Add nocapture.
232 lto_passes.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
233
234 // Hoist loop invariants.
235 lto_passes.add(llvm::createLICMPass());
236
237 // Remove redundancies.
238 lto_passes.add(llvm::createGVNPass());
239
240 // Remove dead memcpys.
241 lto_passes.add(llvm::createMemCpyOptPass());
242
243 // Nuke dead stores.
244 lto_passes.add(llvm::createDeadStoreEliminationPass());
245
246 // Cleanup and simplify the code after the scalar optimizations.
247 lto_passes.add(llvm::createInstructionCombiningPass());
248
249 lto_passes.add(llvm::createJumpThreadingPass());
250
251 // Delete basic blocks, which optimization passes may have killed.
252 lto_passes.add(llvm::createCFGSimplificationPass());
253
254 // Now that we have optimized the program, discard unreachable functions.
255 lto_passes.add(llvm::createGlobalDCEPass());
256 }
257
258 // Invokde "afterAddLTOPasses" after pass manager finished its
259 // construction.
260 if (!afterAddLTOPasses(pScript, lto_passes)) {
261 return kErrHookAfterAddLTOPasses;
262 }
263
264 // Invokde "beforeExecuteLTOPasses" before executing the passes.
265 if (!beforeExecuteLTOPasses(pScript, lto_passes)) {
266 return kErrHookBeforeExecuteLTOPasses;
267 }
268
269 lto_passes.run(pScript.getSource().getModule());
270
271 // Invokde "afterExecuteLTOPasses" before returning.
272 if (!afterExecuteLTOPasses(pScript)) {
273 return kErrHookAfterExecuteLTOPasses;
274 }
275
276 return kSuccess;
277 }
278
runCodeGen(Script & pScript,llvm::raw_ostream & pResult)279 enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript,
280 llvm::raw_ostream &pResult) {
281 llvm::TargetData *target_data;
282 llvm::MCContext *mc_context = NULL;
283
284 // Create pass manager for MC code generation.
285 llvm::PassManager codegen_passes;
286
287 // Prepare TargetData target data from Module
288 target_data = new (std::nothrow) llvm::TargetData(*mTarget->getTargetData());
289 if (target_data == NULL) {
290 return kErrTargetDataNoMemory;
291 }
292
293 // Add TargetData to the pass manager.
294 codegen_passes.add(target_data);
295
296 // Invokde "beforeAddCodeGenPasses" before adding the first pass.
297 if (!beforeAddCodeGenPasses(pScript, codegen_passes)) {
298 return kErrHookBeforeAddCodeGenPasses;
299 }
300
301 // Add passes to the pass manager to emit machine code through MC layer.
302 if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult,
303 /* DisableVerify */false)) {
304 return kPrepareCodeGenPass;
305 }
306
307 // Invokde "afterAddCodeGenPasses" after pass manager finished its
308 // construction.
309 if (!afterAddCodeGenPasses(pScript, codegen_passes)) {
310 return kErrHookAfterAddCodeGenPasses;
311 }
312
313 // Invokde "beforeExecuteCodeGenPasses" before executing the passes.
314 if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) {
315 return kErrHookBeforeExecuteCodeGenPasses;
316 }
317
318 // Execute the pass.
319 codegen_passes.run(pScript.getSource().getModule());
320
321 // Invokde "afterExecuteCodeGenPasses" before returning.
322 if (!afterExecuteCodeGenPasses(pScript)) {
323 return kErrHookAfterExecuteCodeGenPasses;
324 }
325
326 return kSuccess;
327 }
328
compile(Script & pScript,llvm::raw_ostream & pResult)329 enum Compiler::ErrorCode Compiler::compile(Script &pScript,
330 llvm::raw_ostream &pResult) {
331 llvm::Module &module = pScript.getSource().getModule();
332 enum ErrorCode err;
333
334 if (mTarget == NULL) {
335 return kErrNoTargetMachine;
336 }
337
338 // Materialize the bitcode module.
339 if (module.getMaterializer() != NULL) {
340 std::string error;
341 // A module with non-null materializer means that it is a lazy-load module.
342 // Materialize it now via invoking MaterializeAllPermanently(). This
343 // function returns false when the materialization is successful.
344 if (module.MaterializeAllPermanently(&error)) {
345 ALOGE("Failed to materialize the module `%s'! (%s)",
346 module.getModuleIdentifier().c_str(), error.c_str());
347 return kErrMaterialization;
348 }
349 }
350
351 if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) {
352 return err;
353 }
354
355 if ((err = runCodeGen(pScript, pResult)) != kSuccess) {
356 return err;
357 }
358
359 return kSuccess;
360 }
361
compile(Script & pScript,OutputFile & pResult)362 enum Compiler::ErrorCode Compiler::compile(Script &pScript,
363 OutputFile &pResult) {
364 // Check the state of the specified output file.
365 if (pResult.hasError()) {
366 return kErrInvalidOutputFileState;
367 }
368
369 // Open the output file decorated in llvm::raw_ostream.
370 llvm::raw_ostream *out = pResult.dup();
371 if (out == NULL) {
372 return kErrPrepareOutput;
373 }
374
375 // Delegate the request.
376 enum Compiler::ErrorCode err = compile(pScript, *out);
377
378 // Close the output before return.
379 delete out;
380
381 return err;
382 }
383