Home | History | Annotate | Download | only in Core
      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 using namespace bcc;
     38 
     39 const 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 //===----------------------------------------------------------------------===//
     90 Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) {
     91   return;
     92 }
     93 
     94 Compiler::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 
    108 enum 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 
    146 Compiler::~Compiler() {
    147   delete mTarget;
    148 }
    149 
    150 enum 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 
    196 enum 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 
    246 enum 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 
    283 enum 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