blob: 40d658b7199035719dfa2a3a7465917c5df15034 [file] [log] [blame]
Stephen Hines750ee652015-04-16 16:24:18 -07001/*
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
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080017#include "Assert.h"
18#include "Log.h"
19#include "RSUtils.h"
Stephen Hines750ee652015-04-16 16:24:18 -070020
Stephen Hinesfb81ec12015-05-18 20:04:23 -070021#include "rsDefines.h"
22
Stephen Hines750ee652015-04-16 16:24:18 -070023#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
33namespace {
34
Stephen Hinesfb81ec12015-05-18 20:04:23 -070035const bool kDebugGlobalInfo = false;
Stephen Hines750ee652015-04-16 16:24:18 -070036
37/* RSGlobalInfoPass: Embeds additional information about RenderScript global
Stephen Hinesfb81ec12015-05-18 20:04:23 -070038 * variables into the Module. The 5 variables added are specified as follows:
Stephen Hines750ee652015-04-16 16:24:18 -070039 * 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.
Stephen Hinesfb81ec12015-05-18 20:04:23 -070054 * 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)
Stephen Hines750ee652015-04-16 16:24:18 -070065 */
66class RSGlobalInfoPass: public llvm::ModulePass {
67private:
Stephen Hines750ee652015-04-16 16:24:18 -070068 // If true, we don't include information about immutable global variables
69 // in our various exported data structures.
70 bool mSkipConstants;
71
Stephen Hinesfb81ec12015-05-18 20:04:23 -070072 // Encodes properties of the GlobalVariable into a uint32_t.
73 // These values are used to populate the .rs.global_properties array.
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
98public:
99 static char ID;
100
Chih-Hung Hsieh7e920a72016-04-29 14:51:50 -0700101 explicit RSGlobalInfoPass(bool pSkipConstants = false)
Stephen Hines750ee652015-04-16 16:24:18 -0700102 : ModulePass (ID), mSkipConstants(pSkipConstants) {
103 }
104
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700105 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
Stephen Hines750ee652015-04-16 16:24:18 -0700106 // This pass does not use any other analysis passes, but it does
107 // add new global variables.
108 }
109
110 bool runOnModule(llvm::Module &M) override {
111 std::vector<llvm::Constant *> GVAddresses;
112 std::vector<llvm::Constant *> GVNames;
Matt Wala721414c2015-06-09 15:34:37 -0700113 std::vector<std::string> GVNameStrings;
Stephen Hines750ee652015-04-16 16:24:18 -0700114 std::vector<uint32_t> GVSizes32;
115 std::vector<uint64_t> GVSizes64;
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700116 std::vector<uint32_t> GVProperties;
Stephen Hines750ee652015-04-16 16:24:18 -0700117
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
Matt Wala721414c2015-06-09 15:34:37 -0700125 // 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
Stephen Hines750ee652015-04-16 16:24:18 -0700135 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
David Grosse32af522016-01-15 12:15:48 -0800141 // Skip intrinsic variables.
142 if (GV.getName().startswith("llvm.")) {
143 continue;
144 }
145
Stephen Hines750ee652015-04-16 16:24:18 -0700146 // In LLVM, an instance of GlobalVariable is actually a Value
147 // corresponding to the address of it.
Matt Wala721414c2015-06-09 15:34:37 -0700148 GVAddresses.push_back(llvm::ConstantExpr::getBitCast(&GV, VoidPtrTy));
149 GVNameStrings.push_back(GV.getName());
Stephen Hines750ee652015-04-16 16:24:18 -0700150
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.
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700154 auto GlobalType = GV.getType()->getPointerElementType();
155 auto TypeSize = DL.getTypeAllocSize(GlobalType);
Stephen Hines750ee652015-04-16 16:24:18 -0700156 if (PointerSizeInBits == 32) {
157 GVSizes32.push_back(TypeSize);
158 } else {
159 GVSizes64.push_back(TypeSize);
160 }
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700161
162 GVProperties.push_back(getEncodedProperties(GV));
Stephen Hines750ee652015-04-16 16:24:18 -0700163 }
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.
Chih-Hung Hsieh8a019dd2016-08-12 15:49:55 -0700168 for (const auto &GVN : GVNameStrings) {
Stephen Hines750ee652015-04-16 16:24:18 -0700169 llvm::Constant *C =
Matt Wala721414c2015-06-09 15:34:37 -0700170 llvm::ConstantDataArray::getString(M.getContext(), GVN);
Stephen Hines750ee652015-04-16 16:24:18 -0700171 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);
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700178 VarAsStr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
Matt Wala721414c2015-06-09 15:34:37 -0700179 // VarAsStr has type [_ x i8]*. Cast to i8* for storing in
180 // .rs.global_names.
181 GVNames.push_back(llvm::ConstantExpr::getBitCast(VarAsStr, VoidPtrTy));
Stephen Hines750ee652015-04-16 16:24:18 -0700182 }
183
184 if (PointerSizeInBits == 32) {
185 bccAssert(GVAddresses.size() == GVSizes32.size());
186 bccAssert(GVSizes64.size() == 0);
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700187 bccAssert(GVAddresses.size() == GVProperties.size());
Stephen Hines750ee652015-04-16 16:24:18 -0700188 } else {
189 bccAssert(GVSizes32.size() == 0);
190 bccAssert(GVAddresses.size() == GVSizes64.size());
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700191 bccAssert(GVAddresses.size() == GVProperties.size());
Stephen Hines750ee652015-04-16 16:24:18 -0700192 }
Matt Wala721414c2015-06-09 15:34:37 -0700193
Stephen Hines750ee652015-04-16 16:24:18 -0700194 size_t NumGlobals = GVAddresses.size();
195
Stephen Hines750ee652015-04-16 16:24:18 -0700196 // [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
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700202 // [NumGlobals * i32]
203 llvm::ArrayType *Int32ArrayTy = llvm::ArrayType::get(Int32Ty, NumGlobals);
204
Stephen Hines750ee652015-04-16 16:24:18 -0700205 // 1) @.rs.global_entries = constant i32 NumGlobals
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700206 llvm::Value *V = M.getOrInsertGlobal(kRsGlobalEntries, Int32Ty);
Stephen Hines750ee652015-04-16 16:24:18 -0700207 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*] [...]
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700215 V = M.getOrInsertGlobal(kRsGlobalNames, VoidPtrArrayTy);
Stephen Hines750ee652015-04-16 16:24:18 -0700216 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*] [...]
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700224 V = M.getOrInsertGlobal(kRsGlobalAddresses, VoidPtrArrayTy);
Stephen Hines750ee652015-04-16 16:24:18 -0700225 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] [...]
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700234 V = M.getOrInsertGlobal(kRsGlobalSizes, SizeArrayTy);
Stephen Hines750ee652015-04-16 16:24:18 -0700235 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
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700246 // 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
Stephen Hines750ee652015-04-16 16:24:18 -0700255 if (kDebugGlobalInfo) {
256 GlobalEntries->dump();
257 GlobalNames->dump();
258 GlobalAddresses->dump();
259 GlobalSizes->dump();
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700260 GlobalProperties->dump();
Stephen Hines750ee652015-04-16 16:24:18 -0700261 }
262
263 // Upon completion, this pass has always modified the Module.
264 return true;
265 }
266};
267
268}
269
270char RSGlobalInfoPass::ID = 0;
271
272static llvm::RegisterPass<RSGlobalInfoPass> X("embed-rs-global-info",
273 "Embed additional information about RenderScript global variables");
274
275namespace bcc {
276
277llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants) {
278 return new RSGlobalInfoPass(pSkipConstants);
279}
280
281}