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