Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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 | |
Jean-Luc Brouillet | a2dd52f | 2017-02-16 20:57:26 -0800 | [diff] [blame] | 17 | #include "Assert.h" |
| 18 | #include "Log.h" |
| 19 | #include "RSUtils.h" |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 20 | |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 21 | #include "rsDefines.h" |
| 22 | |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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 | |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 35 | const bool kDebugGlobalInfo = false; |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 36 | |
| 37 | /* RSGlobalInfoPass: Embeds additional information about RenderScript global |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 38 | * variables into the Module. The 5 variables added are specified as follows: |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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. |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 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) |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 65 | */ |
| 66 | class RSGlobalInfoPass: public llvm::ModulePass { |
| 67 | private: |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 68 | // If true, we don't include information about immutable global variables |
| 69 | // in our various exported data structures. |
| 70 | bool mSkipConstants; |
| 71 | |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 72 | // 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 | |
| 98 | public: |
| 99 | static char ID; |
| 100 | |
Chih-Hung Hsieh | 7e920a7 | 2016-04-29 14:51:50 -0700 | [diff] [blame] | 101 | explicit RSGlobalInfoPass(bool pSkipConstants = false) |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 102 | : ModulePass (ID), mSkipConstants(pSkipConstants) { |
| 103 | } |
| 104 | |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 105 | void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 106 | // 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 Wala | 721414c | 2015-06-09 15:34:37 -0700 | [diff] [blame] | 113 | std::vector<std::string> GVNameStrings; |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 114 | std::vector<uint32_t> GVSizes32; |
| 115 | std::vector<uint64_t> GVSizes64; |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 116 | std::vector<uint32_t> GVProperties; |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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 | |
Matt Wala | 721414c | 2015-06-09 15:34:37 -0700 | [diff] [blame] | 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 | |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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 | |
David Gross | e32af52 | 2016-01-15 12:15:48 -0800 | [diff] [blame] | 141 | // Skip intrinsic variables. |
| 142 | if (GV.getName().startswith("llvm.")) { |
| 143 | continue; |
| 144 | } |
| 145 | |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 146 | // In LLVM, an instance of GlobalVariable is actually a Value |
| 147 | // corresponding to the address of it. |
Matt Wala | 721414c | 2015-06-09 15:34:37 -0700 | [diff] [blame] | 148 | GVAddresses.push_back(llvm::ConstantExpr::getBitCast(&GV, VoidPtrTy)); |
| 149 | GVNameStrings.push_back(GV.getName()); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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. |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 154 | auto GlobalType = GV.getType()->getPointerElementType(); |
| 155 | auto TypeSize = DL.getTypeAllocSize(GlobalType); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 156 | if (PointerSizeInBits == 32) { |
| 157 | GVSizes32.push_back(TypeSize); |
| 158 | } else { |
| 159 | GVSizes64.push_back(TypeSize); |
| 160 | } |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 161 | |
| 162 | GVProperties.push_back(getEncodedProperties(GV)); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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. |
Chih-Hung Hsieh | 8a019dd | 2016-08-12 15:49:55 -0700 | [diff] [blame] | 168 | for (const auto &GVN : GVNameStrings) { |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 169 | llvm::Constant *C = |
Matt Wala | 721414c | 2015-06-09 15:34:37 -0700 | [diff] [blame] | 170 | llvm::ConstantDataArray::getString(M.getContext(), GVN); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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); |
Pirama Arumuga Nainar | f5b49a0 | 2016-09-15 23:04:25 -0700 | [diff] [blame] | 178 | VarAsStr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); |
Matt Wala | 721414c | 2015-06-09 15:34:37 -0700 | [diff] [blame] | 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)); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | if (PointerSizeInBits == 32) { |
| 185 | bccAssert(GVAddresses.size() == GVSizes32.size()); |
| 186 | bccAssert(GVSizes64.size() == 0); |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 187 | bccAssert(GVAddresses.size() == GVProperties.size()); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 188 | } else { |
| 189 | bccAssert(GVSizes32.size() == 0); |
| 190 | bccAssert(GVAddresses.size() == GVSizes64.size()); |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 191 | bccAssert(GVAddresses.size() == GVProperties.size()); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 192 | } |
Matt Wala | 721414c | 2015-06-09 15:34:37 -0700 | [diff] [blame] | 193 | |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 194 | size_t NumGlobals = GVAddresses.size(); |
| 195 | |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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 | |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 202 | // [NumGlobals * i32] |
| 203 | llvm::ArrayType *Int32ArrayTy = llvm::ArrayType::get(Int32Ty, NumGlobals); |
| 204 | |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 205 | // 1) @.rs.global_entries = constant i32 NumGlobals |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 206 | llvm::Value *V = M.getOrInsertGlobal(kRsGlobalEntries, Int32Ty); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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*] [...] |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 215 | V = M.getOrInsertGlobal(kRsGlobalNames, VoidPtrArrayTy); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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*] [...] |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 224 | V = M.getOrInsertGlobal(kRsGlobalAddresses, VoidPtrArrayTy); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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] [...] |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 234 | V = M.getOrInsertGlobal(kRsGlobalSizes, SizeArrayTy); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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 | |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 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 | |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 255 | if (kDebugGlobalInfo) { |
| 256 | GlobalEntries->dump(); |
| 257 | GlobalNames->dump(); |
| 258 | GlobalAddresses->dump(); |
| 259 | GlobalSizes->dump(); |
Stephen Hines | fb81ec1 | 2015-05-18 20:04:23 -0700 | [diff] [blame] | 260 | GlobalProperties->dump(); |
Stephen Hines | 750ee65 | 2015-04-16 16:24:18 -0700 | [diff] [blame] | 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 | |
| 277 | llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants) { |
| 278 | return new RSGlobalInfoPass(pSkipConstants); |
| 279 | } |
| 280 | |
| 281 | } |