Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 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 "Assert.h"
     18 #include "Log.h"
     19 #include "RSTransforms.h"
     20 #include "RSUtils.h"
     21 #include "rsDefines.h"
     22 
     23 #include "bcc/Config.h"
     24 #include "bcinfo/MetadataExtractor.h"
     25 
     26 #include <string>
     27 #include <cstdlib>
     28 #include <vector>
     29 
     30 #include <llvm/IR/DerivedTypes.h>
     31 #include <llvm/IR/Function.h>
     32 #include <llvm/IR/Metadata.h>
     33 #include <llvm/IR/Instructions.h>
     34 #include <llvm/IR/IRBuilder.h>
     35 #include <llvm/IR/Module.h>
     36 #include <llvm/Pass.h>
     37 #include <llvm/Support/raw_ostream.h>
     38 #include <llvm/IR/Type.h>
     39 
     40 using namespace bcc;
     41 
     42 namespace {
     43 
     44 /* RSEmbedInfoPass - This pass operates on the entire module and embeds a
     45  * string constaining relevant metadata directly as a global variable.
     46  * This information does not need to be consistent across Android releases,
     47  * because the standalone compiler + compatibility driver or system driver
     48  * will be using the same format (i.e. bcc_compat + libRSSupport.so or
     49  * bcc + libRSCpuRef are always paired together for installation).
     50  */
     51 class RSEmbedInfoPass : public llvm::ModulePass {
     52 private:
     53   static char ID;
     54 
     55   llvm::Module *M;
     56   llvm::LLVMContext *C;
     57 
     58 public:
     59   RSEmbedInfoPass()
     60       : ModulePass(ID),
     61         M(nullptr) {
     62   }
     63 
     64   virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
     65     AU.setPreservesAll();
     66   }
     67 
     68   static std::string getRSInfoString(const llvm::Module *module) {
     69     std::string str;
     70     llvm::raw_string_ostream s(str);
     71     bcinfo::MetadataExtractor me(module);
     72     if (!me.extract()) {
     73       bccAssert(false && "Could not extract RS metadata for module!");
     74       return std::string("");
     75     }
     76 
     77     size_t exportVarCount = me.getExportVarCount();
     78     size_t exportFuncCount = me.getExportFuncCount();
     79     size_t exportForEachCount = me.getExportForEachSignatureCount();
     80     size_t exportReduceCount = me.getExportReduceCount();
     81     size_t objectSlotCount = me.getObjectSlotCount();
     82     size_t pragmaCount = me.getPragmaCount();
     83     const char **exportVarNameList = me.getExportVarNameList();
     84     const char **exportFuncNameList = me.getExportFuncNameList();
     85     const char **exportForEachNameList = me.getExportForEachNameList();
     86     const uint32_t *exportForEachSignatureList =
     87         me.getExportForEachSignatureList();
     88     const bcinfo::MetadataExtractor::Reduce *exportReduceList =
     89         me.getExportReduceList();
     90     const uint32_t *objectSlotList = me.getObjectSlotList();
     91     const char **pragmaKeyList = me.getPragmaKeyList();
     92     const char **pragmaValueList = me.getPragmaValueList();
     93     bool isThreadable = me.isThreadable();
     94     const char *buildChecksum = me.getBuildChecksum();
     95 
     96     size_t i;
     97 
     98     // We use a simple text format here that the compatibility library
     99     // can easily parse. Each section starts out with its name
    100     // followed by a count.  The count denotes the number of lines to
    101     // parse for that particular category. Variables and Functions
    102     // merely put the appropriate identifier on the line. ForEach
    103     // kernels have the encoded int signature, followed by a hyphen
    104     // followed by the identifier (function to look up). General
    105     // reduce kernels have the encoded int signature, followed by a
    106     // hyphen followed by the accumulator data size, followed by a
    107     // hyphen followed by the identifier (reduction name); and then
    108     // for each possible constituent function, a hyphen followed by
    109     // the identifier (function name) -- in the case where the
    110     // function is omitted, "." is used in place of the identifier.
    111     // Object Slots are just listed as one integer per line.
    112 
    113     s << "exportVarCount: " << exportVarCount << "\n";
    114     for (i = 0; i < exportVarCount; ++i) {
    115       s << exportVarNameList[i] << "\n";
    116     }
    117 
    118     s << "exportFuncCount: " << exportFuncCount << "\n";
    119     for (i = 0; i < exportFuncCount; ++i) {
    120       s << exportFuncNameList[i] << "\n";
    121     }
    122 
    123     s << "exportForEachCount: " << exportForEachCount << "\n";
    124     for (i = 0; i < exportForEachCount; ++i) {
    125       s << exportForEachSignatureList[i] << " - "
    126         << exportForEachNameList[i] << "\n";
    127     }
    128 
    129     s << "exportReduceCount: " << exportReduceCount << "\n";
    130     auto reduceFnName = [](const char *Name) { return Name ? Name : "."; };
    131     for (i = 0; i < exportReduceCount; ++i) {
    132       const bcinfo::MetadataExtractor::Reduce &reduce = exportReduceList[i];
    133       s << reduce.mSignature << " - "
    134         << reduce.mAccumulatorDataSize << " - "
    135         << reduce.mReduceName << " - "
    136         << reduceFnName(reduce.mInitializerName) << " - "
    137         << reduceFnName(reduce.mAccumulatorName) << " - "
    138         << ((reduce.mCombinerName != nullptr)
    139             ? reduce.mCombinerName
    140             : nameReduceCombinerFromAccumulator(reduce.mAccumulatorName)) << " - "
    141         << reduceFnName(reduce.mOutConverterName) << " - "
    142         << reduceFnName(reduce.mHalterName)
    143         << "\n";
    144     }
    145 
    146     s << "objectSlotCount: " << objectSlotCount << "\n";
    147     for (i = 0; i < objectSlotCount; ++i) {
    148       s << objectSlotList[i] << "\n";
    149     }
    150 
    151     s << "pragmaCount: " << pragmaCount << "\n";
    152     for (i = 0; i < pragmaCount; ++i) {
    153       s << pragmaKeyList[i] << " - "
    154         << pragmaValueList[i] << "\n";
    155     }
    156     s << "isThreadable: " << ((isThreadable) ? "yes" : "no") << "\n";
    157 
    158     if (buildChecksum != nullptr && buildChecksum[0]) {
    159       s << "buildChecksum: " << buildChecksum << "\n";
    160     }
    161 
    162     {
    163       // As per `exportReduceCount`'s linewise fields, we use the literal `"."`
    164       // to signify the empty field. This makes it easy to parse when it's
    165       // missing.
    166       llvm::StringRef slangVersion(".");
    167       if (auto nmd = module->getNamedMetadata("slang.llvm.version")) {
    168         if (auto md = nmd->getOperand(0)) {
    169           if (const auto ver =
    170                   llvm::dyn_cast<llvm::MDString>(md->getOperand(0))) {
    171             slangVersion = ver->getString();
    172           }
    173         }
    174       }
    175       s << "versionInfo: 2\n";
    176       s << "bcc - " << LLVM_VERSION_STRING << "\n";
    177       s << "slang - " << slangVersion << "\n";
    178       if (slangVersion != LLVM_VERSION_STRING && me.hasDebugInfo()) {
    179         ALOGW(
    180             "The debug info in module '%s' has a different version than "
    181             "expected (%s, expecting %s). The debugging experience may be "
    182             "unreliable.",
    183             module->getModuleIdentifier().c_str(), slangVersion.str().c_str(),
    184             LLVM_VERSION_STRING);
    185       }
    186     }
    187 
    188     s.flush();
    189     return str;
    190   }
    191 
    192   virtual bool runOnModule(llvm::Module &M) {
    193     this->M = &M;
    194     C = &M.getContext();
    195 
    196     // Embed this as the global variable .rs.info so that it will be
    197     // accessible from the shared object later.
    198     llvm::Constant *Init = llvm::ConstantDataArray::getString(*C,
    199                                                               getRSInfoString(&M));
    200     llvm::GlobalVariable *InfoGV =
    201         new llvm::GlobalVariable(M, Init->getType(), true,
    202                                  llvm::GlobalValue::ExternalLinkage, Init,
    203                                  kRsInfo);
    204     (void) InfoGV;
    205 
    206     return true;
    207   }
    208 
    209   virtual const char *getPassName() const {
    210     return "Embed Renderscript Info";
    211   }
    212 
    213 };  // end RSEmbedInfoPass
    214 
    215 }  // end anonymous namespace
    216 
    217 char RSEmbedInfoPass::ID = 0;
    218 
    219 namespace bcc {
    220 
    221 llvm::ModulePass *
    222 createRSEmbedInfoPass() {
    223   return new RSEmbedInfoPass();
    224 }
    225 
    226 }  // end namespace bcc
    227