• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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