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