Compiler.cpp revision 6a5fa14074200a18824defa0bffc64e5f2487152
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
37using namespace bcc;
38
39const char *Compiler::GetErrorString(enum ErrorCode pErrCode) {
40  switch (pErrCode) {
41  case kSuccess:
42    return "Successfully compiled.";
43  case kInvalidConfigNoTarget:
44    return "Invalid compiler config supplied (getTarget() returns NULL.) "
45           "(missing call to CompilerConfig::initialize()?)";
46  case kErrCreateTargetMachine:
47    return "Failed to create llvm::TargetMachine.";
48  case kErrSwitchTargetMachine:
49    return  "Failed to switch llvm::TargetMachine.";
50  case kErrNoTargetMachine:
51    return "Failed to compile the script since there's no available "
52           "TargetMachine. (missing call to Compiler::config()?)";
53  case kErrDataLayoutNoMemory:
54    return "Out of memory when create DataLayout during compilation.";
55  case kErrMaterialization:
56    return "Failed to materialize the module.";
57  case kErrInvalidOutputFileState:
58    return "Supplied output file was invalid (in the error state.)";
59  case kErrPrepareOutput:
60    return "Failed to prepare file for output.";
61  case kPrepareCodeGenPass:
62    return "Failed to construct pass list for code-generation.";
63  case kErrHookBeforeAddLTOPasses:
64    return "Error occurred during beforeAddLTOPasses() in subclass.";
65  case kErrHookAfterAddLTOPasses:
66    return "Error occurred during afterAddLTOPasses() in subclass.";
67  case kErrHookAfterExecuteLTOPasses:
68    return "Error occurred during afterExecuteLTOPasses() in subclass.";
69  case kErrHookBeforeAddCodeGenPasses:
70    return "Error occurred during beforeAddCodeGenPasses() in subclass.";
71  case kErrHookAfterAddCodeGenPasses:
72    return "Error occurred during afterAddCodeGenPasses() in subclass.";
73  case kErrHookBeforeExecuteCodeGenPasses:
74    return "Error occurred during beforeExecuteCodeGenPasses() in subclass.";
75  case kErrHookAfterExecuteCodeGenPasses:
76    return "Error occurred during afterExecuteCodeGenPasses() in subclass.";
77  case kErrInvalidSource:
78    return "Error loading input bitcode";
79  }
80
81  // This assert should never be reached as the compiler verifies that the
82  // above switch coveres all enum values.
83  assert(false && "Unknown error code encountered");
84  return  "";
85}
86
87//===----------------------------------------------------------------------===//
88// Instance Methods
89//===----------------------------------------------------------------------===//
90Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) {
91  return;
92}
93
94Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(NULL),
95                                                    mEnableLTO(true) {
96  const std::string &triple = pConfig.getTriple();
97
98  enum ErrorCode err = config(pConfig);
99  if (err != kSuccess) {
100    ALOGE("%s (%s, features: %s)", GetErrorString(err),
101          triple.c_str(), pConfig.getFeatureString().c_str());
102    return;
103  }
104
105  return;
106}
107
108enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) {
109  if (pConfig.getTarget() == NULL) {
110    return kInvalidConfigNoTarget;
111  }
112
113  llvm::TargetMachine *new_target =
114      (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(),
115                                                 pConfig.getCPU(),
116                                                 pConfig.getFeatureString(),
117                                                 pConfig.getTargetOptions(),
118                                                 pConfig.getRelocationModel(),
119                                                 pConfig.getCodeModel(),
120                                                 pConfig.getOptimizationLevel());
121
122  if (new_target == NULL) {
123    return ((mTarget != NULL) ? kErrSwitchTargetMachine :
124                                kErrCreateTargetMachine);
125  }
126
127  // Replace the old TargetMachine.
128  delete mTarget;
129  mTarget = new_target;
130
131  // Adjust register allocation policy according to the optimization level.
132  //  createFastRegisterAllocator: fast but bad quality
133  //  createLinearScanRegisterAllocator: not so fast but good quality
134  if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) {
135    llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator);
136  } else {
137    llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator);
138  }
139
140  // Relax all machine instructions.
141  mTarget->setMCRelaxAll(true);
142
143  return kSuccess;
144}
145
146Compiler::~Compiler() {
147  delete mTarget;
148}
149
150enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) {
151  llvm::DataLayout *data_layout = NULL;
152
153  // Pass manager for link-time optimization
154  llvm::PassManager lto_passes;
155
156  // Prepare DataLayout target data from Module
157  data_layout = new (std::nothrow) llvm::DataLayout(*mTarget->getDataLayout());
158  if (data_layout == NULL) {
159    return kErrDataLayoutNoMemory;
160  }
161
162  // Add DataLayout to the pass manager.
163  lto_passes.add(data_layout);
164
165  // Invoke "beforeAddLTOPasses" before adding the first pass.
166  if (!beforeAddLTOPasses(pScript, lto_passes)) {
167    return kErrHookBeforeAddLTOPasses;
168  }
169
170  if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
171    lto_passes.add(llvm::createGlobalOptimizerPass());
172    lto_passes.add(llvm::createConstantMergePass());
173  } else {
174    // FIXME: Figure out which passes should be executed.
175    llvm::PassManagerBuilder Builder;
176    Builder.populateLTOPassManager(lto_passes, /*Internalize*/false,
177                                   /*RunInliner*/true);
178  }
179
180  // Invoke "afterAddLTOPasses" after pass manager finished its
181  // construction.
182  if (!afterAddLTOPasses(pScript, lto_passes)) {
183    return kErrHookAfterAddLTOPasses;
184  }
185
186  lto_passes.run(pScript.getSource().getModule());
187
188  // Invoke "afterExecuteLTOPasses" before returning.
189  if (!afterExecuteLTOPasses(pScript)) {
190    return kErrHookAfterExecuteLTOPasses;
191  }
192
193  return kSuccess;
194}
195
196enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript,
197                                              llvm::raw_ostream &pResult) {
198  llvm::DataLayout *data_layout;
199  llvm::MCContext *mc_context = NULL;
200
201  // Create pass manager for MC code generation.
202  llvm::PassManager codegen_passes;
203
204  // Prepare DataLayout target data from Module
205  data_layout = new (std::nothrow) llvm::DataLayout(*mTarget->getDataLayout());
206  if (data_layout == NULL) {
207    return kErrDataLayoutNoMemory;
208  }
209
210  // Add DataLayout to the pass manager.
211  codegen_passes.add(data_layout);
212
213  // Invokde "beforeAddCodeGenPasses" before adding the first pass.
214  if (!beforeAddCodeGenPasses(pScript, codegen_passes)) {
215    return kErrHookBeforeAddCodeGenPasses;
216  }
217
218  // Add passes to the pass manager to emit machine code through MC layer.
219  if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult,
220                                 /* DisableVerify */false)) {
221    return kPrepareCodeGenPass;
222  }
223
224  // Invokde "afterAddCodeGenPasses" after pass manager finished its
225  // construction.
226  if (!afterAddCodeGenPasses(pScript, codegen_passes)) {
227    return kErrHookAfterAddCodeGenPasses;
228  }
229
230  // Invokde "beforeExecuteCodeGenPasses" before executing the passes.
231  if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) {
232    return kErrHookBeforeExecuteCodeGenPasses;
233  }
234
235  // Execute the pass.
236  codegen_passes.run(pScript.getSource().getModule());
237
238  // Invokde "afterExecuteCodeGenPasses" before returning.
239  if (!afterExecuteCodeGenPasses(pScript)) {
240    return kErrHookAfterExecuteCodeGenPasses;
241  }
242
243  return kSuccess;
244}
245
246enum Compiler::ErrorCode Compiler::compile(Script &pScript,
247                                           llvm::raw_ostream &pResult,
248                                           llvm::raw_ostream *IRStream) {
249  llvm::Module &module = pScript.getSource().getModule();
250  enum ErrorCode err;
251
252  if (mTarget == NULL) {
253    return kErrNoTargetMachine;
254  }
255
256  // Materialize the bitcode module.
257  if (module.getMaterializer() != NULL) {
258    std::string error;
259    // A module with non-null materializer means that it is a lazy-load module.
260    // Materialize it now via invoking MaterializeAllPermanently(). This
261    // function returns false when the materialization is successful.
262    if (module.MaterializeAllPermanently(&error)) {
263      ALOGE("Failed to materialize the module `%s'! (%s)",
264            module.getModuleIdentifier().c_str(), error.c_str());
265      return kErrMaterialization;
266    }
267  }
268
269  if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) {
270    return err;
271  }
272
273  if (IRStream)
274    *IRStream << module;
275
276  if ((err = runCodeGen(pScript, pResult)) != kSuccess) {
277    return err;
278  }
279
280  return kSuccess;
281}
282
283enum Compiler::ErrorCode Compiler::compile(Script &pScript,
284                                           OutputFile &pResult,
285                                           llvm::raw_ostream *IRStream) {
286  // Check the state of the specified output file.
287  if (pResult.hasError()) {
288    return kErrInvalidOutputFileState;
289  }
290
291  // Open the output file decorated in llvm::raw_ostream.
292  llvm::raw_ostream *out = pResult.dup();
293  if (out == NULL) {
294    return kErrPrepareOutput;
295  }
296
297  // Delegate the request.
298  enum Compiler::ErrorCode err = compile(pScript, *out, IRStream);
299
300  // Close the output before return.
301  delete out;
302
303  return err;
304}
305