Merge "Provide additional information about global variables."
diff --git a/bcinfo/Android.mk b/bcinfo/Android.mk
index ac9a370..5a55014 100644
--- a/bcinfo/Android.mk
+++ b/bcinfo/Android.mk
@@ -31,6 +31,7 @@
 
 libbcinfo_C_INCLUDES := \
   $(LOCAL_PATH)/../include \
+  $(RS_ROOT_PATH) \
   $(LOCAL_PATH)/../../slang
 
 libbcinfo_STATIC_LIBRARIES := \
diff --git a/bcinfo/MetadataExtractor.cpp b/bcinfo/MetadataExtractor.cpp
index 0282276..468e940 100644
--- a/bcinfo/MetadataExtractor.cpp
+++ b/bcinfo/MetadataExtractor.cpp
@@ -17,6 +17,7 @@
 #include "bcinfo/MetadataExtractor.h"
 
 #include "bcinfo/BitcodeWrapper.h"
+#include "rsDefines.h"
 
 #define LOG_TAG "bcinfo"
 #include <cutils/log.h>
@@ -375,8 +376,9 @@
     // which means that we need to set the bottom 5 bits in the mask.
     mExportForEachSignatureCount = 1;
     char **TmpNameList = new char*[mExportForEachSignatureCount];
-    TmpNameList[0] = new char[5];
-    strncpy(TmpNameList[0], "root", 5);
+    size_t RootLen = strlen(kRoot) + 1;
+    TmpNameList[0] = new char[RootLen];
+    strncpy(TmpNameList[0], kRoot, RootLen);
 
     uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
     TmpSigList[0] = 0x1f;
diff --git a/include/bcc/Renderscript/RSUtils.h b/include/bcc/Renderscript/RSUtils.h
new file mode 100644
index 0000000..d8e3684
--- /dev/null
+++ b/include/bcc/Renderscript/RSUtils.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_RS_UTILS_H
+#define BCC_RS_UTILS_H
+
+#include "rsDefines.h"
+
+#include <llvm/IR/Type.h>
+
+namespace {
+
+const char kAllocationTypeName[] = "struct.rs_allocation";
+const char kElementTypeName[]    = "struct.rs_element";
+const char kSamplerTypeName[]    = "struct.rs_sampler";
+const char kScriptTypeName[]     = "struct.rs_script";
+const char kTypeTypeName[]       = "struct.rs_type";
+
+// Returns the RsDataType for a given input LLVM type.
+// This is only used to distinguish the associated RS object types (i.e.
+// rs_allocation, rs_element, rs_sampler, rs_script, and rs_type).
+// All other types are reported back as RS_TYPE_NONE, since no special
+// handling would be necessary.
+static inline enum RsDataType getRsDataTypeForType(const llvm::Type *T) {
+  if (T->isStructTy()) {
+    // Get just the object type name with no suffix.
+    size_t LastDot = T->getStructName().rfind('.');
+    if (LastDot == strlen("struct")) {
+      // If we get back to just the "struct" part, we know that we had a
+      // raw typename (i.e. struct.rs_element with no ".[0-9]+" suffix on it.
+      // In that case, we will want to create our slice such that it contains
+      // the entire name.
+      LastDot = T->getStructName().size();
+    }
+    const llvm::StringRef StructName = T->getStructName().slice(0, LastDot);
+    if (StructName.equals(kAllocationTypeName)) {
+      return RS_TYPE_ALLOCATION;
+    } else if (StructName.equals(kElementTypeName)) {
+      return RS_TYPE_ELEMENT;
+    } else if (StructName.equals(kSamplerTypeName)) {
+      return RS_TYPE_SAMPLER;
+    } else if (StructName.equals(kScriptTypeName)) {
+      return RS_TYPE_SCRIPT;
+    } else if (StructName.equals(kTypeTypeName)) {
+      return RS_TYPE_TYPE;
+    }
+  }
+  return RS_TYPE_NONE;
+}
+
+}  // end namespace
+
+#endif // BCC_RS_UTILS_H
diff --git a/lib/Core/Compiler.cpp b/lib/Core/Compiler.cpp
index 0c1ecd5..33a085b 100644
--- a/lib/Core/Compiler.cpp
+++ b/lib/Core/Compiler.cpp
@@ -40,6 +40,7 @@
 #include "bcc/Support/Log.h"
 #include "bcc/Support/OutputFile.h"
 #include "bcinfo/MetadataExtractor.h"
+#include "rsDefines.h"
 
 #include <string>
 
@@ -300,15 +301,16 @@
   std::vector<const char *> export_symbols;
 
   const char *sf[] = {
-    "root",      // Graphics drawing function or compute kernel.
-    "init",      // Initialization routine called implicitly on startup.
-    ".rs.dtor",  // Static global destructor for a script instance.
-    ".rs.info",  // Variable containing string of RS metadata info.
-    ".rs.global_entries",    // Optional number of global variables.
-    ".rs.global_names",      // Optional global variable name info.
-    ".rs.global_addresses",  // Optional global variable address info.
-    ".rs.global_sizes",      // Optional global variable size info.
-    nullptr         // Must be nullptr-terminated.
+    kRoot,               // Graphics drawing function or compute kernel.
+    kInit,               // Initialization routine called implicitly on startup.
+    kRsDtor,             // Static global destructor for a script instance.
+    kRsInfo,             // Variable containing string of RS metadata info.
+    kRsGlobalEntries,    // Optional number of global variables.
+    kRsGlobalNames,      // Optional global variable name info.
+    kRsGlobalAddresses,  // Optional global variable address info.
+    kRsGlobalSizes,      // Optional global variable size info.
+    kRsGlobalProperties, // Optional global variable properties.
+    nullptr              // Must be nullptr-terminated.
   };
   const char **special_functions = sf;
   // Special RS functions should always be global symbols.
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);
               }
             }
           }
diff --git a/libbcc-device-build.mk b/libbcc-device-build.mk
index 0945980..188f2f9 100644
--- a/libbcc-device-build.mk
+++ b/libbcc-device-build.mk
@@ -51,9 +51,8 @@
 include frameworks/compile/libbcc/libbcc-targets.mk
 
 LOCAL_C_INCLUDES := \
-  bionic \
-  external/libcxx/include \
   $(LIBBCC_ROOT_PATH)/include \
+  $(RS_ROOT_PATH) \
   $(LLVM_ROOT_PATH)/include \
   $(LLVM_ROOT_PATH)/device/include \
   $(LOCAL_C_INCLUDES)
diff --git a/libbcc-host-build.mk b/libbcc-host-build.mk
index 5ccd657..3a8839f 100644
--- a/libbcc-host-build.mk
+++ b/libbcc-host-build.mk
@@ -42,6 +42,7 @@
 
 LOCAL_C_INCLUDES := \
   $(LIBBCC_ROOT_PATH)/include \
+  $(RS_ROOT_PATH) \
   $(LLVM_ROOT_PATH)/include \
   $(LLVM_ROOT_PATH)/host/include \
   $(LOCAL_C_INCLUDES)
diff --git a/libbcc.mk b/libbcc.mk
index 41b0fe7..c3775b2 100644
--- a/libbcc.mk
+++ b/libbcc.mk
@@ -23,6 +23,7 @@
 #=====================================================================
 
 LLVM_ROOT_PATH          := external/llvm
+RS_ROOT_PATH            := frameworks/rs
 
 #=====================================================================
 # Related Makefile Paths of libbcc