Provide additional information about global variables.

Bug: 20306487

This patch extends our global information pass to include details about the
type of a global variable, whether or not it is static, constant, or a
pointer. It also refactors code that deals with conversion between
RenderScript's internal data types and LLVM's type system. A subtle bug
has also been fixed with respect to the RSInvokeHelperPass. The previous
version could ignore an rs_* object that did not have a numeric suffix.
The new helper function properly addresses cases like this.

Change-Id: If9c933a885bf6a9063b7edec3f0873e1b144188d
diff --git a/lib/Renderscript/RSEmbedInfo.cpp b/lib/Renderscript/RSEmbedInfo.cpp
index 65f7ed7..dc1033c 100644
--- a/lib/Renderscript/RSEmbedInfo.cpp
+++ b/lib/Renderscript/RSEmbedInfo.cpp
@@ -15,7 +15,11 @@
  */
 
 #include "bcc/Assert.h"
+#include "bcc/Config/Config.h"
 #include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Support/Log.h"
+#include "bcinfo/MetadataExtractor.h"
+#include "rsDefines.h"
 
 #include <cstdlib>
 #include <vector>
@@ -29,10 +33,6 @@
 #include <llvm/Support/raw_ostream.h>
 #include <llvm/IR/Type.h>
 
-#include "bcc/Config/Config.h"
-#include "bcc/Support/Log.h"
-#include "bcinfo/MetadataExtractor.h"
-
 using namespace bcc;
 
 namespace {
@@ -142,7 +142,7 @@
     llvm::GlobalVariable *InfoGV =
         new llvm::GlobalVariable(M, Init->getType(), true,
                                  llvm::GlobalValue::ExternalLinkage, Init,
-                                 ".rs.info");
+                                 kRsInfo);
     (void) InfoGV;
 
     return true;
diff --git a/lib/Renderscript/RSGlobalInfoPass.cpp b/lib/Renderscript/RSGlobalInfoPass.cpp
index a4ee386..c6a14a0 100644
--- a/lib/Renderscript/RSGlobalInfoPass.cpp
+++ b/lib/Renderscript/RSGlobalInfoPass.cpp
@@ -15,8 +15,11 @@
  */
 
 #include "bcc/Assert.h"
+#include "bcc/Renderscript/RSUtils.h"
 #include "bcc/Support/Log.h"
 
+#include "rsDefines.h"
+
 #include <llvm/IR/Constant.h>
 #include <llvm/IR/Constants.h>
 #include <llvm/IR/Type.h>
@@ -29,10 +32,10 @@
 
 namespace {
 
-static const bool kDebugGlobalInfo = false;
+const bool kDebugGlobalInfo = false;
 
 /* RSGlobalInfoPass: Embeds additional information about RenderScript global
- * variables into the Module. The 4 variables added are specified as follows:
+ * variables into the Module. The 5 variables added are specified as follows:
  * 1) .rs.global_entries
  *    i32 - int
  *    Optional number of global variables.
@@ -48,22 +51,58 @@
  *    [N * i32] or [N * i64] - size_t[N]
  *    Optional global variable size info. Each entry corresponds to the size
  *    of 1 of the N global variables.
+ * 5) .rs.global_properties
+ *    [N * i32]
+ *    Optional global properties. Each entry corresponds to the properties
+ *    for 1 of the N global variables. The 32-bit integer for properties
+ *    can be broken down as follows:
+ *    bit(s)    Encoded value
+ *    ------    -------------
+ *        18    Pointer (1 is pointer, 0 is non-pointer)
+ *        17    Static (1 is static, 0 is extern)
+ *        16    Constant (1 is const, 0 is non-const)
+ *    15 - 0    RsDataType (see frameworks/rs/rsDefines.h for more info)
  */
 class RSGlobalInfoPass: public llvm::ModulePass {
 private:
-
-public:
-  static char ID;
-
   // If true, we don't include information about immutable global variables
   // in our various exported data structures.
   bool mSkipConstants;
 
+  // Encodes properties of the GlobalVariable into a uint32_t.
+  // These values are used to populate the .rs.global_properties array.
+  static uint32_t getEncodedProperties(const llvm::GlobalVariable &GV) {
+    auto GlobalType = GV.getType()->getPointerElementType();
+
+    // We start by getting the RsDataType and placing it into our result.
+    uint32_t result = getRsDataTypeForType(GlobalType);
+    bccAssert(!(result & ~RS_GLOBAL_TYPE));  // Can only alter lower 16-bits.
+
+    if (GlobalType->isPointerTy()) {
+      // Global variables that are pointers can all be used with "bind".
+      result |= RS_GLOBAL_POINTER;
+    }
+
+    if (GV.isConstant()) {
+      result |= RS_GLOBAL_CONSTANT;
+    }
+
+    if (GV.getLinkage() == llvm::GlobalValue::InternalLinkage) {
+      // We only have internal linkage in RS to signify static.
+      result |= RS_GLOBAL_STATIC;
+    }
+
+    return result;
+  }
+
+public:
+  static char ID;
+
   RSGlobalInfoPass(bool pSkipConstants = false)
     : ModulePass (ID), mSkipConstants(pSkipConstants) {
   }
 
-  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+  void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
     // This pass does not use any other analysis passes, but it does
     // add new global variables.
   }
@@ -73,6 +112,7 @@
     std::vector<llvm::Constant *> GVNames;
     std::vector<uint32_t> GVSizes32;
     std::vector<uint64_t> GVSizes64;
+    std::vector<uint32_t> GVProperties;
 
     const llvm::DataLayout &DL = M.getDataLayout();
     const size_t PointerSizeInBits = DL.getPointerSizeInBits();
@@ -94,12 +134,15 @@
       // Since these are all global variables, their type is actually a
       // pointer to the underlying data. We can extract the total underlying
       // storage size by looking at the first contained type.
-      auto TypeSize = DL.getTypeAllocSize(GV.getType()->getContainedType(0));
+      auto GlobalType = GV.getType()->getPointerElementType();
+      auto TypeSize = DL.getTypeAllocSize(GlobalType);
       if (PointerSizeInBits == 32) {
         GVSizes32.push_back(TypeSize);
       } else {
         GVSizes64.push_back(TypeSize);
       }
+
+      GVProperties.push_back(getEncodedProperties(GV));
     }
 
     // Create the new strings for storing the names of the global variables.
