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