Home | History | Annotate | Download | only in lib
      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