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. 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 101 explicit RSGlobalInfoPass(bool pSkipConstants = false) 102 : ModulePass (ID), mSkipConstants(pSkipConstants) { 103 } 104 105 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 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 277 llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants) { 278 return new RSGlobalInfoPass(pSkipConstants); 279 } 280 281 } 282