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:
RSEmbedInfoPass()59   RSEmbedInfoPass()
60       : ModulePass(ID),
61         M(nullptr) {
62   }
63 
getAnalysisUsage(llvm::AnalysisUsage & AU) const64   virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
65     AU.setPreservesAll();
66   }
67 
getRSInfoString(const llvm::Module * module)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 
runOnModule(llvm::Module & M)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 
getPassName() const209   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 *
createRSEmbedInfoPass()222 createRSEmbedInfoPass() {
223   return new RSEmbedInfoPass();
224 }
225 
226 }  // end namespace bcc
227