| /* |
| * Copyright 2012, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "Assert.h" |
| #include "Log.h" |
| #include "RSTransforms.h" |
| #include "RSUtils.h" |
| #include "rsDefines.h" |
| |
| #include "bcc/Config.h" |
| #include "bcinfo/MetadataExtractor.h" |
| |
| #include <string> |
| #include <cstdlib> |
| #include <vector> |
| |
| #include <llvm/IR/DerivedTypes.h> |
| #include <llvm/IR/Function.h> |
| #include <llvm/IR/Metadata.h> |
| #include <llvm/IR/Instructions.h> |
| #include <llvm/IR/IRBuilder.h> |
| #include <llvm/IR/Module.h> |
| #include <llvm/Pass.h> |
| #include <llvm/Support/raw_ostream.h> |
| #include <llvm/IR/Type.h> |
| |
| using namespace bcc; |
| |
| namespace { |
| |
| /* RSEmbedInfoPass - This pass operates on the entire module and embeds a |
| * string constaining relevant metadata directly as a global variable. |
| * This information does not need to be consistent across Android releases, |
| * because the standalone compiler + compatibility driver or system driver |
| * will be using the same format (i.e. bcc_compat + libRSSupport.so or |
| * bcc + libRSCpuRef are always paired together for installation). |
| */ |
| class RSEmbedInfoPass : public llvm::ModulePass { |
| private: |
| static char ID; |
| |
| llvm::Module *M; |
| llvm::LLVMContext *C; |
| |
| public: |
| RSEmbedInfoPass() |
| : ModulePass(ID), |
| M(nullptr) { |
| } |
| |
| virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { |
| AU.setPreservesAll(); |
| } |
| |
| static std::string getRSInfoString(const llvm::Module *module) { |
| std::string str; |
| llvm::raw_string_ostream s(str); |
| bcinfo::MetadataExtractor me(module); |
| if (!me.extract()) { |
| bccAssert(false && "Could not extract RS metadata for module!"); |
| return std::string(""); |
| } |
| |
| size_t exportVarCount = me.getExportVarCount(); |
| size_t exportFuncCount = me.getExportFuncCount(); |
| size_t exportForEachCount = me.getExportForEachSignatureCount(); |
| size_t exportReduceCount = me.getExportReduceCount(); |
| size_t objectSlotCount = me.getObjectSlotCount(); |
| size_t pragmaCount = me.getPragmaCount(); |
| const char **exportVarNameList = me.getExportVarNameList(); |
| const char **exportFuncNameList = me.getExportFuncNameList(); |
| const char **exportForEachNameList = me.getExportForEachNameList(); |
| const uint32_t *exportForEachSignatureList = |
| me.getExportForEachSignatureList(); |
| const bcinfo::MetadataExtractor::Reduce *exportReduceList = |
| me.getExportReduceList(); |
| const uint32_t *objectSlotList = me.getObjectSlotList(); |
| const char **pragmaKeyList = me.getPragmaKeyList(); |
| const char **pragmaValueList = me.getPragmaValueList(); |
| bool isThreadable = me.isThreadable(); |
| const char *buildChecksum = me.getBuildChecksum(); |
| |
| size_t i; |
| |
| // We use a simple text format here that the compatibility library |
| // can easily parse. Each section starts out with its name |
| // followed by a count. The count denotes the number of lines to |
| // parse for that particular category. Variables and Functions |
| // merely put the appropriate identifier on the line. ForEach |
| // kernels have the encoded int signature, followed by a hyphen |
| // followed by the identifier (function to look up). General |
| // reduce kernels have the encoded int signature, followed by a |
| // hyphen followed by the accumulator data size, followed by a |
| // hyphen followed by the identifier (reduction name); and then |
| // for each possible constituent function, a hyphen followed by |
| // the identifier (function name) -- in the case where the |
| // function is omitted, "." is used in place of the identifier. |
| // Object Slots are just listed as one integer per line. |
| |
| s << "exportVarCount: " << exportVarCount << "\n"; |
| for (i = 0; i < exportVarCount; ++i) { |
| s << exportVarNameList[i] << "\n"; |
| } |
| |
| s << "exportFuncCount: " << exportFuncCount << "\n"; |
| for (i = 0; i < exportFuncCount; ++i) { |
| s << exportFuncNameList[i] << "\n"; |
| } |
| |
| s << "exportForEachCount: " << exportForEachCount << "\n"; |
| for (i = 0; i < exportForEachCount; ++i) { |
| s << exportForEachSignatureList[i] << " - " |
| << exportForEachNameList[i] << "\n"; |
| } |
| |
| s << "exportReduceCount: " << exportReduceCount << "\n"; |
| auto reduceFnName = [](const char *Name) { return Name ? Name : "."; }; |
| for (i = 0; i < exportReduceCount; ++i) { |
| const bcinfo::MetadataExtractor::Reduce &reduce = exportReduceList[i]; |
| s << reduce.mSignature << " - " |
| << reduce.mAccumulatorDataSize << " - " |
| << reduce.mReduceName << " - " |
| << reduceFnName(reduce.mInitializerName) << " - " |
| << reduceFnName(reduce.mAccumulatorName) << " - " |
| << ((reduce.mCombinerName != nullptr) |
| ? reduce.mCombinerName |
| : nameReduceCombinerFromAccumulator(reduce.mAccumulatorName)) << " - " |
| << reduceFnName(reduce.mOutConverterName) << " - " |
| << reduceFnName(reduce.mHalterName) |
| << "\n"; |
| } |
| |
| s << "objectSlotCount: " << objectSlotCount << "\n"; |
| for (i = 0; i < objectSlotCount; ++i) { |
| s << objectSlotList[i] << "\n"; |
| } |
| |
| s << "pragmaCount: " << pragmaCount << "\n"; |
| for (i = 0; i < pragmaCount; ++i) { |
| s << pragmaKeyList[i] << " - " |
| << pragmaValueList[i] << "\n"; |
| } |
| s << "isThreadable: " << ((isThreadable) ? "yes" : "no") << "\n"; |
| |
| if (buildChecksum != nullptr && buildChecksum[0]) { |
| s << "buildChecksum: " << buildChecksum << "\n"; |
| } |
| |
| { |
| // As per `exportReduceCount`'s linewise fields, we use the literal `"."` |
| // to signify the empty field. This makes it easy to parse when it's |
| // missing. |
| llvm::StringRef slangVersion("."); |
| if (auto nmd = module->getNamedMetadata("slang.llvm.version")) { |
| if (auto md = nmd->getOperand(0)) { |
| if (const auto ver = |
| llvm::dyn_cast<llvm::MDString>(md->getOperand(0))) { |
| slangVersion = ver->getString(); |
| } |
| } |
| } |
| s << "versionInfo: 2\n"; |
| s << "bcc - " << LLVM_VERSION_STRING << "\n"; |
| s << "slang - " << slangVersion << "\n"; |
| if (slangVersion != LLVM_VERSION_STRING && me.hasDebugInfo()) { |
| ALOGW( |
| "The debug info in module '%s' has a different version than " |
| "expected (%s, expecting %s). The debugging experience may be " |
| "unreliable.", |
| module->getModuleIdentifier().c_str(), slangVersion.str().c_str(), |
| LLVM_VERSION_STRING); |
| } |
| } |
| |
| s.flush(); |
| return str; |
| } |
| |
| virtual bool runOnModule(llvm::Module &M) { |
| this->M = &M; |
| C = &M.getContext(); |
| |
| // Embed this as the global variable .rs.info so that it will be |
| // accessible from the shared object later. |
| llvm::Constant *Init = llvm::ConstantDataArray::getString(*C, |
| getRSInfoString(&M)); |
| llvm::GlobalVariable *InfoGV = |
| new llvm::GlobalVariable(M, Init->getType(), true, |
| llvm::GlobalValue::ExternalLinkage, Init, |
| kRsInfo); |
| (void) InfoGV; |
| |
| return true; |
| } |
| |
| virtual const char *getPassName() const { |
| return "Embed Renderscript Info"; |
| } |
| |
| }; // end RSEmbedInfoPass |
| |
| } // end anonymous namespace |
| |
| char RSEmbedInfoPass::ID = 0; |
| |
| namespace bcc { |
| |
| llvm::ModulePass * |
| createRSEmbedInfoPass() { |
| return new RSEmbedInfoPass(); |
| } |
| |
| } // end namespace bcc |