Merge "Change libbcc so that it compiles as an LLVM loadable module (try 2)."
diff --git a/bcinfo/MetadataExtractor.cpp b/bcinfo/MetadataExtractor.cpp
index 468e940..23d97fe 100644
--- a/bcinfo/MetadataExtractor.cpp
+++ b/bcinfo/MetadataExtractor.cpp
@@ -56,8 +56,75 @@
   return false;
 }
 
+const char *createStringFromValue(llvm::Metadata *m) {
+  auto ref = getStringOperand(m);
+  char *c = new char[ref.size() + 1];
+  memcpy(c, ref.data(), ref.size());
+  c[ref.size()] = '\0';
+  return c;
 }
 
+// Collect metadata from NamedMDNodes that contain a list of names
+// (strings).
+//
+// Inputs:
+//
+// NamedMetadata - An LLVM metadata node, each of whose operands have
+// a string as their first entry
+//
+// NameList - A reference that will hold an allocated array of strings
+//
+// Count - A reference that will hold the length of the allocated
+// array of strings
+//
+// Return value:
+//
+// Return true on success, false on error.
+//
+// Upon success, the function sets NameList to an array of strings
+// corresponding the names found in the metadata. The function sets
+// Count to the number of entries in NameList.
+//
+// An error occurs if one of the metadata operands doesn't have a
+// first entry.
+bool populateNameMetadata(const llvm::NamedMDNode *NameMetadata,
+                          const char **&NameList, size_t &Count) {
+  if (!NameMetadata) {
+    NameList = nullptr;
+    Count = 0;
+    return true;
+  }
+
+  Count = NameMetadata->getNumOperands();
+  if (!Count) {
+    NameList = nullptr;
+    return true;
+  }
+
+  NameList = new const char *[Count];
+
+  for (size_t i = 0; i < Count; i++) {
+    llvm::MDNode *Name = NameMetadata->getOperand(i);
+    if (Name && Name->getNumOperands() > 0) {
+      NameList[i] = createStringFromValue(Name->getOperand(0));
+    } else {
+      ALOGE("Metadata operand does not contain a name string");
+      for (size_t AllocatedIndex = 0; AllocatedIndex < i; AllocatedIndex++) {
+        delete [] NameList[AllocatedIndex];
+      }
+      delete [] NameList;
+      NameList = nullptr;
+      Count = 0;
+
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // end anonymous namespace
+
 // Name of metadata node where pragma info resides (should be synced with
 // slang.cpp)
 static const llvm::StringRef PragmaMetadataName = "#pragma";
@@ -79,6 +146,10 @@
 // (should be synced with slang_rs_metadata.h)
 static const llvm::StringRef ExportForEachMetadataName = "#rs_export_foreach";
 
+// Name of metadata node where exported reduce name information resides
+// (should be synced with slang_rs_metadata.h)
+static const llvm::StringRef ExportReduceMetadataName = "#rs_export_reduce";
+
 // Name of metadata node where RS object slot info resides (should be
 // synced with slang_rs_metadata.h)
 static const llvm::StringRef ObjectSlotMetadataName = "#rs_object_slots";
@@ -92,28 +163,31 @@
 MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize)
     : mModule(nullptr), mBitcode(bitcode), mBitcodeSize(bitcodeSize),
       mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0),
-      mExportVarNameList(nullptr), mExportFuncNameList(nullptr),
-      mExportForEachNameList(nullptr), mExportForEachSignatureList(nullptr),
-      mExportForEachInputCountList(nullptr), mPragmaCount(0),
-      mPragmaKeyList(nullptr), mPragmaValueList(nullptr), mObjectSlotCount(0),
-      mObjectSlotList(nullptr), mRSFloatPrecision(RS_FP_Full),
-      mIsThreadable(true), mBuildChecksum(nullptr) {
+      mExportReduceCount(0), mExportVarNameList(nullptr),
+      mExportFuncNameList(nullptr), mExportForEachNameList(nullptr),
+      mExportForEachSignatureList(nullptr),
+      mExportForEachInputCountList(nullptr), mExportReduceNameList(nullptr),
+      mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr),
+      mObjectSlotCount(0), mObjectSlotList(nullptr),
+      mRSFloatPrecision(RS_FP_Full), mIsThreadable(true),
+      mBuildChecksum(nullptr) {
   BitcodeWrapper wrapper(bitcode, bitcodeSize);
   mTargetAPI = wrapper.getTargetAPI();
   mCompilerVersion = wrapper.getCompilerVersion();
   mOptimizationLevel = wrapper.getOptimizationLevel();
 }
 
-
 MetadataExtractor::MetadataExtractor(const llvm::Module *module)
-    : mModule(module), mBitcode(nullptr), mBitcodeSize(0), mExportVarCount(0),
-      mExportFuncCount(0), mExportForEachSignatureCount(0),
-      mExportVarNameList(nullptr), mExportFuncNameList(nullptr),
-      mExportForEachNameList(nullptr), mExportForEachSignatureList(nullptr),
-      mExportForEachInputCountList(nullptr), mPragmaCount(0),
-      mPragmaKeyList(nullptr), mPragmaValueList(nullptr), mObjectSlotCount(0),
-      mObjectSlotList(nullptr), mRSFloatPrecision(RS_FP_Full),
-      mIsThreadable(true), mBuildChecksum(nullptr) {
+    : mModule(module), mBitcode(nullptr), mBitcodeSize(0),
+      mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0),
+      mExportReduceCount(0), mExportVarNameList(nullptr),
+      mExportFuncNameList(nullptr), mExportForEachNameList(nullptr),
+      mExportForEachSignatureList(nullptr),
+      mExportForEachInputCountList(nullptr), mExportReduceNameList(nullptr),
+      mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr),
+      mObjectSlotCount(0), mObjectSlotList(nullptr),
+      mRSFloatPrecision(RS_FP_Full), mIsThreadable(true),
+      mBuildChecksum(nullptr) {
   mCompilerVersion = RS_VERSION;  // Default to the actual current version.
   mOptimizationLevel = 3;
 }