@@ -122,9 +165,11 @@
     if (PointerSizeInBits == 32) {
       bccAssert(GVAddresses.size() == GVSizes32.size());
       bccAssert(GVSizes64.size() == 0);
+      bccAssert(GVAddresses.size() == GVProperties.size());
     } else {
       bccAssert(GVSizes32.size() == 0);
       bccAssert(GVAddresses.size() == GVSizes64.size());
+      bccAssert(GVAddresses.size() == GVProperties.size());
     }
     size_t NumGlobals = GVAddresses.size();
 
@@ -144,8 +189,11 @@
     // [NumGlobals * i32] or [NumGlobals * i64]
     llvm::ArrayType *SizeArrayTy = llvm::ArrayType::get(SizeTy, NumGlobals);
 
+    // [NumGlobals * i32]
+    llvm::ArrayType *Int32ArrayTy = llvm::ArrayType::get(Int32Ty, NumGlobals);
+
     // 1) @.rs.global_entries = constant i32 NumGlobals
-    llvm::Value *V = M.getOrInsertGlobal(".rs.global_entries", Int32Ty);
+    llvm::Value *V = M.getOrInsertGlobal(kRsGlobalEntries, Int32Ty);
     llvm::GlobalVariable *GlobalEntries =
         llvm::dyn_cast<llvm::GlobalVariable>(V);
     llvm::Constant *GlobalEntriesInit =
@@ -154,7 +202,7 @@
     GlobalEntries->setConstant(true);
 
     // 2) @.rs.global_names = constant [N * i8*] [...]
-    V = M.getOrInsertGlobal(".rs.global_names", VoidPtrArrayTy);
+    V = M.getOrInsertGlobal(kRsGlobalNames, VoidPtrArrayTy);
     llvm::GlobalVariable *GlobalNames =
         llvm::dyn_cast<llvm::GlobalVariable>(V);
     llvm::Constant *GlobalNamesInit =
@@ -163,7 +211,7 @@
     GlobalNames->setConstant(true);
 
     // 3) @.rs.global_addresses = constant [N * i8*] [...]
-    V = M.getOrInsertGlobal(".rs.global_addresses", VoidPtrArrayTy);
+    V = M.getOrInsertGlobal(kRsGlobalAddresses, VoidPtrArrayTy);
     llvm::GlobalVariable *GlobalAddresses =
         llvm::dyn_cast<llvm::GlobalVariable>(V);
     llvm::Constant *GlobalAddressesInit =
@@ -173,7 +221,7 @@
 
 
     // 4) @.rs.global_sizes = constant [N * i32 or i64] [...]
-    V = M.getOrInsertGlobal(".rs.global_sizes", SizeArrayTy);
+    V = M.getOrInsertGlobal(kRsGlobalSizes, SizeArrayTy);
     llvm::GlobalVariable *GlobalSizes =
         llvm::dyn_cast<llvm::GlobalVariable>(V);
     llvm::Constant *GlobalSizesInit;
@@ -185,11 +233,21 @@
     GlobalSizes->setInitializer(GlobalSizesInit);
     GlobalSizes->setConstant(true);
 
+    // 5) @.rs.global_properties = constant i32 NumGlobals
+    V = M.getOrInsertGlobal(kRsGlobalProperties, Int32ArrayTy);
+    llvm::GlobalVariable *GlobalProperties =
+        llvm::dyn_cast<llvm::GlobalVariable>(V);
+    llvm::Constant *GlobalPropertiesInit =
+        llvm::ConstantDataArray::get(M.getContext(), GVProperties);
+    GlobalProperties->setInitializer(GlobalPropertiesInit);
+    GlobalProperties->setConstant(true);
+
     if (kDebugGlobalInfo) {
       GlobalEntries->dump();
       GlobalNames->dump();
       GlobalAddresses->dump();
       GlobalSizes->dump();
+      GlobalProperties->dump();
     }
 
     // Upon completion, this pass has always modified the Module.
