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 #include <string>
     38 
     39 using namespace bcc;
     40 
     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 //===----------------------------------------------------------------------===//
     92 Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) {
     93   return;
     94 }
     95 
     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 
    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 
    145 Compiler::~Compiler() {
    146   delete mTarget;
    147 }
    148 
    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 
    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 
    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 
    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