• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015, 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 "RSUtils.h"
20 
21 #include "rsDefines.h"
22 
23 #include <llvm/IR/Constant.h>
24 #include <llvm/IR/Constants.h>
25 #include <llvm/IR/Type.h>
26 #include <llvm/IR/Module.h>
27 #include <llvm/IR/Function.h>
28 #include <llvm/Pass.h>
29 
30 #include <sstream>
31 #include <vector>
32 
33 namespace {
34 
35 const bool kDebugGlobalInfo = false;
36 
37 /* RSGlobalInfoPass: Embeds additional information about RenderScript global
38  * variables into the Module. The 5 variables added are specified as follows:
39  * 1) .rs.global_entries
40  *    i32 - int
41  *    Optional number of global variables.
42  * 2) .rs.global_names
43  *    [N * i8*] - const char *[N]
44  *    Optional global variable name info. Each entry corresponds to the name
45  *    of 1 of the N global variables.
46  * 3) .rs.global_addresses
47  *    [N * i8*] - void*[N] or void**
48  *    Optional global variable address info. Each entry corresponds to the
49  *    address of 1 of the N global variables.
50  * 4) .rs.global_sizes
51  *    [N * i32] or [N * i64] - size_t[N]
52  *    Optional global variable size info. Each entry corresponds to the size
53  *    of 1 of the N global variables.
54  * 5) .rs.global_properties
55  *    [N * i32]
56  *    Optional global properties. Each entry corresponds to the properties
57  *    for 1 of the N global variables. The 32-bit integer for properties
58  *    can be broken down as follows:
59  *    bit(s)    Encoded value
60  *    ------    -------------
61  *        18    Pointer (1 is pointer, 0 is non-pointer)
62  *        17    Static (1 is static, 0 is extern)
63  *        16    Constant (1 is const, 0 is non-const)
64  *    15 - 0    RsDataType (see frameworks/rs/rsDefines.h for more info)
65  */
66 class RSGlobalInfoPass: public llvm::ModulePass {
67 private:
68   // If true, we don't include information about immutable global variables
69   // in our various exported data structures.
70   bool mSkipConstants;
71 
72   // Encodes properties of the GlobalVariable into a uint32_t.
73   // These values are used to populate the .rs.global_properties array.
getEncodedProperties(const llvm::GlobalVariable & GV)74   static uint32_t getEncodedProperties(const llvm::GlobalVariable &GV) {
75     auto GlobalType = GV.getType()->getPointerElementType();
76 
77     // We start by getting the RsDataType and placing it into our result.
78     uint32_t result = getRsDataTypeForType(GlobalType);
79     bccAssert(!(result & ~RS_GLOBAL_TYPE));  // Can only alter lower 16-bits.
80 
81     if (GlobalType->isPointerTy()) {
82       // Global variables that are pointers can all be used with "bind".
83       result |= RS_GLOBAL_POINTER;
84     }
85 
86     if (GV.isConstant()) {
87       result |= RS_GLOBAL_CONSTANT;
88     }
89 
90     if (GV.getLinkage() == llvm::GlobalValue::InternalLinkage) {
91       // We only have internal linkage in RS to signify static.
92       result |= RS_GLOBAL_STATIC;
93     }
94 
95     return result;
96   }
97 
98 public:
99   static char ID;
100 
RSGlobalInfoPass(bool pSkipConstants=false)101   explicit RSGlobalInfoPass(bool pSkipConstants = false)
102     : ModulePass (ID), mSkipConstants(pSkipConstants) {
103   }
104 
getAnalysisUsage(llvm::AnalysisUsage & AU) const105   void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
106     // This pass does not use any other analysis passes, but it does
107     // add new global variables.
108   }
109 
runOnModule(llvm::Module & M)110   bool runOnModule(llvm::Module &M) override {
111     std::vector<llvm::Constant *> GVAddresses;
112     std::vector<llvm::Constant *> GVNames;
113     std::vector<std::string> GVNameStrings;
114     std::vector<uint32_t> GVSizes32;
115     std::vector<uint64_t> GVSizes64;
116     std::vector<uint32_t> GVProperties;
117 
118     const llvm::DataLayout &DL = M.getDataLayout();
119     const size_t PointerSizeInBits = DL.getPointerSizeInBits();
120 
121     bccAssert(PointerSizeInBits == 32 || PointerSizeInBits == 64);
122 
123     int GlobalNumber = 0;
124 
125     // i8* - LLVM uses this to represent void* and char*
126     llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(M.getContext());
127 
128     // i32
129     llvm::Type *Int32Ty = llvm::Type::getInt32Ty(M.getContext());
130 
131     // i32 or i64 depending on our actual size_t
132     llvm::Type *SizeTy = llvm::Type::getIntNTy(M.getContext(),
133                                                PointerSizeInBits);
134 
135     for (auto &GV : M.globals()) {
136       // Skip constant variables if we were configured to do so.
137       if (mSkipConstants && GV.isConstant()) {
138         continue;
139       }
140 
141       // Skip intrinsic variables.
142       if (GV.getName().startswith("llvm.")) {
143         continue;
144       }
145 
146       // In LLVM, an instance of GlobalVariable is actually a Value
147       // corresponding to the address of it.
148       GVAddresses.push_back(llvm::ConstantExpr::getBitCast(&GV, VoidPtrTy));
149       GVNameStrings.push_back(GV.getName());
150 
151       // Since these are all global variables, their type is actually a
152       // pointer to the underlying data. We can extract the total underlying
153       // storage size by looking at the first contained type.
154       auto GlobalType = GV.getType()->getPointerElementType();
155       auto TypeSize = DL.getTypeAllocSize(GlobalType);
156       if (PointerSizeInBits == 32) {
157         GVSizes32.push_back(TypeSize);
158       } else {
159         GVSizes64.push_back(TypeSize);
160       }
161 
162       GVProperties.push_back(getEncodedProperties(GV));
163     }
164 
165     // Create the new strings for storing the names of the global variables.
166     // This has to be done as a separate pass (over the original global
167     // variables), because these strings are new global variables themselves.
168     for (const auto &GVN : GVNameStrings) {
169       llvm::Constant *C =
170           llvm::ConstantDataArray::getString(M.getContext(), GVN);
171       std::stringstream VarName;
172       VarName << ".rs.name_str_" << GlobalNumber++;
173       llvm::Value *V = M.getOrInsertGlobal(VarName.str(), C->getType());
174       llvm::GlobalVariable *VarAsStr = llvm::dyn_cast<llvm::GlobalVariable>(V);
175       VarAsStr->setInitializer(C);
176       VarAsStr->setConstant(true);
177       VarAsStr->setLinkage(llvm::GlobalValue::PrivateLinkage);
178       VarAsStr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
179       // VarAsStr has type [_ x i8]*. Cast to i8* for storing in
180       // .rs.global_names.
181       GVNames.push_back(llvm::ConstantExpr::getBitCast(VarAsStr, VoidPtrTy));
182     }
183 
184     if (PointerSizeInBits == 32) {
185       bccAssert(GVAddresses.size() == GVSizes32.size());
186       bccAssert(GVSizes64.size() == 0);
187       bccAssert(GVAddresses.size() == GVProperties.size());
188     } else {
189       bccAssert(GVSizes32.size() == 0);
190       bccAssert(GVAddresses.size() == GVSizes64.size());
191       bccAssert(GVAddresses.size() == GVProperties.size());
192     }
193 
194     size_t NumGlobals = GVAddresses.size();
195 
196     // [NumGlobals * i8*]
197     llvm::ArrayType *VoidPtrArrayTy = llvm::ArrayType::get(VoidPtrTy,
198                                                            NumGlobals);
199     // [NumGlobals * i32] or [NumGlobals * i64]
200     llvm::ArrayType *SizeArrayTy = llvm::ArrayType::get(SizeTy, NumGlobals);
201 
202     // [NumGlobals * i32]
203     llvm::ArrayType *Int32ArrayTy = llvm::ArrayType::get(Int32Ty, NumGlobals);
204 
205     // 1) @.rs.global_entries = constant i32 NumGlobals
206     llvm::Value *V = M.getOrInsertGlobal(kRsGlobalEntries, Int32Ty);
207     llvm::GlobalVariable *GlobalEntries =
208         llvm::dyn_cast<llvm::GlobalVariable>(V);
209     llvm::Constant *GlobalEntriesInit =
210         llvm::ConstantInt::get(Int32Ty, NumGlobals);
211     GlobalEntries->setInitializer(GlobalEntriesInit);
212     GlobalEntries->setConstant(true);
213 
214     // 2) @.rs.global_names = constant [N * i8*] [...]
215     V = M.getOrInsertGlobal(kRsGlobalNames, VoidPtrArrayTy);
216     llvm::GlobalVariable *GlobalNames =
217         llvm::dyn_cast<llvm::GlobalVariable>(V);
218     llvm::Constant *GlobalNamesInit =
219         llvm::ConstantArray::get(VoidPtrArrayTy, GVNames);
220     GlobalNames->setInitializer(GlobalNamesInit);
221     GlobalNames->setConstant(true);
222 
223     // 3) @.rs.global_addresses = constant [N * i8*] [...]
224     V = M.getOrInsertGlobal(kRsGlobalAddresses, VoidPtrArrayTy);
225     llvm::GlobalVariable *GlobalAddresses =
226         llvm::dyn_cast<llvm::GlobalVariable>(V);
227     llvm::Constant *GlobalAddressesInit =
228         llvm::ConstantArray::get(VoidPtrArrayTy, GVAddresses);
229     GlobalAddresses->setInitializer(GlobalAddressesInit);
230     GlobalAddresses->setConstant(true);
231 
232 
233     // 4) @.rs.global_sizes = constant [N * i32 or i64] [...]
234     V = M.getOrInsertGlobal(kRsGlobalSizes, SizeArrayTy);
235     llvm::GlobalVariable *GlobalSizes =
236         llvm::dyn_cast<llvm::GlobalVariable>(V);
237     llvm::Constant *GlobalSizesInit;
238     if (PointerSizeInBits == 32) {
239       GlobalSizesInit = llvm::ConstantDataArray::get(M.getContext(), GVSizes32);
240     } else {
241       GlobalSizesInit = llvm::ConstantDataArray::get(M.getContext(), GVSizes64);
242     }
243     GlobalSizes->setInitializer(GlobalSizesInit);
244     GlobalSizes->setConstant(true);
245 
246     // 5) @.rs.global_properties = constant i32 NumGlobals
247     V = M.getOrInsertGlobal(kRsGlobalProperties, Int32ArrayTy);
248     llvm::GlobalVariable *GlobalProperties =
249         llvm::dyn_cast<llvm::GlobalVariable>(V);
250     llvm::Constant *GlobalPropertiesInit =
251         llvm::ConstantDataArray::get(M.getContext(), GVProperties);
252     GlobalProperties->setInitializer(GlobalPropertiesInit);
253     GlobalProperties->setConstant(true);
254 
255     if (kDebugGlobalInfo) {
256       GlobalEntries->dump();
257       GlobalNames->dump();
258       GlobalAddresses->dump();
259       GlobalSizes->dump();
260       GlobalProperties->dump();
261     }
262 
263     // Upon completion, this pass has always modified the Module.
264     return true;
265   }
266 };
267 
268 }
269 
270 char RSGlobalInfoPass::ID = 0;
271 
272 static llvm::RegisterPass<RSGlobalInfoPass> X("embed-rs-global-info",
273   "Embed additional information about RenderScript global variables");
274 
275 namespace bcc {
276 
createRSGlobalInfoPass(bool pSkipConstants)277 llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants) {
278   return new RSGlobalInfoPass(pSkipConstants);
279 }
280 
281 }
282