diff --git a/lib/Renderscript/RSInvokeHelperPass.cpp b/lib/Renderscript/RSInvokeHelperPass.cpp
index 94213f5..af72ff1 100644
--- a/lib/Renderscript/RSInvokeHelperPass.cpp
+++ b/lib/Renderscript/RSInvokeHelperPass.cpp
@@ -16,6 +16,8 @@
 
 #include "bcc/Assert.h"
 #include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Renderscript/RSUtils.h"
+#include "rsDefines.h"
 
 #include <cstdlib>
 
@@ -73,11 +75,11 @@
     llvm::SmallVector<llvm::Type*, 4> rsBaseObj;
     rsBaseObj.append(4, llvm::Type::getInt64PtrTy(M.getContext()));
 
-    rsAllocationType = llvm::StructType::create(rsBaseObj, "struct.rs_allocation");
-    rsElementType = llvm::StructType::create(rsBaseObj, "struct.rs_element");
-    rsSamplerType = llvm::StructType::create(rsBaseObj, "struct.rs_sampler");
-    rsScriptType = llvm::StructType::create(rsBaseObj, "struct.rs_script");
-    rsTypeType = llvm::StructType::create(rsBaseObj, "struct.rs_type");
+    rsAllocationType = llvm::StructType::create(rsBaseObj, kAllocationTypeName);
+    rsElementType = llvm::StructType::create(rsBaseObj, kElementTypeName);
+    rsSamplerType = llvm::StructType::create(rsBaseObj, kSamplerTypeName);
+    rsScriptType = llvm::StructType::create(rsBaseObj, kScriptTypeName);
+    rsTypeType = llvm::StructType::create(rsBaseObj, kTypeTypeName);
 
     llvm::SmallVector<llvm::Value*, 1> SetObjParams;
     llvm::SmallVector<llvm::Type*, 2> SetObjTypeParams;
@@ -117,25 +119,31 @@
     return true;
   }
 
-  bool insertSetObjectHelper(llvm::CallInst *Call, llvm::Value *V, llvm::StringRef StructName) {
+  bool insertSetObjectHelper(llvm::CallInst *Call, llvm::Value *V, enum RsDataType DT) {
     llvm::Constant *SetObj = nullptr;
     llvm::StructType *RSStructType = nullptr;
-    if (StructName.equals(rsAllocationType->getName())) {
+    switch (DT) {
+    case RS_TYPE_ALLOCATION:
       SetObj = rsAllocationSetObj;
       RSStructType = rsAllocationType;
-    } else if (StructName.equals(rsElementType->getName())) {
+      break;
+    case RS_TYPE_ELEMENT:
       SetObj = rsElementSetObj;
       RSStructType = rsElementType;
-    } else if (StructName.equals(rsSamplerType->getName())) {
+      break;
+    case RS_TYPE_SAMPLER:
       SetObj = rsSamplerSetObj;
       RSStructType = rsSamplerType;
-    } else if (StructName.equals(rsScriptType->getName())) {
+      break;
+    case RS_TYPE_SCRIPT:
       SetObj = rsScriptSetObj;
       RSStructType = rsScriptType;
-    } else if (StructName.equals(rsTypeType->getName())) {
+      break;
+    case RS_TYPE_TYPE:
       SetObj = rsTypeSetObj;
       RSStructType = rsTypeType;
-    } else {
+      break;
+    default:
       return false; // this is for graphics types and matrices; do nothing
     }
 
@@ -191,14 +199,14 @@
           if (llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(&Inst)) {
             for (unsigned int i = 0; i < call->getNumArgOperands(); i++) {
               llvm::Value *V = call->getArgOperand(i);
-              if (V->getType()->isPointerTy() && V->getType()->getPointerElementType()->isStructTy() &&
-                  V->getType()->getPointerElementType()->getStructName().startswith("struct.rs_")) {
-                // get just the object type name with no prefix or suffix
-                size_t LastDot = V->getType()->getPointerElementType()->getStructName().rfind('.');
-                llvm::StringRef StructName = V->getType()->getPointerElementType()->getStructName().slice(0, LastDot);
-
+              llvm::Type *T = V->getType();
+              enum RsDataType DT = RS_TYPE_NONE;
+              if (T->isPointerTy() && T->getPointerElementType()->isStructTy()) {
+                DT = getRsDataTypeForType(T->getPointerElementType());
+              }
+              if (DT != RS_TYPE_NONE) {
                 // generate the new call instruction and insert it
-                changed |= insertSetObjectHelper(call, V, StructName);
+                changed |= insertSetObjectHelper(call, V, DT);
               }
             }
           }