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/Analysis/TargetTransformInfo.h>
     21 #include <llvm/CodeGen/RegAllocRegistry.h>
     22 #include <llvm/IR/LegacyPassManager.h>
     23 #include <llvm/IR/Module.h>
     24 #include <llvm/Support/TargetRegistry.h>
     25 #include <llvm/Support/raw_ostream.h>
     26 #include <llvm/IR/DataLayout.h>
     27 #include <llvm/Target/TargetSubtargetInfo.h>
     28 #include <llvm/Target/TargetMachine.h>
     29 #include <llvm/Transforms/IPO.h>
     30 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
     31 #include <llvm/Transforms/Scalar.h>
     32 #include <llvm/Transforms/Vectorize.h>
     33 
     34 #include "bcc/Assert.h"
     35 #include "bcc/Config/Config.h"
     36 #include "bcc/Renderscript/RSScript.h"
     37 #include "bcc/Renderscript/RSTransforms.h"
     38 #include "bcc/Renderscript/RSUtils.h"
     39 #include "bcc/Script.h"
     40 #include "bcc/Source.h"
     41 #include "bcc/Support/CompilerConfig.h"
     42 #include "bcc/Support/Log.h"
     43 #include "bcc/Support/OutputFile.h"
     44 #include "bcinfo/MetadataExtractor.h"
     45 #include "rsDefines.h"
     46 
     47 #include <string>
     48 
     49 using namespace bcc;
     50 
     51 const char *Compiler::GetErrorString(enum ErrorCode pErrCode) {
     52   switch (pErrCode) {
     53   case kSuccess:
     54     return "Successfully compiled.";
     55   case kInvalidConfigNoTarget:
     56     return "Invalid compiler config supplied (getTarget() returns nullptr.) "
     57            "(missing call to CompilerConfig::initialize()?)";
     58   case kErrCreateTargetMachine:
     59     return "Failed to create llvm::TargetMachine.";
     60   case kErrSwitchTargetMachine:
     61     return  "Failed to switch llvm::TargetMachine.";
     62   case kErrNoTargetMachine:
     63     return "Failed to compile the script since there's no available "
     64            "TargetMachine. (missing call to Compiler::config()?)";
     65   case kErrMaterialization:
     66     return "Failed to materialize the module.";
     67   case kErrInvalidOutputFileState:
     68     return "Supplied output file was invalid (in the error state.)";
     69   case kErrPrepareOutput:
     70     return "Failed to prepare file for output.";
     71   case kPrepareCodeGenPass:
     72     return "Failed to construct pass list for code-generation.";
     73   case kErrCustomPasses:
     74     return "Error occurred while adding custom passes.";
     75   case kErrInvalidSource:
     76     return "Error loading input bitcode";
     77   case kIllegalGlobalFunction:
     78     return "Use of undefined external function";
     79   case kErrInvalidTargetMachine:
     80     return "Invalid/unexpected llvm::TargetMachine.";
     81   }
     82 
     83   // This assert should never be reached as the compiler verifies that the
     84   // above switch coveres all enum values.
     85   bccAssert(false && "Unknown error code encountered");
     86   return  "";
     87 }
     88 
     89 //===----------------------------------------------------------------------===//
     90 // Instance Methods
     91 //===----------------------------------------------------------------------===//
     92 Compiler::Compiler() : mTarget(nullptr), mEnableOpt(true) {
     93   return;
     94 }
     95 
     96 Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(nullptr),
     97                                                     mEnableOpt(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() == nullptr) {
    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 == nullptr) {
    125     return ((mTarget != nullptr) ? 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 
    150 // This function has complete responsibility for creating and executing the
    151 // exact list of compiler passes.
    152 enum Compiler::ErrorCode Compiler::runPasses(Script &pScript,
    153                                              llvm::raw_pwrite_stream &pResult) {
    154   // Pass manager for link-time optimization
    155   llvm::legacy::PassManager transformPasses;
    156 
    157   // Empty MCContext.
    158   llvm::MCContext *mc_context = nullptr;
    159 
    160   transformPasses.add(
    161       createTargetTransformInfoWrapperPass(mTarget->getTargetIRAnalysis()));
    162 
    163   // Add some initial custom passes.
    164   addInvokeHelperPass(transformPasses);
    165   addExpandKernelPass(transformPasses);
    166   addDebugInfoPass(pScript, transformPasses);
    167   addInvariantPass(transformPasses);
    168   if (mTarget->getOptLevel() != llvm::CodeGenOpt::None) {
    169     if (!addInternalizeSymbolsPass(pScript, transformPasses))
    170       return kErrCustomPasses;
    171   }
    172   addGlobalInfoPass(pScript, transformPasses);
    173 
    174   if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
    175     transformPasses.add(llvm::createGlobalOptimizerPass());
    176     transformPasses.add(llvm::createConstantMergePass());
    177 
    178   } else {
    179     // FIXME: Figure out which passes should be executed.
    180     llvm::PassManagerBuilder Builder;
    181     Builder.Inliner = llvm::createFunctionInliningPass();
    182     Builder.populateLTOPassManager(transformPasses);
    183 
    184     /* FIXME: Reenable autovectorization after rebase.
    185        bug 19324423
    186     // Add vectorization passes after LTO passes are in
    187     // additional flag: -unroll-runtime
    188     transformPasses.add(llvm::createLoopUnrollPass(-1, 16, 0, 1));
    189     // Need to pass appropriate flags here: -scalarize-load-store
    190     transformPasses.add(llvm::createScalarizerPass());
    191     transformPasses.add(llvm::createCFGSimplificationPass());
    192     transformPasses.add(llvm::createScopedNoAliasAAPass());
    193     transformPasses.add(llvm::createScalarEvolutionAliasAnalysisPass());
    194     // additional flags: -slp-vectorize-hor -slp-vectorize-hor-store (unnecessary?)
    195     transformPasses.add(llvm::createSLPVectorizerPass());
    196     transformPasses.add(llvm::createDeadCodeEliminationPass());
    197     transformPasses.add(llvm::createInstructionCombiningPass());
    198     */
    199   }
    200 
    201   // These passes have to come after LTO, since we don't want to examine
    202   // functions that are never actually called.
    203   if (llvm::Triple(getTargetMachine().getTargetTriple()).getArch() == llvm::Triple::x86_64)
    204     transformPasses.add(createRSX86_64CallConvPass());  // Add pass to correct calling convention for X86-64.
    205   transformPasses.add(createRSIsThreadablePass());      // Add pass to mark script as threadable.
    206 
    207   // RSEmbedInfoPass needs to come after we have scanned for non-threadable
    208   // functions.
    209   // Script passed to RSCompiler must be a RSScript.
    210   RSScript &script = static_cast<RSScript &>(pScript);
    211   if (script.getEmbedInfo())
    212     transformPasses.add(createRSEmbedInfoPass());
    213 
    214   // Execute the passes.
    215   transformPasses.run(pScript.getSource().getModule());
    216 
    217   // Run backend separately to avoid interference between debug metadata
    218   // generation and backend initialization.
    219   llvm::legacy::PassManager codeGenPasses;
    220 
    221   // Add passes to the pass manager to emit machine code through MC layer.
    222   if (mTarget->addPassesToEmitMC(codeGenPasses, mc_context, pResult,
    223                                  /* DisableVerify */false)) {
    224     return kPrepareCodeGenPass;
    225   }
    226 
    227   // Execute the passes.
    228   codeGenPasses.run(pScript.getSource().getModule());
    229 
    230   return kSuccess;
    231 }
    232 
    233 enum Compiler::ErrorCode Compiler::compile(Script &pScript,
    234                                            llvm::raw_pwrite_stream &pResult,
    235                                            llvm::raw_ostream *IRStream) {
    236   llvm::Module &module = pScript.getSource().getModule();
    237   enum ErrorCode err;
    238 
    239   if (mTarget == nullptr) {
    240     return kErrNoTargetMachine;
    241   }
    242 
    243   const std::string &triple = module.getTargetTriple();
    244   const llvm::DataLayout dl = getTargetMachine().createDataLayout();
    245   unsigned int pointerSize = dl.getPointerSizeInBits();
    246   if (triple == "armv7-none-linux-gnueabi") {
    247     if (pointerSize != 32) {
    248       return kErrInvalidSource;
    249     }
    250   } else if (triple == "aarch64-none-linux-gnueabi") {
    251     if (pointerSize != 64) {
    252       return kErrInvalidSource;
    253     }
    254   } else {
    255     return kErrInvalidSource;
    256   }
    257 
    258   if (getTargetMachine().getTargetTriple().getArch() == llvm::Triple::x86) {
    259     // Detect and fail if TargetMachine datalayout is different than what we
    260     // expect.  This is to detect changes in default target layout for x86 and
    261     // update X86_CUSTOM_DL_STRING in include/bcc/Config/Config.h appropriately.
    262     if (dl.getStringRepresentation().compare(X86_DEFAULT_DL_STRING) != 0) {
    263       return kErrInvalidTargetMachine;
    264     }
    265   }
    266 
    267   // Sanitize module's target information.
    268   module.setTargetTriple(getTargetMachine().getTargetTriple().str());
    269   module.setDataLayout(getTargetMachine().createDataLayout());
    270 
    271   // Materialize the bitcode module.
    272   if (module.getMaterializer() != nullptr) {
    273     // A module with non-null materializer means that it is a lazy-load module.
    274     // Materialize it now.  This function returns false when the materialization
    275     // is successful.
    276     std::error_code ec = module.materializeAll();
    277     if (ec) {
    278       ALOGE("Failed to materialize the module `%s'! (%s)",
    279             module.getModuleIdentifier().c_str(), ec.message().c_str());
    280       return kErrMaterialization;
    281     }
    282   }
    283 
    284   if ((err = runPasses(pScript, pResult)) != kSuccess) {
    285     return err;
    286   }
    287 
    288   if (IRStream) {
    289     *IRStream << module;
    290   }
    291 
    292   return kSuccess;
    293 }
    294 
    295 enum Compiler::ErrorCode Compiler::compile(Script &pScript,
    296                                            OutputFile &pResult,
    297                                            llvm::raw_ostream *IRStream) {
    298   // Check the state of the specified output file.
    299   if (pResult.hasError()) {
    300     return kErrInvalidOutputFileState;
    301   }
    302 
    303   // Open the output file decorated in llvm::raw_ostream.
    304   llvm::raw_pwrite_stream *out = pResult.dup();
    305   if (out == nullptr) {
    306     return kErrPrepareOutput;
    307   }
    308 
    309   // Delegate the request.
    310   enum Compiler::ErrorCode err = compile(pScript, *out, IRStream);
    311 
    312   // Close the output before return.
    313   delete out;
    314 
    315   return err;
    316 }
    317 
    318 bool Compiler::addInternalizeSymbolsPass(Script &pScript, llvm::legacy::PassManager &pPM) {
    319   // Add a pass to internalize the symbols that don't need to have global
    320   // visibility.
    321   RSScript &script = static_cast<RSScript &>(pScript);
    322   llvm::Module &module = script.getSource().getModule();
    323   bcinfo::MetadataExtractor me(&module);
    324   if (!me.extract()) {
    325     bccAssert(false && "Could not extract metadata for module!");
    326     return false;
    327   }
    328 
    329   // The vector contains the symbols that should not be internalized.
    330   std::vector<const char *> export_symbols;
    331 
    332   const char *sf[] = {
    333     kRoot,               // Graphics drawing function or compute kernel.
    334     kInit,               // Initialization routine called implicitly on startup.
    335     kRsDtor,             // Static global destructor for a script instance.
    336     kRsInfo,             // Variable containing string of RS metadata info.
    337     kRsGlobalEntries,    // Optional number of global variables.
    338     kRsGlobalNames,      // Optional global variable name info.
    339     kRsGlobalAddresses,  // Optional global variable address info.
    340     kRsGlobalSizes,      // Optional global variable size info.
    341     kRsGlobalProperties, // Optional global variable properties.
    342     nullptr              // Must be nullptr-terminated.
    343   };
    344   const char **special_functions = sf;
    345   // Special RS functions should always be global symbols.
    346   while (*special_functions != nullptr) {
    347     export_symbols.push_back(*special_functions);
    348     special_functions++;
    349   }
    350 
    351   // Visibility of symbols appeared in rs_export_var and rs_export_func should
    352   // also be preserved.
    353   size_t exportVarCount = me.getExportVarCount();
    354   size_t exportFuncCount = me.getExportFuncCount();
    355   size_t exportForEachCount = me.getExportForEachSignatureCount();
    356   size_t exportReduceCount = me.getExportReduceCount();
    357   const char **exportVarNameList = me.getExportVarNameList();
    358   const char **exportFuncNameList = me.getExportFuncNameList();
    359   const char **exportForEachNameList = me.getExportForEachNameList();
    360   const bcinfo::MetadataExtractor::Reduce *exportReduceList = me.getExportReduceList();
    361   size_t i;
    362 
    363   for (i = 0; i < exportVarCount; ++i) {
    364     export_symbols.push_back(exportVarNameList[i]);
    365   }
    366 
    367   for (i = 0; i < exportFuncCount; ++i) {
    368     export_symbols.push_back(exportFuncNameList[i]);
    369   }
    370 
    371   // Expanded foreach functions should not be internalized; nor should
    372   // general reduction initializer, combiner, and outconverter
    373   // functions. keep_funcs keeps the names of these functions around
    374   // until createInternalizePass() is finished making its own copy of
    375   // the visible symbols.
    376   std::vector<std::string> keep_funcs;
    377   keep_funcs.reserve(exportForEachCount + exportReduceCount*4);
    378 
    379   for (i = 0; i < exportForEachCount; ++i) {
    380     keep_funcs.push_back(std::string(exportForEachNameList[i]) + ".expand");
    381   }
    382   auto keepFuncsPushBackIfPresent = [&keep_funcs](const char *Name) {
    383     if (Name) keep_funcs.push_back(Name);
    384   };
    385   for (i = 0; i < exportReduceCount; ++i) {
    386     keep_funcs.push_back(std::string(exportReduceList[i].mAccumulatorName) + ".expand");
    387     keepFuncsPushBackIfPresent(exportReduceList[i].mInitializerName);
    388     if (exportReduceList[i].mCombinerName != nullptr) {
    389       keep_funcs.push_back(exportReduceList[i].mCombinerName);
    390     } else {
    391       keep_funcs.push_back(nameReduceCombinerFromAccumulator(exportReduceList[i].mAccumulatorName));
    392     }
    393     keepFuncsPushBackIfPresent(exportReduceList[i].mOutConverterName);
    394   }
    395 
    396   for (auto &symbol_name : keep_funcs) {
    397     export_symbols.push_back(symbol_name.c_str());
    398   }
    399 
    400   // http://b/26165616 - WAR for this bug defines the __truncxfhf2 function in
    401   // frameworks/rs/driver/runtime.  Don't internalize this function for x86, so
    402   // that a script can find and link against it.
    403   llvm::Triple triple(getTargetMachine().getTargetTriple());
    404   if (triple.getArch() == llvm::Triple::x86) {
    405     export_symbols.push_back("__truncxfhf2");
    406   }
    407 
    408   pPM.add(llvm::createInternalizePass(export_symbols));
    409 
    410   return true;
    411 }
    412 
    413 void Compiler::addInvokeHelperPass(llvm::legacy::PassManager &pPM) {
    414   llvm::Triple arch(getTargetMachine().getTargetTriple());
    415   if (arch.isArch64Bit()) {
    416     pPM.add(createRSInvokeHelperPass());
    417   }
    418 }
    419 
    420 void Compiler::addDebugInfoPass(Script &pScript, llvm::legacy::PassManager &pPM) {
    421   if (pScript.getSource().getDebugInfoEnabled())
    422     pPM.add(createRSAddDebugInfoPass());
    423 }
    424 
    425 void Compiler::addExpandKernelPass(llvm::legacy::PassManager &pPM) {
    426   // Expand ForEach and reduce on CPU path to reduce launch overhead.
    427   bool pEnableStepOpt = true;
    428   pPM.add(createRSKernelExpandPass(pEnableStepOpt));
    429 }
    430 
    431 void Compiler::addGlobalInfoPass(Script &pScript, llvm::legacy::PassManager &pPM) {
    432   // Add additional information about RS global variables inside the Module.
    433   RSScript &script = static_cast<RSScript &>(pScript);
    434   if (script.getEmbedGlobalInfo()) {
    435     pPM.add(createRSGlobalInfoPass(script.getEmbedGlobalInfoSkipConstant()));
    436   }
    437 }
    438 
    439 void Compiler::addInvariantPass(llvm::legacy::PassManager &pPM) {
    440   // Mark Loads from RsExpandKernelDriverInfo as "load.invariant".
    441   // Should run after ExpandForEach and before inlining.
    442   pPM.add(createRSInvariantPass());
    443 }
    444 
    445 enum Compiler::ErrorCode Compiler::screenGlobalFunctions(Script &pScript) {
    446   llvm::Module &module = pScript.getSource().getModule();
    447 
    448   // Materialize the bitcode module in case this is a lazy-load module.  Do not
    449   // clear the materializer by calling materializeAllPermanently since the
    450   // runtime library has not been merged into the module yet.
    451   if (module.getMaterializer() != nullptr) {
    452     std::error_code ec = module.materializeAll();
    453     if (ec) {
    454       ALOGE("Failed to materialize module `%s' when screening globals! (%s)",
    455             module.getModuleIdentifier().c_str(), ec.message().c_str());
    456       return kErrMaterialization;
    457     }
    458   }
    459 
    460   // Add pass to check for illegal function calls.
    461   llvm::legacy::PassManager pPM;
    462   pPM.add(createRSScreenFunctionsPass());
    463   pPM.run(module);
    464 
    465   return kSuccess;
    466 
    467 }
    468 
    469 void Compiler::translateGEPs(Script &pScript) {
    470   llvm::legacy::PassManager pPM;
    471   pPM.add(createRSX86TranslateGEPPass());
    472 
    473   // Materialization done in screenGlobalFunctions above.
    474   pPM.run(pScript.getSource().getModule());
    475 }
    476