Merge "Fix mad performance."
diff --git a/bcinfo/tools/Android.mk b/bcinfo/tools/Android.mk
index 0d99f71..f7cf34b 100644
--- a/bcinfo/tools/Android.mk
+++ b/bcinfo/tools/Android.mk
@@ -16,6 +16,8 @@
 
 LOCAL_PATH := $(call my-dir)
 
+LLVM_ROOT_PATH := external/llvm
+
 # Executable for host
 # ========================================================
 include $(CLEAR_VARS)
@@ -28,6 +30,12 @@
 LOCAL_SHARED_LIBRARIES := \
   libbcinfo
 
+LOCAL_STATIC_LIBRARIES := \
+  libLLVMBitReader \
+  libLLVMBitWriter \
+  libLLVMCore \
+  libLLVMSupport
+
 LOCAL_CFLAGS += -D__HOST__
 
 LOCAL_C_INCLUDES := \
@@ -37,5 +45,6 @@
 
 LOCAL_LDLIBS = -ldl
 
+include $(LLVM_ROOT_PATH)/llvm-host-build.mk
 include $(BUILD_HOST_EXECUTABLE)
 
diff --git a/bcinfo/tools/main.cpp b/bcinfo/tools/main.cpp
index 1360c68..2d1e449 100644
--- a/bcinfo/tools/main.cpp
+++ b/bcinfo/tools/main.cpp
@@ -18,6 +18,16 @@
 #include <bcinfo/BitcodeWrapper.h>
 #include <bcinfo/MetadataExtractor.h>
 
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Assembly/AssemblyAnnotationWriter.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/Module.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/ToolOutputFile.h>
+
 #include <ctype.h>
 #include <dlfcn.h>
 #include <stdarg.h>
@@ -33,12 +43,14 @@
 
 #include <unistd.h>
 
+#include <string>
 #include <vector>
 
 // This file corresponds to the standalone bcinfo tool. It prints a variety of
 // information about a supplied bitcode input file.
 
-const char* inFile = NULL;
+std::string inFile;
+std::string outFile;
 
 extern int opterr;
 extern int optind;
@@ -72,6 +84,13 @@
   }
 
   inFile = argv[optind];
+
+  int l = inFile.length();
+  if (l > 3 && inFile[l-3] == '.' && inFile[l-2] == 'b' && inFile[l-1] == 'c') {
+    outFile = std::string(inFile.begin(), inFile.end() - 3) + ".ll";
+  } else {
+    outFile = inFile + ".ll";
+  }
   return 1;
 }
 
@@ -141,26 +160,26 @@
 
 
 static size_t readBitcode(const char **bitcode) {
-  if (!inFile) {
+  if (!inFile.length()) {
     fprintf(stderr, "input file required\n");
-    return NULL;
+    return 0;
   }
 
   struct stat statInFile;
-  if (stat(inFile, &statInFile) < 0) {
+  if (stat(inFile.c_str(), &statInFile) < 0) {
     fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
-    return NULL;
+    return 0;
   }
 
   if (!S_ISREG(statInFile.st_mode)) {
     fprintf(stderr, "Input file should be a regular file.\n");
-    return NULL;
+    return 0;
   }
 
-  FILE *in = fopen(inFile, "r");
+  FILE *in = fopen(inFile.c_str(), "r");
   if (!in) {
-    fprintf(stderr, "Could not open input file %s\n", inFile);
-    return NULL;
+    fprintf(stderr, "Could not open input file %s\n", inFile.c_str());
+    return 0;
   }
 
   size_t bitcodeSize = statInFile.st_size;
@@ -169,7 +188,7 @@
   size_t nread = fread((void*) *bitcode, 1, bitcodeSize, in);
 
   if (nread != bitcodeSize)
-      fprintf(stderr, "Could not read all of file %s\n", inFile);
+      fprintf(stderr, "Could not read all of file %s\n", inFile.c_str());
 
   fclose(in);
   return nread;
@@ -192,7 +211,6 @@
   }
 
   const char *bitcode = NULL;
-  const char *translatedBitcode = NULL;
   size_t bitcodeSize = readBitcode(&bitcode);
 
   unsigned int version = 0;
@@ -209,25 +227,58 @@
   printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
   printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
 
-  bcinfo::BitcodeTranslator *BT =
-      new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version);
+  llvm::OwningPtr<bcinfo::BitcodeTranslator> BT;
+  BT.reset(new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version));
   if (!BT->translate()) {
     fprintf(stderr, "failed to translate bitcode\n");
     return 3;
   }
 
-  bcinfo::MetadataExtractor *ME =
-      new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(),
-                                    BT->getTranslatedBitcodeSize());
+  llvm::OwningPtr<bcinfo::MetadataExtractor> ME;
+  ME.reset(new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(),
+                                         BT->getTranslatedBitcodeSize()));
   if (!ME->extract()) {
     fprintf(stderr, "failed to get metadata\n");
     return 4;
   }
 
-  dumpMetadata(ME);
+  dumpMetadata(ME.get());
 
-  delete ME;
-  delete BT;
+  const char *translatedBitcode = BT->getTranslatedBitcode();
+  size_t translatedBitcodeSize = BT->getTranslatedBitcodeSize();
+
+  llvm::LLVMContext &ctx = llvm::getGlobalContext();
+  llvm::llvm_shutdown_obj called_on_exit;
+
+  llvm::OwningPtr<llvm::MemoryBuffer> mem;
+
+  mem.reset(llvm::MemoryBuffer::getMemBuffer(
+      llvm::StringRef(translatedBitcode, translatedBitcodeSize),
+      inFile.c_str(), false));
+
+  llvm::OwningPtr<llvm::Module> module;
+  std::string errmsg;
+  module.reset(llvm::ParseBitcodeFile(mem.get(), ctx, &errmsg));
+  if (module.get() != 0 && module->MaterializeAllPermanently(&errmsg)) {
+    module.reset();
+  }
+
+  if (module.get() == 0) {
+    if (errmsg.size()) {
+      fprintf(stderr, "error: %s\n", errmsg.c_str());
+    } else {
+      fprintf(stderr, "error: failed to parse bitcode file\n");
+    }
+    return 5;
+  }
+
+  llvm::OwningPtr<llvm::tool_output_file> tof(
+      new llvm::tool_output_file(outFile.c_str(), errmsg,
+                                 llvm::raw_fd_ostream::F_Binary));
+  llvm::OwningPtr<llvm::AssemblyAnnotationWriter> ann;
+  module->print(tof->os(), ann.get());
+
+  tof->keep();
 
   releaseBitcode(&bitcode);