Compiler.cpp revision a630078b32eb37a8de91ae09e26babf235d4fc9f
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  return kSuccess;
141}
142
143Compiler::~Compiler() {
144  delete mTarget;
145}
146
147enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) {
148  llvm::DataLayoutPass *data_layout_pass = NULL;
149
150  // Pass manager for link-time optimization
151  llvm::PassManager lto_passes;
152
153  // Prepare DataLayout target data from Module
154  data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout());
155  if (data_layout_pass == NULL) {
156    return kErrDataLayoutNoMemory;
157  }
158
159  // Add DataLayout to the pass manager.
160  lto_passes.add(data_layout_pass);
161
162  // Invoke "beforeAddLTOPasses" before adding the first pass.
163  if (!beforeAddLTOPasses(pScript, lto_passes)) {
164    return kErrHookBeforeAddLTOPasses;
165  }
166
167  if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
168    lto_passes.add(llvm::createGlobalOptimizerPass());
169    lto_passes.add(llvm::createConstantMergePass());
170  } else {
171    // FIXME: Figure out which passes should be executed.
172    llvm::PassManagerBuilder Builder;
173    Builder.populateLTOPassManager(lto_passes, /*Internalize*/false,
174                                   /*RunInliner*/true);
175  }
176
177  // Invoke "afterAddLTOPasses" after pass manager finished its
178  // construction.
179  if (!afterAddLTOPasses(pScript, lto_passes)) {
180    return kErrHookAfterAddLTOPasses;
181  }
182
183  lto_passes.run(pScript.getSource().getModule());
184
185  // Invoke "afterExecuteLTOPasses" before returning.
186  if (!afterExecuteLTOPasses(pScript)) {
187    return kErrHookAfterExecuteLTOPasses;
188  }
189
190  return kSuccess;
191}
192
193enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript,
194                                              llvm::raw_ostream &pResult) {
195  llvm::DataLayoutPass *data_layout_pass;
196  llvm::MCContext *mc_context = NULL;
197
198  // Create pass manager for MC code generation.
199  llvm::PassManager codegen_passes;
200
201  // Prepare DataLayout target data from Module
202  data_layout_pass = new (std::nothrow) llvm::DataLayoutPass(*mTarget->getDataLayout());
203  if (data_layout_pass == NULL) {
204    return kErrDataLayoutNoMemory;
205  }
206
207  // Add DataLayout to the pass manager.
208  codegen_passes.add(data_layout_pass);
209
210  // Invokde "beforeAddCodeGenPasses" before adding the first pass.
211  if (!beforeAddCodeGenPasses(pScript, codegen_passes)) {
212    return kErrHookBeforeAddCodeGenPasses;
213  }
214
215  // Add passes to the pass manager to emit machine code through MC layer.
216  if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult,
217                                 /* DisableVerify */false)) {
218    return kPrepareCodeGenPass;
219  }
220
221  // Invokde "afterAddCodeGenPasses" after pass manager finished its
222  // construction.
223  if (!afterAddCodeGenPasses(pScript, codegen_passes)) {
224    return kErrHookAfterAddCodeGenPasses;
225  }
226
227  // Invokde "beforeExecuteCodeGenPasses" before executing the passes.
228  if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) {
229    return kErrHookBeforeExecuteCodeGenPasses;
230  }
231
232  // Execute the pass.
233  codegen_passes.run(pScript.getSource().getModule());
234
235  // Invokde "afterExecuteCodeGenPasses" before returning.
236  if (!afterExecuteCodeGenPasses(pScript)) {
237    return kErrHookAfterExecuteCodeGenPasses;
238  }
239
240  return kSuccess;
241}
242
243enum Compiler::ErrorCode Compiler::compile(Script &pScript,
244                                           llvm::raw_ostream &pResult,
245                                           llvm::raw_ostream *IRStream) {
246  llvm::Module &module = pScript.getSource().getModule();
247  enum ErrorCode err;
248
249  if (mTarget == NULL) {
250    return kErrNoTargetMachine;
251  }
252
253  // Materialize the bitcode module.
254  if (module.getMaterializer() != NULL) {
255    // A module with non-null materializer means that it is a lazy-load module.
256    // Materialize it now via invoking MaterializeAllPermanently(). This
257    // function returns false when the materialization is successful.
258    llvm::error_code ec = module.materializeAllPermanently();
259    if (ec) {
260      ALOGE("Failed to materialize the module `%s'! (%s)",
261            module.getModuleIdentifier().c_str(), ec.message().c_str());
262      return kErrMaterialization;
263    }
264  }
265
266  if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) {
267    return err;
268  }
269
270  if (IRStream)
271    *IRStream << module;
272
273  if ((err = runCodeGen(pScript, pResult)) != kSuccess) {
274    return err;
275  }
276
277  return kSuccess;
278}
279
280enum Compiler::ErrorCode Compiler::compile(Script &pScript,
281                                           OutputFile &pResult,
282                                           llvm::raw_ostream *IRStream) {
283  // Check the state of the specified output file.
284  if (pResult.hasError()) {
285    return kErrInvalidOutputFileState;
286  }
287
288  // Open the output file decorated in llvm::raw_ostream.
289  llvm::raw_ostream *out = pResult.dup();
290  if (out == NULL) {
291    return kErrPrepareOutput;
292  }
293
294  // Delegate the request.
295  enum Compiler::ErrorCode err = compile(pScript, *out, IRStream);
296
297  // Close the output before return.
298  delete out;
299
300  return err;
301}
302