@@ -150,6 +224,15 @@
   delete [] mExportForEachSignatureList;
   mExportForEachSignatureList = nullptr;
 
+  if (mExportReduceNameList) {
+    for (size_t i = 0; i < mExportReduceCount; i++) {
+      delete [] mExportReduceNameList[i];
+      mExportReduceNameList[i] = nullptr;
+    }
+  }
+  delete [] mExportReduceNameList;
+  mExportReduceNameList = nullptr;
+
   for (size_t i = 0; i < mPragmaCount; i++) {
     if (mPragmaKeyList) {
       delete [] mPragmaKeyList[i];
@@ -208,15 +291,6 @@
 }
 
 
-static const char *createStringFromValue(llvm::Metadata *m) {
-  auto ref = getStringOperand(m);
-  char *c = new char[ref.size() + 1];
-  memcpy(c, ref.data(), ref.size());
-  c[ref.size()] = '\0';
-  return c;
-}
-
-
 void MetadataExtractor::populatePragmaMetadata(
     const llvm::NamedMDNode *PragmaMetadata) {
   if (!PragmaMetadata) {
@@ -292,59 +366,6 @@
 #endif
 }
 
-
-bool MetadataExtractor::populateVarNameMetadata(
-    const llvm::NamedMDNode *VarNameMetadata) {
-  if (!VarNameMetadata) {
-    return true;
-  }
-
-  mExportVarCount = VarNameMetadata->getNumOperands();
-  if (!mExportVarCount) {
-    return true;
-  }
-
-  const char **TmpNameList = new const char *[mExportVarCount];
-
-  for (size_t i = 0; i < mExportVarCount; i++) {
-    llvm::MDNode *Name = VarNameMetadata->getOperand(i);
-    if (Name != nullptr && Name->getNumOperands() > 1) {
-      TmpNameList[i] = createStringFromValue(Name->getOperand(0));
-    }
-  }
-
-  mExportVarNameList = TmpNameList;
-
-  return true;
-}
-
-
-bool MetadataExtractor::populateFuncNameMetadata(
-    const llvm::NamedMDNode *FuncNameMetadata) {
-  if (!FuncNameMetadata) {
-    return true;
-  }
-
-  mExportFuncCount = FuncNameMetadata->getNumOperands();
-  if (!mExportFuncCount) {
-    return true;
-  }
-
-  const char **TmpNameList = new const char*[mExportFuncCount];
-
-  for (size_t i = 0; i < mExportFuncCount; i++) {
-    llvm::MDNode *Name = FuncNameMetadata->getOperand(i);
-    if (Name != nullptr && Name->getNumOperands() == 1) {
-      TmpNameList[i] = createStringFromValue(Name->getOperand(0));
-    }
-  }
-
-  mExportFuncNameList = TmpNameList;
-
-  return true;
-}
-
-
 uint32_t MetadataExtractor::calculateNumInputs(const llvm::Function *Function,
                                                uint32_t Signature) {
 
@@ -521,6 +542,8 @@
       mModule->getNamedMetadata(ExportForEachNameMetadataName);
   const llvm::NamedMDNode *ExportForEachMetadata =
       mModule->getNamedMetadata(ExportForEachMetadataName);
+  const llvm::NamedMDNode *ExportReduceMetadata =
+      mModule->getNamedMetadata(ExportReduceMetadataName);
   const llvm::NamedMDNode *PragmaMetadata =
       mModule->getNamedMetadata(PragmaMetadataName);
   const llvm::NamedMDNode *ObjectSlotMetadata =
@@ -530,17 +553,24 @@
   const llvm::NamedMDNode *ChecksumMetadata =
       mModule->getNamedMetadata(ChecksumMetadataName);
 
-
-  if (!populateVarNameMetadata(ExportVarMetadata)) {
+  if (!populateNameMetadata(ExportVarMetadata, mExportVarNameList,
+                            mExportVarCount)) {
     ALOGE("Could not populate export variable metadata");
     return false;
   }
 
-  if (!populateFuncNameMetadata(ExportFuncMetadata)) {
+  if (!populateNameMetadata(ExportFuncMetadata, mExportFuncNameList,
+                            mExportFuncCount)) {
     ALOGE("Could not populate export function metadata");
     return false;
   }
 
+  if (!populateNameMetadata(ExportReduceMetadata, mExportReduceNameList,
+                            mExportReduceCount)) {
+    ALOGE("Could not populate export reduce metadata");
+    return false;
+  }
+
   if (!populateForEachMetadata(ExportForEachNameMetadata,
                                ExportForEachMetadata)) {
     ALOGE("Could not populate ForEach signature metadata");
diff --git a/bcinfo/tools/main.cpp b/bcinfo/tools/main.cpp
index 0921151..c4e40f4 100644
--- a/bcinfo/tools/main.cpp
+++ b/bcinfo/tools/main.cpp
@@ -143,6 +143,12 @@
             inputCountList[i]);
   }
 
+  fprintf(info, "exportReduceCount: %zu\n", ME->getExportReduceCount());
+  const char **reduceNameList = ME->getExportReduceNameList();
+  for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
+    fprintf(info, "%s\n", reduceNameList[i]);
+  }
+
   fprintf(info, "objectSlotCount: %zu\n", ME->getObjectSlotCount());
   const uint32_t *slotList = ME->getObjectSlotList();
   for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
@@ -197,6 +203,13 @@
   }
   printf("\n");
 
+  printf("exportReduceCount: %zu\n", ME->getExportReduceCount());
+  const char **reduceNameList = ME->getExportReduceNameList();
+  for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
+    printf("func[%zu]: %s\n", i, reduceNameList[i]);
+  }
+  printf("\n");
+
   printf("pragmaCount: %zu\n", ME->getPragmaCount());
   const char **keyList = ME->getPragmaKeyList();
   const char **valueList = ME->getPragmaValueList();
diff --git a/include/bcinfo/MetadataExtractor.h b/include/bcinfo/MetadataExtractor.h
index 99818ca..742346a 100644
--- a/include/bcinfo/MetadataExtractor.h
+++ b/include/bcinfo/MetadataExtractor.h
@@ -54,12 +54,13 @@
   size_t mExportVarCount;
   size_t mExportFuncCount;
   size_t mExportForEachSignatureCount;
+  size_t mExportReduceCount;
   const char **mExportVarNameList;
   const char **mExportFuncNameList;
   const char **mExportForEachNameList;
   const uint32_t *mExportForEachSignatureList;
-
   const uint32_t *mExportForEachInputCountList;
+  const char **mExportReduceNameList;
 
   size_t mPragmaCount;
   const char **mPragmaKeyList;
@@ -80,8 +81,6 @@
   const char *mBuildChecksum;
 
   // Helper functions for extraction
-  bool populateVarNameMetadata(const llvm::NamedMDNode *VarNameMetadata);
-  bool populateFuncNameMetadata(const llvm::NamedMDNode *FuncNameMetadata);
   bool populateForEachMetadata(const llvm::NamedMDNode *Names,
                                const llvm::NamedMDNode *Signatures);
   bool populateObjectSlotMetadata(const llvm::NamedMDNode *ObjectSlotMetadata);
@@ -184,6 +183,20 @@
   }
 
   /**
+   * \return number of exported reduce kernels (slots) in this script/module.
+   */
+  size_t getExportReduceCount() const {
+    return mExportReduceCount;
+  }
+
+  /**
+   * \return array of exported reduce kernel names.
+   */
+  const char **getExportReduceNameList() const {
+    return mExportReduceNameList;
+  }
+
+  /**
    * \return number of pragmas contained in pragmaKeyList and pragmaValueList.
    */
   size_t getPragmaCount() const {
diff --git a/tests/libbcc/lit.cfg b/tests/libbcc/lit.cfg
new file mode 100644
index 0000000..5b3c749
--- /dev/null
+++ b/tests/libbcc/lit.cfg
@@ -0,0 +1,46 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import re
+
+# name: The name of this test suite.
+config.name = 'libbcc'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.ll']
+
+# testFormat: The test format to use to interpret tests.
+import lit.formats
+config.test_format = lit.formats.ShTest()
+
+ANDROID_HOST_OUT = os.getenv("ANDROID_HOST_OUT")
+ANDROID_PRODUCT_OUT = os.getenv("ANDROID_PRODUCT_OUT")
+
+if not ANDROID_HOST_OUT or not ANDROID_PRODUCT_OUT:
+    import sys
+    sys.exit(1)
+
+# test_source_root: The path where tests are located (default is the test suite
+# root).
+config.test_source_root = None
+config.test_exec_root = os.path.join(ANDROID_HOST_OUT, 'tests', 'bcinfo')
+
+tools_dir = os.path.join(ANDROID_HOST_OUT, 'bin')
+
+# Based on LLVM's lit.cfg: "For each occurrence of an llvm tool name
+# as its own word, replace it with the full path to the build directory
+# holding that tool."
+for pattern in [r"\bFileCheck\b",
+                r"\bllvm-rs-as\b",
+                r"\bbcinfo\b"]:
+    tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_]+)\\b\W*$",
+                          pattern)
+    tool_pipe = tool_match.group(2)
+    tool_name = tool_match.group(4)
+    import lit.util
+    tool_path = lit.util.which(tool_name, tools_dir)
+    if not tool_path:
+        lit_config.note("Did not find " + tool_name + " in " + tools_dir)
+        tool_path = os.path.join(tools_dir, tool_name)
+    config.substitutions.append((pattern, tool_pipe + tool_path))
diff --git a/tests/libbcc/test_reduce_metadata.ll b/tests/libbcc/test_reduce_metadata.ll
new file mode 100644
index 0000000..aea8f36
--- /dev/null
+++ b/tests/libbcc/test_reduce_metadata.ll
@@ -0,0 +1,28 @@
+; Check that the #rs_export_reduce node is recognized.
+
+; RUN: llvm-rs-as %s -o %t
+; RUN: bcinfo %t | FileCheck %s
+
+; CHECK: exportReduceCount: 1
+; CHECK: func[0]: add
+
+; ModuleID = 'reduce.bc'
+target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-none-linux-gnueabi"
+
+; Function Attrs: nounwind readnone
+define i32 @add(i32 %a, i32 %b) #0 {
+  %1 = add nsw i32 %b, %a
+  ret i32 %1
+}
+
+attributes #0 = { nounwind readnone }
+
+!llvm.ident = !{!0}
+!\23pragma = !{!1, !2}
+!\23rs_export_reduce = !{!3}
+
+!0 = !{!"clang version 3.6 "}
+!1 = !{!"version", !"1"}
+!2 = !{!"java_package_name", !"com.android.rs.test"}
+!3 = !{!"add"}
diff --git a/tests/run-lit-tests.sh b/tests/run-lit-tests.sh
new file mode 100755
index 0000000..8976555
--- /dev/null
+++ b/tests/run-lit-tests.sh
@@ -0,0 +1,6 @@
+#!/bin/bash -e
+
+LIT_PATH=$ANDROID_BUILD_TOP/frameworks/compile/libbcc/tests/debuginfo/llvm-lit
+LIBBCC_TESTS=$ANDROID_BUILD_TOP/frameworks/compile/libbcc/tests/libbcc
+
+$LIT_PATH $LIBBCC_TESTS $@