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