[llvm] r365286 - [llvm-bcanalyzer] Refactor and move to libLLVMBitReader

Francis Visoiu Mistrih via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 7 19:06:35 PDT 2019


Author: thegameg
Date: Sun Jul  7 19:06:34 2019
New Revision: 365286

URL: http://llvm.org/viewvc/llvm-project?rev=365286&view=rev
Log:
[llvm-bcanalyzer] Refactor and move to libLLVMBitReader

This allows us to use the analyzer from unit tests.

* Refactor the interface to use proper error handling for most functions
  after JF's work.
* Move everything into a BitstreamAnalyzer class.
* Move that to Bitcode/BitcodeAnalyzer.h.

Differential Revision: https://reviews.llvm.org/D64116

Added:
    llvm/trunk/include/llvm/Bitcode/BitcodeAnalyzer.h
    llvm/trunk/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
Modified:
    llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt
    llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp

Added: llvm/trunk/include/llvm/Bitcode/BitcodeAnalyzer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/BitcodeAnalyzer.h?rev=365286&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/BitcodeAnalyzer.h (added)
+++ llvm/trunk/include/llvm/Bitcode/BitcodeAnalyzer.h Sun Jul  7 19:06:34 2019
@@ -0,0 +1,103 @@
+//===- llvm/Bitcode/BitcodeAnalyzer.h - Bitcode analyzer --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines interfaces to analyze LLVM bitcode files/streams.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BITCODE_BITCODE_ANALYZER_H
+#define LLVM_BITCODE_BITCODE_ANALYZER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Bitstream/BitstreamReader.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+/// CurStreamTypeType - A type for CurStreamType
+enum CurStreamTypeType {
+  UnknownBitstream,
+  LLVMIRBitstream,
+  ClangSerializedASTBitstream,
+  ClangSerializedDiagnosticsBitstream,
+};
+
+struct BCDumpOptions {
+  /// The stream.
+  raw_ostream &OS;
+  /// Print per-code histogram.
+  bool Histogram = false;
+  /// Don't emit numeric info in dump if symbolic info is available.
+  bool Symbolic = false;
+  /// Print binary blobs using hex escapes.
+  bool ShowBinaryBlobs = false;
+
+  BCDumpOptions(raw_ostream &OS) : OS(OS) {}
+};
+
+class BitcodeAnalyzer {
+  BitstreamCursor Stream;
+  BitstreamBlockInfo BlockInfo;
+  CurStreamTypeType CurStreamType;
+  Optional<BitstreamCursor> BlockInfoStream;
+  unsigned NumTopBlocks = 0;
+
+  struct PerRecordStats {
+    unsigned NumInstances;
+    unsigned NumAbbrev;
+    uint64_t TotalBits;
+    PerRecordStats() : NumInstances(0), NumAbbrev(0), TotalBits(0) {}
+  };
+
+  struct PerBlockIDStats {
+    /// NumInstances - This the number of times this block ID has been seen.
+    unsigned NumInstances;
+    /// NumBits - The total size in bits of all of these blocks.
+    uint64_t NumBits;
+    /// NumSubBlocks - The total number of blocks these blocks contain.
+    unsigned NumSubBlocks;
+    /// NumAbbrevs - The total number of abbreviations.
+    unsigned NumAbbrevs;
+    /// NumRecords - The total number of records these blocks contain, and the
+    /// number that are abbreviated.
+    unsigned NumRecords, NumAbbreviatedRecords;
+    /// CodeFreq - Keep track of the number of times we see each code.
+    std::vector<PerRecordStats> CodeFreq;
+    PerBlockIDStats()
+        : NumInstances(0), NumBits(0), NumSubBlocks(0), NumAbbrevs(0),
+          NumRecords(0), NumAbbreviatedRecords(0) {}
+  };
+
+  std::map<unsigned, PerBlockIDStats> BlockIDStats;
+
+public:
+  BitcodeAnalyzer(StringRef Buffer, Optional<StringRef> BlockInfoBuffer = None);
+  /// Analyze the bitcode file.
+  Error analyze(Optional<BCDumpOptions> O = None,
+                Optional<StringRef> CheckHash = None);
+  /// Print stats about the bitcode file.
+  void printStats(BCDumpOptions O, Optional<StringRef> Filename = None);
+
+private:
+  /// Read a block, updating statistics, etc.
+  Error parseBlock(unsigned BlockID, unsigned IndentLevel,
+                   Optional<BCDumpOptions> O = None,
+                   Optional<StringRef> CheckHash = None);
+
+  Error decodeMetadataStringsBlob(StringRef Indent, ArrayRef<uint64_t> Record,
+                                  StringRef Blob, raw_ostream &OS);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_BITCODE_BITCODE_ANALYZER_H

Added: llvm/trunk/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeAnalyzer.cpp?rev=365286&view=auto
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeAnalyzer.cpp (added)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeAnalyzer.cpp Sun Jul  7 19:06:34 2019
@@ -0,0 +1,977 @@
+//===- BitcodeAnalyzer.cpp - Internal BitcodeAnalyzer implementation ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/BitcodeAnalyzer.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/SHA1.h"
+
+using namespace llvm;
+
+static Error reportError(StringRef Message) {
+  return createStringError(std::errc::illegal_byte_sequence, Message.data());
+}
+
+/// Return a symbolic block name if known, otherwise return null.
+static Optional<const char *> GetBlockName(unsigned BlockID,
+                                           const BitstreamBlockInfo &BlockInfo,
+                                           CurStreamTypeType CurStreamType) {
+  // Standard blocks for all bitcode files.
+  if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
+    if (BlockID == bitc::BLOCKINFO_BLOCK_ID)
+      return "BLOCKINFO_BLOCK";
+    return None;
+  }
+
+  // Check to see if we have a blockinfo record for this block, with a name.
+  if (const BitstreamBlockInfo::BlockInfo *Info =
+          BlockInfo.getBlockInfo(BlockID)) {
+    if (!Info->Name.empty())
+      return Info->Name.c_str();
+  }
+
+  if (CurStreamType != LLVMIRBitstream)
+    return None;
+
+  switch (BlockID) {
+  default:
+    return None;
+  case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID:
+    return "OPERAND_BUNDLE_TAGS_BLOCK";
+  case bitc::MODULE_BLOCK_ID:
+    return "MODULE_BLOCK";
+  case bitc::PARAMATTR_BLOCK_ID:
+    return "PARAMATTR_BLOCK";
+  case bitc::PARAMATTR_GROUP_BLOCK_ID:
+    return "PARAMATTR_GROUP_BLOCK_ID";
+  case bitc::TYPE_BLOCK_ID_NEW:
+    return "TYPE_BLOCK_ID";
+  case bitc::CONSTANTS_BLOCK_ID:
+    return "CONSTANTS_BLOCK";
+  case bitc::FUNCTION_BLOCK_ID:
+    return "FUNCTION_BLOCK";
+  case bitc::IDENTIFICATION_BLOCK_ID:
+    return "IDENTIFICATION_BLOCK_ID";
+  case bitc::VALUE_SYMTAB_BLOCK_ID:
+    return "VALUE_SYMTAB";
+  case bitc::METADATA_BLOCK_ID:
+    return "METADATA_BLOCK";
+  case bitc::METADATA_KIND_BLOCK_ID:
+    return "METADATA_KIND_BLOCK";
+  case bitc::METADATA_ATTACHMENT_ID:
+    return "METADATA_ATTACHMENT_BLOCK";
+  case bitc::USELIST_BLOCK_ID:
+    return "USELIST_BLOCK_ID";
+  case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
+    return "GLOBALVAL_SUMMARY_BLOCK";
+  case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
+    return "FULL_LTO_GLOBALVAL_SUMMARY_BLOCK";
+  case bitc::MODULE_STRTAB_BLOCK_ID:
+    return "MODULE_STRTAB_BLOCK";
+  case bitc::STRTAB_BLOCK_ID:
+    return "STRTAB_BLOCK";
+  case bitc::SYMTAB_BLOCK_ID:
+    return "SYMTAB_BLOCK";
+  }
+}
+
+/// Return a symbolic code name if known, otherwise return null.
+static Optional<const char *> GetCodeName(unsigned CodeID, unsigned BlockID,
+                                          const BitstreamBlockInfo &BlockInfo,
+                                          CurStreamTypeType CurStreamType) {
+  // Standard blocks for all bitcode files.
+  if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
+    if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
+      switch (CodeID) {
+      default:
+        return None;
+      case bitc::BLOCKINFO_CODE_SETBID:
+        return "SETBID";
+      case bitc::BLOCKINFO_CODE_BLOCKNAME:
+        return "BLOCKNAME";
+      case bitc::BLOCKINFO_CODE_SETRECORDNAME:
+        return "SETRECORDNAME";
+      }
+    }
+    return None;
+  }
+
+  // Check to see if we have a blockinfo record for this record, with a name.
+  if (const BitstreamBlockInfo::BlockInfo *Info =
+          BlockInfo.getBlockInfo(BlockID)) {
+    for (unsigned i = 0, e = Info->RecordNames.size(); i != e; ++i)
+      if (Info->RecordNames[i].first == CodeID)
+        return Info->RecordNames[i].second.c_str();
+  }
+
+  if (CurStreamType != LLVMIRBitstream)
+    return None;
+
+#define STRINGIFY_CODE(PREFIX, CODE)                                           \
+  case bitc::PREFIX##_##CODE:                                                  \
+    return #CODE;
+  switch (BlockID) {
+  default:
+    return None;
+  case bitc::MODULE_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(MODULE_CODE, VERSION)
+      STRINGIFY_CODE(MODULE_CODE, TRIPLE)
+      STRINGIFY_CODE(MODULE_CODE, DATALAYOUT)
+      STRINGIFY_CODE(MODULE_CODE, ASM)
+      STRINGIFY_CODE(MODULE_CODE, SECTIONNAME)
+      STRINGIFY_CODE(MODULE_CODE, DEPLIB) // FIXME: Remove in 4.0
+      STRINGIFY_CODE(MODULE_CODE, GLOBALVAR)
+      STRINGIFY_CODE(MODULE_CODE, FUNCTION)
+      STRINGIFY_CODE(MODULE_CODE, ALIAS)
+      STRINGIFY_CODE(MODULE_CODE, GCNAME)
+      STRINGIFY_CODE(MODULE_CODE, VSTOFFSET)
+      STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES_UNUSED)
+      STRINGIFY_CODE(MODULE_CODE, SOURCE_FILENAME)
+      STRINGIFY_CODE(MODULE_CODE, HASH)
+    }
+  case bitc::IDENTIFICATION_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(IDENTIFICATION_CODE, STRING)
+      STRINGIFY_CODE(IDENTIFICATION_CODE, EPOCH)
+    }
+  case bitc::PARAMATTR_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+    // FIXME: Should these be different?
+    case bitc::PARAMATTR_CODE_ENTRY_OLD:
+      return "ENTRY";
+    case bitc::PARAMATTR_CODE_ENTRY:
+      return "ENTRY";
+    }
+  case bitc::PARAMATTR_GROUP_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+    case bitc::PARAMATTR_GRP_CODE_ENTRY:
+      return "ENTRY";
+    }
+  case bitc::TYPE_BLOCK_ID_NEW:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(TYPE_CODE, NUMENTRY)
+      STRINGIFY_CODE(TYPE_CODE, VOID)
+      STRINGIFY_CODE(TYPE_CODE, FLOAT)
+      STRINGIFY_CODE(TYPE_CODE, DOUBLE)
+      STRINGIFY_CODE(TYPE_CODE, LABEL)
+      STRINGIFY_CODE(TYPE_CODE, OPAQUE)
+      STRINGIFY_CODE(TYPE_CODE, INTEGER)
+      STRINGIFY_CODE(TYPE_CODE, POINTER)
+      STRINGIFY_CODE(TYPE_CODE, ARRAY)
+      STRINGIFY_CODE(TYPE_CODE, VECTOR)
+      STRINGIFY_CODE(TYPE_CODE, X86_FP80)
+      STRINGIFY_CODE(TYPE_CODE, FP128)
+      STRINGIFY_CODE(TYPE_CODE, PPC_FP128)
+      STRINGIFY_CODE(TYPE_CODE, METADATA)
+      STRINGIFY_CODE(TYPE_CODE, STRUCT_ANON)
+      STRINGIFY_CODE(TYPE_CODE, STRUCT_NAME)
+      STRINGIFY_CODE(TYPE_CODE, STRUCT_NAMED)
+      STRINGIFY_CODE(TYPE_CODE, FUNCTION)
+    }
+
+  case bitc::CONSTANTS_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(CST_CODE, SETTYPE)
+      STRINGIFY_CODE(CST_CODE, NULL)
+      STRINGIFY_CODE(CST_CODE, UNDEF)
+      STRINGIFY_CODE(CST_CODE, INTEGER)
+      STRINGIFY_CODE(CST_CODE, WIDE_INTEGER)
+      STRINGIFY_CODE(CST_CODE, FLOAT)
+      STRINGIFY_CODE(CST_CODE, AGGREGATE)
+      STRINGIFY_CODE(CST_CODE, STRING)
+      STRINGIFY_CODE(CST_CODE, CSTRING)
+      STRINGIFY_CODE(CST_CODE, CE_BINOP)
+      STRINGIFY_CODE(CST_CODE, CE_CAST)
+      STRINGIFY_CODE(CST_CODE, CE_GEP)
+      STRINGIFY_CODE(CST_CODE, CE_INBOUNDS_GEP)
+      STRINGIFY_CODE(CST_CODE, CE_SELECT)
+      STRINGIFY_CODE(CST_CODE, CE_EXTRACTELT)
+      STRINGIFY_CODE(CST_CODE, CE_INSERTELT)
+      STRINGIFY_CODE(CST_CODE, CE_SHUFFLEVEC)
+      STRINGIFY_CODE(CST_CODE, CE_CMP)
+      STRINGIFY_CODE(CST_CODE, INLINEASM)
+      STRINGIFY_CODE(CST_CODE, CE_SHUFVEC_EX)
+      STRINGIFY_CODE(CST_CODE, CE_UNOP)
+    case bitc::CST_CODE_BLOCKADDRESS:
+      return "CST_CODE_BLOCKADDRESS";
+      STRINGIFY_CODE(CST_CODE, DATA)
+    }
+  case bitc::FUNCTION_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(FUNC_CODE, DECLAREBLOCKS)
+      STRINGIFY_CODE(FUNC_CODE, INST_BINOP)
+      STRINGIFY_CODE(FUNC_CODE, INST_CAST)
+      STRINGIFY_CODE(FUNC_CODE, INST_GEP_OLD)
+      STRINGIFY_CODE(FUNC_CODE, INST_INBOUNDS_GEP_OLD)
+      STRINGIFY_CODE(FUNC_CODE, INST_SELECT)
+      STRINGIFY_CODE(FUNC_CODE, INST_EXTRACTELT)
+      STRINGIFY_CODE(FUNC_CODE, INST_INSERTELT)
+      STRINGIFY_CODE(FUNC_CODE, INST_SHUFFLEVEC)
+      STRINGIFY_CODE(FUNC_CODE, INST_CMP)
+      STRINGIFY_CODE(FUNC_CODE, INST_RET)
+      STRINGIFY_CODE(FUNC_CODE, INST_BR)
+      STRINGIFY_CODE(FUNC_CODE, INST_SWITCH)
+      STRINGIFY_CODE(FUNC_CODE, INST_INVOKE)
+      STRINGIFY_CODE(FUNC_CODE, INST_UNOP)
+      STRINGIFY_CODE(FUNC_CODE, INST_UNREACHABLE)
+      STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET)
+      STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET)
+      STRINGIFY_CODE(FUNC_CODE, INST_CATCHPAD)
+      STRINGIFY_CODE(FUNC_CODE, INST_PHI)
+      STRINGIFY_CODE(FUNC_CODE, INST_ALLOCA)
+      STRINGIFY_CODE(FUNC_CODE, INST_LOAD)
+      STRINGIFY_CODE(FUNC_CODE, INST_VAARG)
+      STRINGIFY_CODE(FUNC_CODE, INST_STORE)
+      STRINGIFY_CODE(FUNC_CODE, INST_EXTRACTVAL)
+      STRINGIFY_CODE(FUNC_CODE, INST_INSERTVAL)
+      STRINGIFY_CODE(FUNC_CODE, INST_CMP2)
+      STRINGIFY_CODE(FUNC_CODE, INST_VSELECT)
+      STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC_AGAIN)
+      STRINGIFY_CODE(FUNC_CODE, INST_CALL)
+      STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC)
+      STRINGIFY_CODE(FUNC_CODE, INST_GEP)
+      STRINGIFY_CODE(FUNC_CODE, OPERAND_BUNDLE)
+      STRINGIFY_CODE(FUNC_CODE, INST_FENCE)
+      STRINGIFY_CODE(FUNC_CODE, INST_ATOMICRMW)
+      STRINGIFY_CODE(FUNC_CODE, INST_LOADATOMIC)
+      STRINGIFY_CODE(FUNC_CODE, INST_STOREATOMIC)
+      STRINGIFY_CODE(FUNC_CODE, INST_CMPXCHG)
+      STRINGIFY_CODE(FUNC_CODE, INST_CALLBR)
+    }
+  case bitc::VALUE_SYMTAB_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(VST_CODE, ENTRY)
+      STRINGIFY_CODE(VST_CODE, BBENTRY)
+      STRINGIFY_CODE(VST_CODE, FNENTRY)
+      STRINGIFY_CODE(VST_CODE, COMBINED_ENTRY)
+    }
+  case bitc::MODULE_STRTAB_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(MST_CODE, ENTRY)
+      STRINGIFY_CODE(MST_CODE, HASH)
+    }
+  case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
+  case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(FS, PERMODULE)
+      STRINGIFY_CODE(FS, PERMODULE_PROFILE)
+      STRINGIFY_CODE(FS, PERMODULE_RELBF)
+      STRINGIFY_CODE(FS, PERMODULE_GLOBALVAR_INIT_REFS)
+      STRINGIFY_CODE(FS, PERMODULE_VTABLE_GLOBALVAR_INIT_REFS)
+      STRINGIFY_CODE(FS, COMBINED)
+      STRINGIFY_CODE(FS, COMBINED_PROFILE)
+      STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS)
+      STRINGIFY_CODE(FS, ALIAS)
+      STRINGIFY_CODE(FS, COMBINED_ALIAS)
+      STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME)
+      STRINGIFY_CODE(FS, VERSION)
+      STRINGIFY_CODE(FS, FLAGS)
+      STRINGIFY_CODE(FS, TYPE_TESTS)
+      STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_VCALLS)
+      STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS)
+      STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL)
+      STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
+      STRINGIFY_CODE(FS, VALUE_GUID)
+      STRINGIFY_CODE(FS, CFI_FUNCTION_DEFS)
+      STRINGIFY_CODE(FS, CFI_FUNCTION_DECLS)
+      STRINGIFY_CODE(FS, TYPE_ID)
+      STRINGIFY_CODE(FS, TYPE_ID_METADATA)
+    }
+  case bitc::METADATA_ATTACHMENT_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(METADATA, ATTACHMENT)
+    }
+  case bitc::METADATA_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(METADATA, STRING_OLD)
+      STRINGIFY_CODE(METADATA, VALUE)
+      STRINGIFY_CODE(METADATA, NODE)
+      STRINGIFY_CODE(METADATA, NAME)
+      STRINGIFY_CODE(METADATA, DISTINCT_NODE)
+      STRINGIFY_CODE(METADATA, KIND) // Older bitcode has it in a MODULE_BLOCK
+      STRINGIFY_CODE(METADATA, LOCATION)
+      STRINGIFY_CODE(METADATA, OLD_NODE)
+      STRINGIFY_CODE(METADATA, OLD_FN_NODE)
+      STRINGIFY_CODE(METADATA, NAMED_NODE)
+      STRINGIFY_CODE(METADATA, GENERIC_DEBUG)
+      STRINGIFY_CODE(METADATA, SUBRANGE)
+      STRINGIFY_CODE(METADATA, ENUMERATOR)
+      STRINGIFY_CODE(METADATA, BASIC_TYPE)
+      STRINGIFY_CODE(METADATA, FILE)
+      STRINGIFY_CODE(METADATA, DERIVED_TYPE)
+      STRINGIFY_CODE(METADATA, COMPOSITE_TYPE)
+      STRINGIFY_CODE(METADATA, SUBROUTINE_TYPE)
+      STRINGIFY_CODE(METADATA, COMPILE_UNIT)
+      STRINGIFY_CODE(METADATA, SUBPROGRAM)
+      STRINGIFY_CODE(METADATA, LEXICAL_BLOCK)
+      STRINGIFY_CODE(METADATA, LEXICAL_BLOCK_FILE)
+      STRINGIFY_CODE(METADATA, NAMESPACE)
+      STRINGIFY_CODE(METADATA, TEMPLATE_TYPE)
+      STRINGIFY_CODE(METADATA, TEMPLATE_VALUE)
+      STRINGIFY_CODE(METADATA, GLOBAL_VAR)
+      STRINGIFY_CODE(METADATA, LOCAL_VAR)
+      STRINGIFY_CODE(METADATA, EXPRESSION)
+      STRINGIFY_CODE(METADATA, OBJC_PROPERTY)
+      STRINGIFY_CODE(METADATA, IMPORTED_ENTITY)
+      STRINGIFY_CODE(METADATA, MODULE)
+      STRINGIFY_CODE(METADATA, MACRO)
+      STRINGIFY_CODE(METADATA, MACRO_FILE)
+      STRINGIFY_CODE(METADATA, STRINGS)
+      STRINGIFY_CODE(METADATA, GLOBAL_DECL_ATTACHMENT)
+      STRINGIFY_CODE(METADATA, GLOBAL_VAR_EXPR)
+      STRINGIFY_CODE(METADATA, INDEX_OFFSET)
+      STRINGIFY_CODE(METADATA, INDEX)
+    }
+  case bitc::METADATA_KIND_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+      STRINGIFY_CODE(METADATA, KIND)
+    }
+  case bitc::USELIST_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+    case bitc::USELIST_CODE_DEFAULT:
+      return "USELIST_CODE_DEFAULT";
+    case bitc::USELIST_CODE_BB:
+      return "USELIST_CODE_BB";
+    }
+
+  case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+    case bitc::OPERAND_BUNDLE_TAG:
+      return "OPERAND_BUNDLE_TAG";
+    }
+  case bitc::STRTAB_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+    case bitc::STRTAB_BLOB:
+      return "BLOB";
+    }
+  case bitc::SYMTAB_BLOCK_ID:
+    switch (CodeID) {
+    default:
+      return None;
+    case bitc::SYMTAB_BLOB:
+      return "BLOB";
+    }
+  }
+#undef STRINGIFY_CODE
+}
+
+static void printSize(raw_ostream &OS, double Bits) {
+  OS << format("%.2f/%.2fB/%luW", Bits, Bits / 8, (unsigned long)(Bits / 32));
+}
+static void printSize(raw_ostream &OS, uint64_t Bits) {
+  OS << format("%lub/%.2fB/%luW", (unsigned long)Bits, (double)Bits / 8,
+               (unsigned long)(Bits / 32));
+}
+
+static Expected<CurStreamTypeType> ReadSignature(BitstreamCursor &Stream) {
+  auto tryRead = [&Stream](char &Dest, size_t size) -> Error {
+    if (Expected<SimpleBitstreamCursor::word_t> MaybeWord = Stream.Read(size))
+      Dest = MaybeWord.get();
+    else
+      return MaybeWord.takeError();
+    return Error::success();
+  };
+
+  char Signature[6];
+  if (Error Err = tryRead(Signature[0], 8))
+    return std::move(Err);
+  if (Error Err = tryRead(Signature[1], 8))
+    return std::move(Err);
+
+  // Autodetect the file contents, if it is one we know.
+  if (Signature[0] == 'C' && Signature[1] == 'P') {
+    if (Error Err = tryRead(Signature[2], 8))
+      return std::move(Err);
+    if (Error Err = tryRead(Signature[3], 8))
+      return std::move(Err);
+    if (Signature[2] == 'C' && Signature[3] == 'H')
+      return ClangSerializedASTBitstream;
+  } else if (Signature[0] == 'D' && Signature[1] == 'I') {
+    if (Error Err = tryRead(Signature[2], 8))
+      return std::move(Err);
+    if (Error Err = tryRead(Signature[3], 8))
+      return std::move(Err);
+    if (Signature[2] == 'A' && Signature[3] == 'G')
+      return ClangSerializedDiagnosticsBitstream;
+  } else {
+    if (Error Err = tryRead(Signature[2], 4))
+      return std::move(Err);
+    if (Error Err = tryRead(Signature[3], 4))
+      return std::move(Err);
+    if (Error Err = tryRead(Signature[4], 4))
+      return std::move(Err);
+    if (Error Err = tryRead(Signature[5], 4))
+      return std::move(Err);
+    if (Signature[0] == 'B' && Signature[1] == 'C' && Signature[2] == 0x0 &&
+        Signature[3] == 0xC && Signature[4] == 0xE && Signature[5] == 0xD)
+      return LLVMIRBitstream;
+  }
+  return UnknownBitstream;
+}
+
+static Expected<CurStreamTypeType> analyzeHeader(Optional<BCDumpOptions> O,
+                                                 BitstreamCursor &Stream) {
+  ArrayRef<uint8_t> Bytes = Stream.getBitcodeBytes();
+  const unsigned char *BufPtr = (const unsigned char *)Bytes.data();
+  const unsigned char *EndBufPtr = BufPtr + Bytes.size();
+
+  // If we have a wrapper header, parse it and ignore the non-bc file
+  // contents. The magic number is 0x0B17C0DE stored in little endian.
+  if (isBitcodeWrapper(BufPtr, EndBufPtr)) {
+    if (Bytes.size() < BWH_HeaderSize)
+      return reportError("Invalid bitcode wrapper header");
+
+    if (O) {
+      unsigned Magic = support::endian::read32le(&BufPtr[BWH_MagicField]);
+      unsigned Version = support::endian::read32le(&BufPtr[BWH_VersionField]);
+      unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]);
+      unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]);
+      unsigned CPUType = support::endian::read32le(&BufPtr[BWH_CPUTypeField]);
+
+      O->OS << "<BITCODE_WRAPPER_HEADER"
+            << " Magic=" << format_hex(Magic, 10)
+            << " Version=" << format_hex(Version, 10)
+            << " Offset=" << format_hex(Offset, 10)
+            << " Size=" << format_hex(Size, 10)
+            << " CPUType=" << format_hex(CPUType, 10) << "/>\n";
+    }
+
+    if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true))
+      return reportError("Invalid bitcode wrapper header");
+  }
+
+  // Use the cursor modified by skipping the wrapper header.
+  Stream = BitstreamCursor(ArrayRef<uint8_t>(BufPtr, EndBufPtr));
+
+  return ReadSignature(Stream);
+}
+
+static bool canDecodeBlob(unsigned Code, unsigned BlockID) {
+  return BlockID == bitc::METADATA_BLOCK_ID && Code == bitc::METADATA_STRINGS;
+}
+
+Error BitcodeAnalyzer::decodeMetadataStringsBlob(StringRef Indent,
+                                                 ArrayRef<uint64_t> Record,
+                                                 StringRef Blob,
+                                                 raw_ostream &OS) {
+  if (Blob.empty())
+    return reportError("Cannot decode empty blob.");
+
+  if (Record.size() != 2)
+    return reportError(
+        "Decoding metadata strings blob needs two record entries.");
+
+  unsigned NumStrings = Record[0];
+  unsigned StringsOffset = Record[1];
+  OS << " num-strings = " << NumStrings << " {\n";
+
+  StringRef Lengths = Blob.slice(0, StringsOffset);
+  SimpleBitstreamCursor R(Lengths);
+  StringRef Strings = Blob.drop_front(StringsOffset);
+  do {
+    if (R.AtEndOfStream())
+      return reportError("bad length");
+
+    Expected<uint32_t> MaybeSize = R.ReadVBR(6);
+    if (!MaybeSize)
+      return MaybeSize.takeError();
+    uint32_t Size = MaybeSize.get();
+    if (Strings.size() < Size)
+      return reportError("truncated chars");
+
+    OS << Indent << "    '";
+    OS.write_escaped(Strings.slice(0, Size), /*hex=*/true);
+    OS << "'\n";
+    Strings = Strings.drop_front(Size);
+  } while (--NumStrings);
+
+  OS << Indent << "  }";
+  return Error::success();
+}
+
+BitcodeAnalyzer::BitcodeAnalyzer(StringRef Buffer,
+                                 Optional<StringRef> BlockInfoBuffer)
+    : Stream(Buffer) {
+  if (BlockInfoBuffer)
+    BlockInfoStream.emplace(*BlockInfoBuffer);
+}
+
+Error BitcodeAnalyzer::analyze(Optional<BCDumpOptions> O,
+                               Optional<StringRef> CheckHash) {
+  if (Expected<CurStreamTypeType> H = analyzeHeader(O, Stream))
+    CurStreamType = *H;
+
+  Stream.setBlockInfo(&BlockInfo);
+
+  // Read block info from BlockInfoStream, if specified.
+  // The block info must be a top-level block.
+  if (BlockInfoStream) {
+    BitstreamCursor BlockInfoCursor(*BlockInfoStream);
+    CurStreamTypeType BlockInfoStreamType;
+    Expected<CurStreamTypeType> H = analyzeHeader(O, BlockInfoCursor);
+    if (!H)
+      return H.takeError();
+    BlockInfoStreamType = *H;
+
+    while (!BlockInfoCursor.AtEndOfStream()) {
+      Expected<unsigned> MaybeCode = BlockInfoCursor.ReadCode();
+      if (!MaybeCode)
+        return MaybeCode.takeError();
+      if (MaybeCode.get() != bitc::ENTER_SUBBLOCK)
+        return reportError("Invalid record at top-level in block info file");
+
+      Expected<unsigned> MaybeBlockID = BlockInfoCursor.ReadSubBlockID();
+      if (!MaybeBlockID)
+        return MaybeBlockID.takeError();
+      if (MaybeBlockID.get() == bitc::BLOCKINFO_BLOCK_ID) {
+        Expected<Optional<BitstreamBlockInfo>> MaybeNewBlockInfo =
+            BlockInfoCursor.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
+        if (!MaybeNewBlockInfo)
+          return MaybeNewBlockInfo.takeError();
+        Optional<BitstreamBlockInfo> NewBlockInfo =
+            std::move(MaybeNewBlockInfo.get());
+        if (!NewBlockInfo)
+          return reportError("Malformed BlockInfoBlock in block info file");
+        BlockInfo = std::move(*NewBlockInfo);
+        break;
+      }
+
+      if (Error Err = BlockInfoCursor.SkipBlock())
+        return Err;
+    }
+  }
+
+  // Parse the top-level structure.  We only allow blocks at the top-level.
+  while (!Stream.AtEndOfStream()) {
+    Expected<unsigned> MaybeCode = Stream.ReadCode();
+    if (!MaybeCode)
+      return MaybeCode.takeError();
+    if (MaybeCode.get() != bitc::ENTER_SUBBLOCK)
+      return reportError("Invalid record at top-level");
+
+    Expected<unsigned> MaybeBlockID = Stream.ReadSubBlockID();
+    if (!MaybeBlockID)
+      return MaybeBlockID.takeError();
+
+    if (Error E = parseBlock(MaybeBlockID.get(), 0, O, CheckHash))
+      return E;
+    ++NumTopBlocks;
+  }
+
+  return Error::success();
+}
+
+void BitcodeAnalyzer::printStats(BCDumpOptions O,
+                                 Optional<StringRef> Filename) {
+  uint64_t BufferSizeBits = Stream.getBitcodeBytes().size() * CHAR_BIT;
+  // Print a summary of the read file.
+  O.OS << "Summary ";
+  if (Filename)
+    O.OS << "of " << Filename->data() << ":\n";
+  O.OS << "         Total size: ";
+  printSize(O.OS, BufferSizeBits);
+  O.OS << "\n";
+  O.OS << "        Stream type: ";
+  switch (CurStreamType) {
+  case UnknownBitstream:
+    O.OS << "unknown\n";
+    break;
+  case LLVMIRBitstream:
+    O.OS << "LLVM IR\n";
+    break;
+  case ClangSerializedASTBitstream:
+    O.OS << "Clang Serialized AST\n";
+    break;
+  case ClangSerializedDiagnosticsBitstream:
+    O.OS << "Clang Serialized Diagnostics\n";
+    break;
+  }
+  O.OS << "  # Toplevel Blocks: " << NumTopBlocks << "\n";
+  O.OS << "\n";
+
+  // Emit per-block stats.
+  O.OS << "Per-block Summary:\n";
+  for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
+                                                     E = BlockIDStats.end();
+       I != E; ++I) {
+    O.OS << "  Block ID #" << I->first;
+    if (Optional<const char *> BlockName =
+            GetBlockName(I->first, BlockInfo, CurStreamType))
+      O.OS << " (" << *BlockName << ")";
+    O.OS << ":\n";
+
+    const PerBlockIDStats &Stats = I->second;
+    O.OS << "      Num Instances: " << Stats.NumInstances << "\n";
+    O.OS << "         Total Size: ";
+    printSize(O.OS, Stats.NumBits);
+    O.OS << "\n";
+    double pct = (Stats.NumBits * 100.0) / BufferSizeBits;
+    O.OS << "    Percent of file: " << format("%2.4f%%", pct) << "\n";
+    if (Stats.NumInstances > 1) {
+      O.OS << "       Average Size: ";
+      printSize(O.OS, Stats.NumBits / (double)Stats.NumInstances);
+      O.OS << "\n";
+      O.OS << "  Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
+           << Stats.NumSubBlocks / (double)Stats.NumInstances << "\n";
+      O.OS << "    Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
+           << Stats.NumAbbrevs / (double)Stats.NumInstances << "\n";
+      O.OS << "    Tot/Avg Records: " << Stats.NumRecords << "/"
+           << Stats.NumRecords / (double)Stats.NumInstances << "\n";
+    } else {
+      O.OS << "      Num SubBlocks: " << Stats.NumSubBlocks << "\n";
+      O.OS << "        Num Abbrevs: " << Stats.NumAbbrevs << "\n";
+      O.OS << "        Num Records: " << Stats.NumRecords << "\n";
+    }
+    if (Stats.NumRecords) {
+      double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords;
+      O.OS << "    Percent Abbrevs: " << format("%2.4f%%", pct) << "\n";
+    }
+    O.OS << "\n";
+
+    // Print a histogram of the codes we see.
+    if (O.Histogram && !Stats.CodeFreq.empty()) {
+      std::vector<std::pair<unsigned, unsigned>> FreqPairs; // <freq,code>
+      for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i)
+        if (unsigned Freq = Stats.CodeFreq[i].NumInstances)
+          FreqPairs.push_back(std::make_pair(Freq, i));
+      llvm::stable_sort(FreqPairs);
+      std::reverse(FreqPairs.begin(), FreqPairs.end());
+
+      O.OS << "\tRecord Histogram:\n";
+      O.OS << "\t\t  Count    # Bits     b/Rec   % Abv  Record Kind\n";
+      for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) {
+        const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second];
+
+        O.OS << format("\t\t%7d %9lu", RecStats.NumInstances,
+                       (unsigned long)RecStats.TotalBits);
+
+        if (RecStats.NumInstances > 1)
+          O.OS << format(" %9.1f",
+                         (double)RecStats.TotalBits / RecStats.NumInstances);
+        else
+          O.OS << "          ";
+
+        if (RecStats.NumAbbrev)
+          O.OS << format(" %7.2f", (double)RecStats.NumAbbrev /
+                                       RecStats.NumInstances * 100);
+        else
+          O.OS << "        ";
+
+        O.OS << "  ";
+        if (Optional<const char *> CodeName = GetCodeName(
+                FreqPairs[i].second, I->first, BlockInfo, CurStreamType))
+          O.OS << *CodeName << "\n";
+        else
+          O.OS << "UnknownCode" << FreqPairs[i].second << "\n";
+      }
+      O.OS << "\n";
+    }
+  }
+}
+
+Error BitcodeAnalyzer::parseBlock(unsigned BlockID, unsigned IndentLevel,
+                                  Optional<BCDumpOptions> O,
+                                  Optional<StringRef> CheckHash) {
+  std::string Indent(IndentLevel * 2, ' ');
+  uint64_t BlockBitStart = Stream.GetCurrentBitNo();
+
+  // Get the statistics for this BlockID.
+  PerBlockIDStats &BlockStats = BlockIDStats[BlockID];
+
+  BlockStats.NumInstances++;
+
+  // BLOCKINFO is a special part of the stream.
+  bool DumpRecords = O.hasValue();
+  if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
+    if (O)
+      O->OS << Indent << "<BLOCKINFO_BLOCK/>\n";
+    Expected<Optional<BitstreamBlockInfo>> MaybeNewBlockInfo =
+        Stream.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
+    if (!MaybeNewBlockInfo)
+      return MaybeNewBlockInfo.takeError();
+    Optional<BitstreamBlockInfo> NewBlockInfo =
+        std::move(MaybeNewBlockInfo.get());
+    if (!NewBlockInfo)
+      return reportError("Malformed BlockInfoBlock");
+    BlockInfo = std::move(*NewBlockInfo);
+    if (Error Err = Stream.JumpToBit(BlockBitStart))
+      return Err;
+    // It's not really interesting to dump the contents of the blockinfo
+    // block.
+    DumpRecords = false;
+  }
+
+  unsigned NumWords = 0;
+  if (Error Err = Stream.EnterSubBlock(BlockID, &NumWords))
+    return Err;
+
+  // Keep it for later, when we see a MODULE_HASH record
+  uint64_t BlockEntryPos = Stream.getCurrentByteNo();
+
+  Optional<const char *> BlockName = None;
+  if (DumpRecords) {
+    O->OS << Indent << "<";
+    if ((BlockName = GetBlockName(BlockID, BlockInfo, CurStreamType)))
+      O->OS << *BlockName;
+    else
+      O->OS << "UnknownBlock" << BlockID;
+
+    if (!O->Symbolic && BlockName)
+      O->OS << " BlockID=" << BlockID;
+
+    O->OS << " NumWords=" << NumWords
+          << " BlockCodeSize=" << Stream.getAbbrevIDWidth() << ">\n";
+  }
+
+  SmallVector<uint64_t, 64> Record;
+
+  // Keep the offset to the metadata index if seen.
+  uint64_t MetadataIndexOffset = 0;
+
+  // Read all the records for this block.
+  while (1) {
+    if (Stream.AtEndOfStream())
+      return reportError("Premature end of bitstream");
+
+    uint64_t RecordStartBit = Stream.GetCurrentBitNo();
+
+    Expected<BitstreamEntry> MaybeEntry =
+        Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
+    if (!MaybeEntry)
+      return MaybeEntry.takeError();
+    BitstreamEntry Entry = MaybeEntry.get();
+
+    switch (Entry.Kind) {
+    case BitstreamEntry::Error:
+      return reportError("malformed bitcode file");
+    case BitstreamEntry::EndBlock: {
+      uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
+      BlockStats.NumBits += BlockBitEnd - BlockBitStart;
+      if (DumpRecords) {
+        O->OS << Indent << "</";
+        if (BlockName)
+          O->OS << *BlockName << ">\n";
+        else
+          O->OS << "UnknownBlock" << BlockID << ">\n";
+      }
+      return Error::success();
+    }
+
+    case BitstreamEntry::SubBlock: {
+      uint64_t SubBlockBitStart = Stream.GetCurrentBitNo();
+      if (Error E = parseBlock(Entry.ID, IndentLevel + 1, O, CheckHash))
+        return E;
+      ++BlockStats.NumSubBlocks;
+      uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo();
+
+      // Don't include subblock sizes in the size of this block.
+      BlockBitStart += SubBlockBitEnd - SubBlockBitStart;
+      continue;
+    }
+    case BitstreamEntry::Record:
+      // The interesting case.
+      break;
+    }
+
+    if (Entry.ID == bitc::DEFINE_ABBREV) {
+      if (Error Err = Stream.ReadAbbrevRecord())
+        return Err;
+      ++BlockStats.NumAbbrevs;
+      continue;
+    }
+
+    Record.clear();
+
+    ++BlockStats.NumRecords;
+
+    StringRef Blob;
+    uint64_t CurrentRecordPos = Stream.GetCurrentBitNo();
+    Expected<unsigned> MaybeCode = Stream.readRecord(Entry.ID, Record, &Blob);
+    if (!MaybeCode)
+      return MaybeCode.takeError();
+    unsigned Code = MaybeCode.get();
+
+    // Increment the # occurrences of this code.
+    if (BlockStats.CodeFreq.size() <= Code)
+      BlockStats.CodeFreq.resize(Code + 1);
+    BlockStats.CodeFreq[Code].NumInstances++;
+    BlockStats.CodeFreq[Code].TotalBits +=
+        Stream.GetCurrentBitNo() - RecordStartBit;
+    if (Entry.ID != bitc::UNABBREV_RECORD) {
+      BlockStats.CodeFreq[Code].NumAbbrev++;
+      ++BlockStats.NumAbbreviatedRecords;
+    }
+
+    if (DumpRecords) {
+      O->OS << Indent << "  <";
+      Optional<const char *> CodeName =
+          GetCodeName(Code, BlockID, BlockInfo, CurStreamType);
+      if (CodeName)
+        O->OS << *CodeName;
+      else
+        O->OS << "UnknownCode" << Code;
+      if (!O->Symbolic && CodeName)
+        O->OS << " codeid=" << Code;
+      const BitCodeAbbrev *Abbv = nullptr;
+      if (Entry.ID != bitc::UNABBREV_RECORD) {
+        Abbv = Stream.getAbbrev(Entry.ID);
+        O->OS << " abbrevid=" << Entry.ID;
+      }
+
+      for (unsigned i = 0, e = Record.size(); i != e; ++i)
+        O->OS << " op" << i << "=" << (int64_t)Record[i];
+
+      // If we found a metadata index, let's verify that we had an offset
+      // before and validate its forward reference offset was correct!
+      if (BlockID == bitc::METADATA_BLOCK_ID) {
+        if (Code == bitc::METADATA_INDEX_OFFSET) {
+          if (Record.size() != 2)
+            O->OS << "(Invalid record)";
+          else {
+            auto Offset = Record[0] + (Record[1] << 32);
+            MetadataIndexOffset = Stream.GetCurrentBitNo() + Offset;
+          }
+        }
+        if (Code == bitc::METADATA_INDEX) {
+          O->OS << " (offset ";
+          if (MetadataIndexOffset == RecordStartBit)
+            O->OS << "match)";
+          else
+            O->OS << "mismatch: " << MetadataIndexOffset << " vs "
+                  << RecordStartBit << ")";
+        }
+      }
+
+      // If we found a module hash, let's verify that it matches!
+      if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH &&
+          CheckHash.hasValue()) {
+        if (Record.size() != 5)
+          O->OS << " (invalid)";
+        else {
+          // Recompute the hash and compare it to the one in the bitcode
+          SHA1 Hasher;
+          StringRef Hash;
+          Hasher.update(*CheckHash);
+          {
+            int BlockSize = (CurrentRecordPos / 8) - BlockEntryPos;
+            auto Ptr = Stream.getPointerToByte(BlockEntryPos, BlockSize);
+            Hasher.update(ArrayRef<uint8_t>(Ptr, BlockSize));
+            Hash = Hasher.result();
+          }
+          SmallString<20> RecordedHash;
+          RecordedHash.resize(20);
+          int Pos = 0;
+          for (auto &Val : Record) {
+            assert(!(Val >> 32) && "Unexpected high bits set");
+            RecordedHash[Pos++] = (Val >> 24) & 0xFF;
+            RecordedHash[Pos++] = (Val >> 16) & 0xFF;
+            RecordedHash[Pos++] = (Val >> 8) & 0xFF;
+            RecordedHash[Pos++] = (Val >> 0) & 0xFF;
+          }
+          if (Hash == RecordedHash)
+            O->OS << " (match)";
+          else
+            O->OS << " (!mismatch!)";
+        }
+      }
+
+      O->OS << "/>";
+
+      if (Abbv) {
+        for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) {
+          const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i);
+          if (!Op.isEncoding() || Op.getEncoding() != BitCodeAbbrevOp::Array)
+            continue;
+          assert(i + 2 == e && "Array op not second to last");
+          std::string Str;
+          bool ArrayIsPrintable = true;
+          for (unsigned j = i - 1, je = Record.size(); j != je; ++j) {
+            if (!isPrint(static_cast<unsigned char>(Record[j]))) {
+              ArrayIsPrintable = false;
+              break;
+            }
+            Str += (char)Record[j];
+          }
+          if (ArrayIsPrintable)
+            O->OS << " record string = '" << Str << "'";
+          break;
+        }
+      }
+
+      if (Blob.data()) {
+        if (canDecodeBlob(Code, BlockID)) {
+          if (Error E = decodeMetadataStringsBlob(Indent, Record, Blob, O->OS))
+            return E;
+        } else {
+          O->OS << " blob data = ";
+          if (O->ShowBinaryBlobs) {
+            O->OS << "'";
+            O->OS.write_escaped(Blob, /*hex=*/true) << "'";
+          } else {
+            bool BlobIsPrintable = true;
+            for (unsigned i = 0, e = Blob.size(); i != e; ++i)
+              if (!isPrint(static_cast<unsigned char>(Blob[i]))) {
+                BlobIsPrintable = false;
+                break;
+              }
+
+            if (BlobIsPrintable)
+              O->OS << "'" << Blob << "'";
+            else
+              O->OS << "unprintable, " << Blob.size() << " bytes.";
+          }
+        }
+      }
+
+      O->OS << "\n";
+    }
+
+    // Make sure that we can skip the current record.
+    if (Error Err = Stream.JumpToBit(CurrentRecordPos))
+      return Err;
+    if (Expected<unsigned> Skipped = Stream.skipRecord(Entry.ID))
+      ; // Do nothing.
+    else
+      return Skipped.takeError();
+  }
+}
+

Modified: llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt?rev=365286&r1=365285&r2=365286&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt (original)
+++ llvm/trunk/lib/Bitcode/Reader/CMakeLists.txt Sun Jul  7 19:06:34 2019
@@ -1,4 +1,5 @@
 add_llvm_library(LLVMBitReader
+  BitcodeAnalyzer.cpp
   BitReader.cpp
   BitcodeReader.cpp
   MetadataLoader.cpp

Modified: llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp?rev=365286&r1=365285&r2=365286&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp (original)
+++ llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp Sun Jul  7 19:06:34 2019
@@ -26,22 +26,18 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/Bitstream/BitstreamReader.h"
-#include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Bitcode/BitcodeAnalyzer.h"
 #include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Format.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SHA1.h"
-#include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
+#include <memory>
 using namespace llvm;
 
 static cl::opt<std::string>
-  InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
+    InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
 
 static cl::opt<bool> Dump("dump", cl::desc("Dump low level bitcode trace"));
 
@@ -52,1009 +48,66 @@ static cl::opt<bool> Dump("dump", cl::de
 static cl::opt<bool> NoHistogram("disable-histogram",
                                  cl::desc("Do not print per-code histogram"));
 
-static cl::opt<bool>
-NonSymbolic("non-symbolic",
-            cl::desc("Emit numeric info in dump even if"
-                     " symbolic info is available"));
+static cl::opt<bool> NonSymbolic("non-symbolic",
+                                 cl::desc("Emit numeric info in dump even if"
+                                          " symbolic info is available"));
 
 static cl::opt<std::string>
-  BlockInfoFilename("block-info",
-                    cl::desc("Use the BLOCK_INFO from the given file"));
+    BlockInfoFilename("block-info",
+                      cl::desc("Use the BLOCK_INFO from the given file"));
 
 static cl::opt<bool>
-  ShowBinaryBlobs("show-binary-blobs",
-                  cl::desc("Print binary blobs using hex escapes"));
+    ShowBinaryBlobs("show-binary-blobs",
+                    cl::desc("Print binary blobs using hex escapes"));
 
 static cl::opt<std::string> CheckHash(
     "check-hash",
     cl::desc("Check module hash using the argument as a string table"));
 
-namespace {
-
-/// CurStreamTypeType - A type for CurStreamType
-enum CurStreamTypeType {
-  UnknownBitstream,
-  LLVMIRBitstream,
-  ClangSerializedASTBitstream,
-  ClangSerializedDiagnosticsBitstream,
-};
-
-}
-
-/// GetBlockName - Return a symbolic block name if known, otherwise return
-/// null.
-static const char *GetBlockName(unsigned BlockID,
-                                const BitstreamBlockInfo &BlockInfo,
-                                CurStreamTypeType CurStreamType) {
-  // Standard blocks for all bitcode files.
-  if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
-    if (BlockID == bitc::BLOCKINFO_BLOCK_ID)
-      return "BLOCKINFO_BLOCK";
-    return nullptr;
-  }
-
-  // Check to see if we have a blockinfo record for this block, with a name.
-  if (const BitstreamBlockInfo::BlockInfo *Info =
-          BlockInfo.getBlockInfo(BlockID)) {
-    if (!Info->Name.empty())
-      return Info->Name.c_str();
-  }
-
-
-  if (CurStreamType != LLVMIRBitstream) return nullptr;
-
-  switch (BlockID) {
-  default:                                 return nullptr;
-  case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: return "OPERAND_BUNDLE_TAGS_BLOCK";
-  case bitc::MODULE_BLOCK_ID:              return "MODULE_BLOCK";
-  case bitc::PARAMATTR_BLOCK_ID:           return "PARAMATTR_BLOCK";
-  case bitc::PARAMATTR_GROUP_BLOCK_ID:     return "PARAMATTR_GROUP_BLOCK_ID";
-  case bitc::TYPE_BLOCK_ID_NEW:            return "TYPE_BLOCK_ID";
-  case bitc::CONSTANTS_BLOCK_ID:           return "CONSTANTS_BLOCK";
-  case bitc::FUNCTION_BLOCK_ID:            return "FUNCTION_BLOCK";
-  case bitc::IDENTIFICATION_BLOCK_ID:
-                                           return "IDENTIFICATION_BLOCK_ID";
-  case bitc::VALUE_SYMTAB_BLOCK_ID:        return "VALUE_SYMTAB";
-  case bitc::METADATA_BLOCK_ID:            return "METADATA_BLOCK";
-  case bitc::METADATA_KIND_BLOCK_ID:       return "METADATA_KIND_BLOCK";
-  case bitc::METADATA_ATTACHMENT_ID:       return "METADATA_ATTACHMENT_BLOCK";
-  case bitc::USELIST_BLOCK_ID:             return "USELIST_BLOCK_ID";
-  case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
-                                           return "GLOBALVAL_SUMMARY_BLOCK";
-  case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
-                                      return "FULL_LTO_GLOBALVAL_SUMMARY_BLOCK";
-  case bitc::MODULE_STRTAB_BLOCK_ID:       return "MODULE_STRTAB_BLOCK";
-  case bitc::STRTAB_BLOCK_ID:              return "STRTAB_BLOCK";
-  case bitc::SYMTAB_BLOCK_ID:              return "SYMTAB_BLOCK";
-  }
-}
-
-/// GetCodeName - Return a symbolic code name if known, otherwise return
-/// null.
-static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
-                               const BitstreamBlockInfo &BlockInfo,
-                               CurStreamTypeType CurStreamType) {
-  // Standard blocks for all bitcode files.
-  if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
-    if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
-      switch (CodeID) {
-      default: return nullptr;
-      case bitc::BLOCKINFO_CODE_SETBID:        return "SETBID";
-      case bitc::BLOCKINFO_CODE_BLOCKNAME:     return "BLOCKNAME";
-      case bitc::BLOCKINFO_CODE_SETRECORDNAME: return "SETRECORDNAME";
-      }
-    }
-    return nullptr;
-  }
-
-  // Check to see if we have a blockinfo record for this record, with a name.
-  if (const BitstreamBlockInfo::BlockInfo *Info =
-        BlockInfo.getBlockInfo(BlockID)) {
-    for (unsigned i = 0, e = Info->RecordNames.size(); i != e; ++i)
-      if (Info->RecordNames[i].first == CodeID)
-        return Info->RecordNames[i].second.c_str();
-  }
-
-
-  if (CurStreamType != LLVMIRBitstream) return nullptr;
-
-#define STRINGIFY_CODE(PREFIX, CODE)                                           \
-  case bitc::PREFIX##_##CODE:                                                  \
-    return #CODE;
-  switch (BlockID) {
-  default: return nullptr;
-  case bitc::MODULE_BLOCK_ID:
-    switch (CodeID) {
-    default: return nullptr;
-      STRINGIFY_CODE(MODULE_CODE, VERSION)
-      STRINGIFY_CODE(MODULE_CODE, TRIPLE)
-      STRINGIFY_CODE(MODULE_CODE, DATALAYOUT)
-      STRINGIFY_CODE(MODULE_CODE, ASM)
-      STRINGIFY_CODE(MODULE_CODE, SECTIONNAME)
-      STRINGIFY_CODE(MODULE_CODE, DEPLIB) // FIXME: Remove in 4.0
-      STRINGIFY_CODE(MODULE_CODE, GLOBALVAR)
-      STRINGIFY_CODE(MODULE_CODE, FUNCTION)
-      STRINGIFY_CODE(MODULE_CODE, ALIAS)
-      STRINGIFY_CODE(MODULE_CODE, GCNAME)
-      STRINGIFY_CODE(MODULE_CODE, VSTOFFSET)
-      STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES_UNUSED)
-      STRINGIFY_CODE(MODULE_CODE, SOURCE_FILENAME)
-      STRINGIFY_CODE(MODULE_CODE, HASH)
-    }
-  case bitc::IDENTIFICATION_BLOCK_ID:
-    switch (CodeID) {
-    default:
-      return nullptr;
-      STRINGIFY_CODE(IDENTIFICATION_CODE, STRING)
-      STRINGIFY_CODE(IDENTIFICATION_CODE, EPOCH)
-    }
-  case bitc::PARAMATTR_BLOCK_ID:
-    switch (CodeID) {
-    default: return nullptr;
-    // FIXME: Should these be different?
-    case bitc::PARAMATTR_CODE_ENTRY_OLD: return "ENTRY";
-    case bitc::PARAMATTR_CODE_ENTRY:     return "ENTRY";
-    }
-  case bitc::PARAMATTR_GROUP_BLOCK_ID:
-    switch (CodeID) {
-    default: return nullptr;
-    case bitc::PARAMATTR_GRP_CODE_ENTRY: return "ENTRY";
-    }
-  case bitc::TYPE_BLOCK_ID_NEW:
-    switch (CodeID) {
-    default: return nullptr;
-      STRINGIFY_CODE(TYPE_CODE, NUMENTRY)
-      STRINGIFY_CODE(TYPE_CODE, VOID)
-      STRINGIFY_CODE(TYPE_CODE, FLOAT)
-      STRINGIFY_CODE(TYPE_CODE, DOUBLE)
-      STRINGIFY_CODE(TYPE_CODE, LABEL)
-      STRINGIFY_CODE(TYPE_CODE, OPAQUE)
-      STRINGIFY_CODE(TYPE_CODE, INTEGER)
-      STRINGIFY_CODE(TYPE_CODE, POINTER)
-      STRINGIFY_CODE(TYPE_CODE, ARRAY)
-      STRINGIFY_CODE(TYPE_CODE, VECTOR)
-      STRINGIFY_CODE(TYPE_CODE, X86_FP80)
-      STRINGIFY_CODE(TYPE_CODE, FP128)
-      STRINGIFY_CODE(TYPE_CODE, PPC_FP128)
-      STRINGIFY_CODE(TYPE_CODE, METADATA)
-      STRINGIFY_CODE(TYPE_CODE, STRUCT_ANON)
-      STRINGIFY_CODE(TYPE_CODE, STRUCT_NAME)
-      STRINGIFY_CODE(TYPE_CODE, STRUCT_NAMED)
-      STRINGIFY_CODE(TYPE_CODE, FUNCTION)
-    }
-
-  case bitc::CONSTANTS_BLOCK_ID:
-    switch (CodeID) {
-    default: return nullptr;
-      STRINGIFY_CODE(CST_CODE, SETTYPE)
-      STRINGIFY_CODE(CST_CODE, NULL)
-      STRINGIFY_CODE(CST_CODE, UNDEF)
-      STRINGIFY_CODE(CST_CODE, INTEGER)
-      STRINGIFY_CODE(CST_CODE, WIDE_INTEGER)
-      STRINGIFY_CODE(CST_CODE, FLOAT)
-      STRINGIFY_CODE(CST_CODE, AGGREGATE)
-      STRINGIFY_CODE(CST_CODE, STRING)
-      STRINGIFY_CODE(CST_CODE, CSTRING)
-      STRINGIFY_CODE(CST_CODE, CE_BINOP)
-      STRINGIFY_CODE(CST_CODE, CE_CAST)
-      STRINGIFY_CODE(CST_CODE, CE_GEP)
-      STRINGIFY_CODE(CST_CODE, CE_INBOUNDS_GEP)
-      STRINGIFY_CODE(CST_CODE, CE_SELECT)
-      STRINGIFY_CODE(CST_CODE, CE_EXTRACTELT)
-      STRINGIFY_CODE(CST_CODE, CE_INSERTELT)
-      STRINGIFY_CODE(CST_CODE, CE_SHUFFLEVEC)
-      STRINGIFY_CODE(CST_CODE, CE_CMP)
-      STRINGIFY_CODE(CST_CODE, INLINEASM)
-      STRINGIFY_CODE(CST_CODE, CE_SHUFVEC_EX)
-      STRINGIFY_CODE(CST_CODE, CE_UNOP)
-    case bitc::CST_CODE_BLOCKADDRESS:    return "CST_CODE_BLOCKADDRESS";
-      STRINGIFY_CODE(CST_CODE, DATA)
-    }
-  case bitc::FUNCTION_BLOCK_ID:
-    switch (CodeID) {
-    default: return nullptr;
-      STRINGIFY_CODE(FUNC_CODE, DECLAREBLOCKS)
-      STRINGIFY_CODE(FUNC_CODE, INST_BINOP)
-      STRINGIFY_CODE(FUNC_CODE, INST_CAST)
-      STRINGIFY_CODE(FUNC_CODE, INST_GEP_OLD)
-      STRINGIFY_CODE(FUNC_CODE, INST_INBOUNDS_GEP_OLD)
-      STRINGIFY_CODE(FUNC_CODE, INST_SELECT)
-      STRINGIFY_CODE(FUNC_CODE, INST_EXTRACTELT)
-      STRINGIFY_CODE(FUNC_CODE, INST_INSERTELT)
-      STRINGIFY_CODE(FUNC_CODE, INST_SHUFFLEVEC)
-      STRINGIFY_CODE(FUNC_CODE, INST_CMP)
-      STRINGIFY_CODE(FUNC_CODE, INST_RET)
-      STRINGIFY_CODE(FUNC_CODE, INST_BR)
-      STRINGIFY_CODE(FUNC_CODE, INST_SWITCH)
-      STRINGIFY_CODE(FUNC_CODE, INST_INVOKE)
-      STRINGIFY_CODE(FUNC_CODE, INST_UNOP)
-      STRINGIFY_CODE(FUNC_CODE, INST_UNREACHABLE)
-      STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET)
-      STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET)
-      STRINGIFY_CODE(FUNC_CODE, INST_CATCHPAD)
-      STRINGIFY_CODE(FUNC_CODE, INST_PHI)
-      STRINGIFY_CODE(FUNC_CODE, INST_ALLOCA)
-      STRINGIFY_CODE(FUNC_CODE, INST_LOAD)
-      STRINGIFY_CODE(FUNC_CODE, INST_VAARG)
-      STRINGIFY_CODE(FUNC_CODE, INST_STORE)
-      STRINGIFY_CODE(FUNC_CODE, INST_EXTRACTVAL)
-      STRINGIFY_CODE(FUNC_CODE, INST_INSERTVAL)
-      STRINGIFY_CODE(FUNC_CODE, INST_CMP2)
-      STRINGIFY_CODE(FUNC_CODE, INST_VSELECT)
-      STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC_AGAIN)
-      STRINGIFY_CODE(FUNC_CODE, INST_CALL)
-      STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC)
-      STRINGIFY_CODE(FUNC_CODE, INST_GEP)
-      STRINGIFY_CODE(FUNC_CODE, OPERAND_BUNDLE)
-      STRINGIFY_CODE(FUNC_CODE, INST_FENCE)
-      STRINGIFY_CODE(FUNC_CODE, INST_ATOMICRMW)
-      STRINGIFY_CODE(FUNC_CODE, INST_LOADATOMIC)
-      STRINGIFY_CODE(FUNC_CODE, INST_STOREATOMIC)
-      STRINGIFY_CODE(FUNC_CODE, INST_CMPXCHG)
-      STRINGIFY_CODE(FUNC_CODE, INST_CALLBR)
-    }
-  case bitc::VALUE_SYMTAB_BLOCK_ID:
-    switch (CodeID) {
-    default: return nullptr;
-    STRINGIFY_CODE(VST_CODE, ENTRY)
-    STRINGIFY_CODE(VST_CODE, BBENTRY)
-    STRINGIFY_CODE(VST_CODE, FNENTRY)
-    STRINGIFY_CODE(VST_CODE, COMBINED_ENTRY)
-    }
-  case bitc::MODULE_STRTAB_BLOCK_ID:
-    switch (CodeID) {
-    default:
-      return nullptr;
-      STRINGIFY_CODE(MST_CODE, ENTRY)
-      STRINGIFY_CODE(MST_CODE, HASH)
-    }
-  case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
-  case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
-    switch (CodeID) {
-    default:
-      return nullptr;
-      STRINGIFY_CODE(FS, PERMODULE)
-      STRINGIFY_CODE(FS, PERMODULE_PROFILE)
-      STRINGIFY_CODE(FS, PERMODULE_RELBF)
-      STRINGIFY_CODE(FS, PERMODULE_GLOBALVAR_INIT_REFS)
-      STRINGIFY_CODE(FS, PERMODULE_VTABLE_GLOBALVAR_INIT_REFS)
-      STRINGIFY_CODE(FS, COMBINED)
-      STRINGIFY_CODE(FS, COMBINED_PROFILE)
-      STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS)
-      STRINGIFY_CODE(FS, ALIAS)
-      STRINGIFY_CODE(FS, COMBINED_ALIAS)
-      STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME)
-      STRINGIFY_CODE(FS, VERSION)
-      STRINGIFY_CODE(FS, FLAGS)
-      STRINGIFY_CODE(FS, TYPE_TESTS)
-      STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_VCALLS)
-      STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS)
-      STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL)
-      STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
-      STRINGIFY_CODE(FS, VALUE_GUID)
-      STRINGIFY_CODE(FS, CFI_FUNCTION_DEFS)
-      STRINGIFY_CODE(FS, CFI_FUNCTION_DECLS)
-      STRINGIFY_CODE(FS, TYPE_ID)
-      STRINGIFY_CODE(FS, TYPE_ID_METADATA)
-    }
-  case bitc::METADATA_ATTACHMENT_ID:
-    switch(CodeID) {
-    default:return nullptr;
-      STRINGIFY_CODE(METADATA, ATTACHMENT)
-    }
-  case bitc::METADATA_BLOCK_ID:
-    switch(CodeID) {
-    default:return nullptr;
-      STRINGIFY_CODE(METADATA, STRING_OLD)
-      STRINGIFY_CODE(METADATA, VALUE)
-      STRINGIFY_CODE(METADATA, NODE)
-      STRINGIFY_CODE(METADATA, NAME)
-      STRINGIFY_CODE(METADATA, DISTINCT_NODE)
-      STRINGIFY_CODE(METADATA, KIND) // Older bitcode has it in a MODULE_BLOCK
-      STRINGIFY_CODE(METADATA, LOCATION)
-      STRINGIFY_CODE(METADATA, OLD_NODE)
-      STRINGIFY_CODE(METADATA, OLD_FN_NODE)
-      STRINGIFY_CODE(METADATA, NAMED_NODE)
-      STRINGIFY_CODE(METADATA, GENERIC_DEBUG)
-      STRINGIFY_CODE(METADATA, SUBRANGE)
-      STRINGIFY_CODE(METADATA, ENUMERATOR)
-      STRINGIFY_CODE(METADATA, BASIC_TYPE)
-      STRINGIFY_CODE(METADATA, FILE)
-      STRINGIFY_CODE(METADATA, DERIVED_TYPE)
-      STRINGIFY_CODE(METADATA, COMPOSITE_TYPE)
-      STRINGIFY_CODE(METADATA, SUBROUTINE_TYPE)
-      STRINGIFY_CODE(METADATA, COMPILE_UNIT)
-      STRINGIFY_CODE(METADATA, SUBPROGRAM)
-      STRINGIFY_CODE(METADATA, LEXICAL_BLOCK)
-      STRINGIFY_CODE(METADATA, LEXICAL_BLOCK_FILE)
-      STRINGIFY_CODE(METADATA, NAMESPACE)
-      STRINGIFY_CODE(METADATA, TEMPLATE_TYPE)
-      STRINGIFY_CODE(METADATA, TEMPLATE_VALUE)
-      STRINGIFY_CODE(METADATA, GLOBAL_VAR)
-      STRINGIFY_CODE(METADATA, LOCAL_VAR)
-      STRINGIFY_CODE(METADATA, EXPRESSION)
-      STRINGIFY_CODE(METADATA, OBJC_PROPERTY)
-      STRINGIFY_CODE(METADATA, IMPORTED_ENTITY)
-      STRINGIFY_CODE(METADATA, MODULE)
-      STRINGIFY_CODE(METADATA, MACRO)
-      STRINGIFY_CODE(METADATA, MACRO_FILE)
-      STRINGIFY_CODE(METADATA, STRINGS)
-      STRINGIFY_CODE(METADATA, GLOBAL_DECL_ATTACHMENT)
-      STRINGIFY_CODE(METADATA, GLOBAL_VAR_EXPR)
-      STRINGIFY_CODE(METADATA, INDEX_OFFSET)
-      STRINGIFY_CODE(METADATA, INDEX)
-    }
-  case bitc::METADATA_KIND_BLOCK_ID:
-    switch (CodeID) {
-    default:
-      return nullptr;
-      STRINGIFY_CODE(METADATA, KIND)
-    }
-  case bitc::USELIST_BLOCK_ID:
-    switch(CodeID) {
-    default:return nullptr;
-    case bitc::USELIST_CODE_DEFAULT: return "USELIST_CODE_DEFAULT";
-    case bitc::USELIST_CODE_BB:      return "USELIST_CODE_BB";
-    }
-
-  case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID:
-    switch(CodeID) {
-    default: return nullptr;
-    case bitc::OPERAND_BUNDLE_TAG: return "OPERAND_BUNDLE_TAG";
-    }
-  case bitc::STRTAB_BLOCK_ID:
-    switch(CodeID) {
-    default: return nullptr;
-    case bitc::STRTAB_BLOB: return "BLOB";
-    }
-  case bitc::SYMTAB_BLOCK_ID:
-    switch(CodeID) {
-    default: return nullptr;
-    case bitc::SYMTAB_BLOB: return "BLOB";
-    }
-  }
-#undef STRINGIFY_CODE
+static Error reportError(StringRef Message) {
+  return createStringError(std::errc::illegal_byte_sequence, Message.data());
 }
 
-struct PerRecordStats {
-  unsigned NumInstances;
-  unsigned NumAbbrev;
-  uint64_t TotalBits;
-
-  PerRecordStats() : NumInstances(0), NumAbbrev(0), TotalBits(0) {}
-};
-
-struct PerBlockIDStats {
-  /// NumInstances - This the number of times this block ID has been seen.
-  unsigned NumInstances;
-
-  /// NumBits - The total size in bits of all of these blocks.
-  uint64_t NumBits;
-
-  /// NumSubBlocks - The total number of blocks these blocks contain.
-  unsigned NumSubBlocks;
-
-  /// NumAbbrevs - The total number of abbreviations.
-  unsigned NumAbbrevs;
-
-  /// NumRecords - The total number of records these blocks contain, and the
-  /// number that are abbreviated.
-  unsigned NumRecords, NumAbbreviatedRecords;
-
-  /// CodeFreq - Keep track of the number of times we see each code.
-  std::vector<PerRecordStats> CodeFreq;
-
-  PerBlockIDStats()
-    : NumInstances(0), NumBits(0),
-      NumSubBlocks(0), NumAbbrevs(0), NumRecords(0), NumAbbreviatedRecords(0) {}
-};
-
-static std::map<unsigned, PerBlockIDStats> BlockIDStats;
-
-/// All bitcode analysis errors go through this function, making this a good
-/// place to breakpoint if debugging.
-static bool ReportError(const Twine &Err) {
-  WithColor::error() << Err << "\n";
-  return true;
-}
-
-static bool ReportError(Error &&Err) {
-  return ReportError(toString(std::move(Err)));
-}
-
-static bool decodeMetadataStringsBlob(StringRef Indent,
-                                      ArrayRef<uint64_t> Record,
-                                      StringRef Blob) {
-  if (Blob.empty())
-    return true;
-
-  if (Record.size() != 2)
-    return true;
-
-  unsigned NumStrings = Record[0];
-  unsigned StringsOffset = Record[1];
-  outs() << " num-strings = " << NumStrings << " {\n";
-
-  StringRef Lengths = Blob.slice(0, StringsOffset);
-  SimpleBitstreamCursor R(Lengths);
-  StringRef Strings = Blob.drop_front(StringsOffset);
-  do {
-    if (R.AtEndOfStream())
-      return ReportError("bad length");
-
-    Expected<uint32_t> MaybeSize = R.ReadVBR(6);
-    if (!MaybeSize)
-      return ReportError(MaybeSize.takeError());
-    uint32_t Size = MaybeSize.get();
-    if (Strings.size() < Size)
-      return ReportError("truncated chars");
-
-    outs() << Indent << "    '";
-    outs().write_escaped(Strings.slice(0, Size), /*hex=*/true);
-    outs() << "'\n";
-    Strings = Strings.drop_front(Size);
-  } while (--NumStrings);
-
-  outs() << Indent << "  }";
-  return false;
-}
-
-static bool decodeBlob(unsigned Code, unsigned BlockID, StringRef Indent,
-                       ArrayRef<uint64_t> Record, StringRef Blob) {
-  if (BlockID != bitc::METADATA_BLOCK_ID)
-    return true;
-  if (Code != bitc::METADATA_STRINGS)
-    return true;
-
-  return decodeMetadataStringsBlob(Indent, Record, Blob);
-}
-
-/// ParseBlock - Read a block, updating statistics, etc.
-static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
-                       unsigned BlockID, unsigned IndentLevel,
-                       CurStreamTypeType CurStreamType) {
-  std::string Indent(IndentLevel*2, ' ');
-  uint64_t BlockBitStart = Stream.GetCurrentBitNo();
-
-  // Get the statistics for this BlockID.
-  PerBlockIDStats &BlockStats = BlockIDStats[BlockID];
-
-  BlockStats.NumInstances++;
-
-  // BLOCKINFO is a special part of the stream.
-  bool DumpRecords = Dump;
-  if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
-    if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n";
-    Expected<Optional<BitstreamBlockInfo>> MaybeNewBlockInfo =
-        Stream.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
-    if (!MaybeNewBlockInfo)
-      return ReportError(MaybeNewBlockInfo.takeError());
-    Optional<BitstreamBlockInfo> NewBlockInfo =
-        std::move(MaybeNewBlockInfo.get());
-    if (!NewBlockInfo)
-      return ReportError("Malformed BlockInfoBlock");
-    BlockInfo = std::move(*NewBlockInfo);
-    if (Error Err = Stream.JumpToBit(BlockBitStart))
-      return ReportError(std::move(Err));
-    // It's not really interesting to dump the contents of the blockinfo block.
-    DumpRecords = false;
-  }
-
-  unsigned NumWords = 0;
-  if (Error Err = Stream.EnterSubBlock(BlockID, &NumWords))
-    return ReportError(std::move(Err));
-
-  // Keep it for later, when we see a MODULE_HASH record
-  uint64_t BlockEntryPos = Stream.getCurrentByteNo();
-
-  const char *BlockName = nullptr;
-  if (DumpRecords) {
-    outs() << Indent << "<";
-    if ((BlockName = GetBlockName(BlockID, BlockInfo, CurStreamType)))
-      outs() << BlockName;
-    else
-      outs() << "UnknownBlock" << BlockID;
-
-    if (NonSymbolic && BlockName)
-      outs() << " BlockID=" << BlockID;
-
-    outs() << " NumWords=" << NumWords
-           << " BlockCodeSize=" << Stream.getAbbrevIDWidth() << ">\n";
-  }
-
-  SmallVector<uint64_t, 64> Record;
-
-  // Keep the offset to the metadata index if seen.
-  uint64_t MetadataIndexOffset = 0;
-
-  // Read all the records for this block.
-  while (1) {
-    if (Stream.AtEndOfStream())
-      return ReportError("Premature end of bitstream");
-
-    uint64_t RecordStartBit = Stream.GetCurrentBitNo();
-
-    Expected<BitstreamEntry> MaybeEntry =
-        Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
-    if (!MaybeEntry)
-      return ReportError(MaybeEntry.takeError());
-    BitstreamEntry Entry = MaybeEntry.get();
-
-    switch (Entry.Kind) {
-    case BitstreamEntry::Error:
-      return ReportError("malformed bitcode file");
-    case BitstreamEntry::EndBlock: {
-      uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
-      BlockStats.NumBits += BlockBitEnd-BlockBitStart;
-      if (DumpRecords) {
-        outs() << Indent << "</";
-        if (BlockName)
-          outs() << BlockName << ">\n";
-        else
-          outs() << "UnknownBlock" << BlockID << ">\n";
-      }
-      return false;
-    }
-        
-    case BitstreamEntry::SubBlock: {
-      uint64_t SubBlockBitStart = Stream.GetCurrentBitNo();
-      if (ParseBlock(Stream, BlockInfo, Entry.ID, IndentLevel + 1,
-                     CurStreamType))
-        return true;
-      ++BlockStats.NumSubBlocks;
-      uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo();
-      
-      // Don't include subblock sizes in the size of this block.
-      BlockBitStart += SubBlockBitEnd-SubBlockBitStart;
-      continue;
-    }
-    case BitstreamEntry::Record:
-      // The interesting case.
-      break;
-    }
-
-    if (Entry.ID == bitc::DEFINE_ABBREV) {
-      if (Error Err = Stream.ReadAbbrevRecord())
-        return ReportError(std::move(Err));
-      ++BlockStats.NumAbbrevs;
-      continue;
-    }
-    
-    Record.clear();
-
-    ++BlockStats.NumRecords;
-
-    StringRef Blob;
-    uint64_t CurrentRecordPos = Stream.GetCurrentBitNo();
-    Expected<unsigned> MaybeCode = Stream.readRecord(Entry.ID, Record, &Blob);
-    if (!MaybeCode)
-      return ReportError(MaybeCode.takeError());
-    unsigned Code = MaybeCode.get();
-
-    // Increment the # occurrences of this code.
-    if (BlockStats.CodeFreq.size() <= Code)
-      BlockStats.CodeFreq.resize(Code+1);
-    BlockStats.CodeFreq[Code].NumInstances++;
-    BlockStats.CodeFreq[Code].TotalBits +=
-      Stream.GetCurrentBitNo()-RecordStartBit;
-    if (Entry.ID != bitc::UNABBREV_RECORD) {
-      BlockStats.CodeFreq[Code].NumAbbrev++;
-      ++BlockStats.NumAbbreviatedRecords;
-    }
-
-    if (DumpRecords) {
-      outs() << Indent << "  <";
-      if (const char *CodeName =
-              GetCodeName(Code, BlockID, BlockInfo, CurStreamType))
-        outs() << CodeName;
-      else
-        outs() << "UnknownCode" << Code;
-      if (NonSymbolic && GetCodeName(Code, BlockID, BlockInfo, CurStreamType))
-        outs() << " codeid=" << Code;
-      const BitCodeAbbrev *Abbv = nullptr;
-      if (Entry.ID != bitc::UNABBREV_RECORD) {
-        Abbv = Stream.getAbbrev(Entry.ID);
-        outs() << " abbrevid=" << Entry.ID;
-      }
-
-      for (unsigned i = 0, e = Record.size(); i != e; ++i)
-        outs() << " op" << i << "=" << (int64_t)Record[i];
-
-      // If we found a metadata index, let's verify that we had an offset before
-      // and validate its forward reference offset was correct!
-      if (BlockID == bitc::METADATA_BLOCK_ID) {
-        if (Code == bitc::METADATA_INDEX_OFFSET) {
-          if (Record.size() != 2)
-            outs() << "(Invalid record)";
-          else {
-            auto Offset = Record[0] + (Record[1] << 32);
-            MetadataIndexOffset = Stream.GetCurrentBitNo() + Offset;
-          }
-        }
-        if (Code == bitc::METADATA_INDEX) {
-          outs() << " (offset ";
-          if (MetadataIndexOffset == RecordStartBit)
-            outs() << "match)";
-          else
-            outs() << "mismatch: " << MetadataIndexOffset << " vs "
-                   << RecordStartBit << ")";
-        }
-      }
-
-      // If we found a module hash, let's verify that it matches!
-      if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH &&
-          !CheckHash.empty()) {
-        if (Record.size() != 5)
-          outs() << " (invalid)";
-        else {
-          // Recompute the hash and compare it to the one in the bitcode
-          SHA1 Hasher;
-          StringRef Hash;
-          Hasher.update(CheckHash);
-          {
-            int BlockSize = (CurrentRecordPos / 8) - BlockEntryPos;
-            auto Ptr = Stream.getPointerToByte(BlockEntryPos, BlockSize);
-            Hasher.update(ArrayRef<uint8_t>(Ptr, BlockSize));
-            Hash = Hasher.result();
-          }
-          SmallString<20> RecordedHash;
-          RecordedHash.resize(20);
-          int Pos = 0;
-          for (auto &Val : Record) {
-            assert(!(Val >> 32) && "Unexpected high bits set");
-            RecordedHash[Pos++] = (Val >> 24) & 0xFF;
-            RecordedHash[Pos++] = (Val >> 16) & 0xFF;
-            RecordedHash[Pos++] = (Val >> 8) & 0xFF;
-            RecordedHash[Pos++] = (Val >> 0) & 0xFF;
-          }
-          if (Hash == RecordedHash)
-            outs() << " (match)";
-          else
-            outs() << " (!mismatch!)";
-        }
-      }
-
-      outs() << "/>";
-
-      if (Abbv) {
-        for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) {
-          const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i);
-          if (!Op.isEncoding() || Op.getEncoding() != BitCodeAbbrevOp::Array)
-            continue;
-          assert(i + 2 == e && "Array op not second to last");
-          std::string Str;
-          bool ArrayIsPrintable = true;
-          for (unsigned j = i - 1, je = Record.size(); j != je; ++j) {
-            if (!isPrint(static_cast<unsigned char>(Record[j]))) {
-              ArrayIsPrintable = false;
-              break;
-            }
-            Str += (char)Record[j];
-          }
-          if (ArrayIsPrintable)
-            outs() << " record string = '" << Str << "'";
-          break;
-        }
-      }
-
-      if (Blob.data() && decodeBlob(Code, BlockID, Indent, Record, Blob)) {
-        outs() << " blob data = ";
-        if (ShowBinaryBlobs) {
-          outs() << "'";
-          outs().write_escaped(Blob, /*hex=*/true) << "'";
-        } else {
-          bool BlobIsPrintable = true;
-          for (unsigned i = 0, e = Blob.size(); i != e; ++i)
-            if (!isPrint(static_cast<unsigned char>(Blob[i]))) {
-              BlobIsPrintable = false;
-              break;
-            }
-
-          if (BlobIsPrintable)
-            outs() << "'" << Blob << "'";
-          else
-            outs() << "unprintable, " << Blob.size() << " bytes.";          
-        }
-      }
-
-      outs() << "\n";
-    }
-
-    // Make sure that we can skip the current record.
-    if (Error Err = Stream.JumpToBit(CurrentRecordPos))
-      return ReportError(std::move(Err));
-    if (Expected<unsigned> Skipped = Stream.skipRecord(Entry.ID))
-      ; // Do nothing.
-    else
-      return ReportError(Skipped.takeError());
-  }
-}
-
-static void PrintSize(double Bits) {
-  outs() << format("%.2f/%.2fB/%luW", Bits, Bits/8,(unsigned long)(Bits/32));
-}
-static void PrintSize(uint64_t Bits) {
-  outs() << format("%lub/%.2fB/%luW", (unsigned long)Bits,
-                   (double)Bits/8, (unsigned long)(Bits/32));
-}
-
-static Expected<CurStreamTypeType> ReadSignature(BitstreamCursor &Stream) {
-  auto tryRead = [&Stream](char &Dest, size_t size) -> Error {
-    if (Expected<SimpleBitstreamCursor::word_t> MaybeWord = Stream.Read(size))
-      Dest = MaybeWord.get();
-    else
-      return MaybeWord.takeError();
-    return Error::success();
-  };
-
-  char Signature[6];
-  if (Error Err = tryRead(Signature[0], 8))
-    return std::move(Err);
-  if (Error Err = tryRead(Signature[1], 8))
-    return std::move(Err);
-
-  // Autodetect the file contents, if it is one we know.
-  if (Signature[0] == 'C' && Signature[1] == 'P') {
-    if (Error Err = tryRead(Signature[2], 8))
-      return std::move(Err);
-    if (Error Err = tryRead(Signature[3], 8))
-      return std::move(Err);
-    if (Signature[2] == 'C' && Signature[3] == 'H')
-      return ClangSerializedASTBitstream;
-  } else if (Signature[0] == 'D' && Signature[1] == 'I') {
-    if (Error Err = tryRead(Signature[2], 8))
-      return std::move(Err);
-    if (Error Err = tryRead(Signature[3], 8))
-      return std::move(Err);
-    if (Signature[2] == 'A' && Signature[3] == 'G')
-      return ClangSerializedDiagnosticsBitstream;
-  } else {
-    if (Error Err = tryRead(Signature[2], 4))
-      return std::move(Err);
-    if (Error Err = tryRead(Signature[3], 4))
-      return std::move(Err);
-    if (Error Err = tryRead(Signature[4], 4))
-      return std::move(Err);
-    if (Error Err = tryRead(Signature[5], 4))
-      return std::move(Err);
-    if (Signature[0] == 'B' && Signature[1] == 'C' &&
-        Signature[2] == 0x0 && Signature[3] == 0xC &&
-        Signature[4] == 0xE && Signature[5] == 0xD)
-      return LLVMIRBitstream;
-  }
-  return UnknownBitstream;
-}
-
-static bool openBitcodeFile(StringRef Path,
-                            std::unique_ptr<MemoryBuffer> &MemBuf,
-                            BitstreamCursor &Stream,
-                            CurStreamTypeType &CurStreamType) {
+static Expected<std::unique_ptr<MemoryBuffer>> openBitcodeFile(StringRef Path) {
   // Read the input file.
-  ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
-      MemoryBuffer::getFileOrSTDIN(Path);
-  if (std::error_code EC = MemBufOrErr.getError())
-    return ReportError(Twine("ReportError reading '") + Path + "': " + EC.message());
-  MemBuf = std::move(MemBufOrErr.get());
-
-  if (MemBuf->getBufferSize() & 3)
-    return ReportError("Bitcode stream should be a multiple of 4 bytes in length");
-
-  const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart();
-  const unsigned char *EndBufPtr = BufPtr + MemBuf->getBufferSize();
+  Expected<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
+      errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Path));
+  if (Error E = MemBufOrErr.takeError())
+    return std::move(E);
 
-  // If we have a wrapper header, parse it and ignore the non-bc file contents.
-  // The magic number is 0x0B17C0DE stored in little endian.
-  if (isBitcodeWrapper(BufPtr, EndBufPtr)) {
-    if (MemBuf->getBufferSize() < BWH_HeaderSize)
-      return ReportError("Invalid bitcode wrapper header");
+  std::unique_ptr<MemoryBuffer> MemBuf = std::move(*MemBufOrErr);
 
-    if (Dump) {
-      unsigned Magic = support::endian::read32le(&BufPtr[BWH_MagicField]);
-      unsigned Version = support::endian::read32le(&BufPtr[BWH_VersionField]);
-      unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]);
-      unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]);
-      unsigned CPUType = support::endian::read32le(&BufPtr[BWH_CPUTypeField]);
-
-      outs() << "<BITCODE_WRAPPER_HEADER"
-             << " Magic=" << format_hex(Magic, 10)
-             << " Version=" << format_hex(Version, 10)
-             << " Offset=" << format_hex(Offset, 10)
-             << " Size=" << format_hex(Size, 10)
-             << " CPUType=" << format_hex(CPUType, 10) << "/>\n";
-    }
-
-    if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true))
-      return ReportError("Invalid bitcode wrapper header");
-  }
-
-  Stream = BitstreamCursor(ArrayRef<uint8_t>(BufPtr, EndBufPtr));
-  Expected<CurStreamTypeType> MaybeSignature = ReadSignature(Stream);
-  if (!MaybeSignature)
-    return ReportError(MaybeSignature.takeError());
-  CurStreamType = std::move(MaybeSignature.get());
-
-  return false;
+  if (MemBuf->getBufferSize() & 3)
+    return reportError(
+        "Bitcode stream should be a multiple of 4 bytes in length");
+  return std::move(MemBuf);
 }
 
-/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
-static int AnalyzeBitcode() {
-  std::unique_ptr<MemoryBuffer> StreamBuffer;
-  BitstreamCursor Stream;
-  BitstreamBlockInfo BlockInfo;
-  CurStreamTypeType CurStreamType;
-  if (openBitcodeFile(InputFilename, StreamBuffer, Stream, CurStreamType))
-    return true;
-  Stream.setBlockInfo(&BlockInfo);
-
-  // Read block info from BlockInfoFilename, if specified.
-  // The block info must be a top-level block.
-  if (!BlockInfoFilename.empty()) {
-    std::unique_ptr<MemoryBuffer> BlockInfoBuffer;
-    BitstreamCursor BlockInfoCursor;
-    CurStreamTypeType BlockInfoStreamType;
-    if (openBitcodeFile(BlockInfoFilename, BlockInfoBuffer, BlockInfoCursor,
-                        BlockInfoStreamType))
-      return true;
-
-    while (!BlockInfoCursor.AtEndOfStream()) {
-      Expected<unsigned> MaybeCode = BlockInfoCursor.ReadCode();
-      if (!MaybeCode)
-        return ReportError(MaybeCode.takeError());
-      if (MaybeCode.get() != bitc::ENTER_SUBBLOCK)
-        return ReportError("Invalid record at top-level in block info file");
-
-      Expected<unsigned> MaybeBlockID = BlockInfoCursor.ReadSubBlockID();
-      if (!MaybeBlockID)
-        return ReportError(MaybeBlockID.takeError());
-      if (MaybeBlockID.get() == bitc::BLOCKINFO_BLOCK_ID) {
-        Expected<Optional<BitstreamBlockInfo>> MaybeNewBlockInfo =
-            BlockInfoCursor.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
-        if (!MaybeNewBlockInfo)
-          return ReportError(MaybeNewBlockInfo.takeError());
-        Optional<BitstreamBlockInfo> NewBlockInfo =
-            std::move(MaybeNewBlockInfo.get());
-        if (!NewBlockInfo)
-          return ReportError("Malformed BlockInfoBlock in block info file");
-        BlockInfo = std::move(*NewBlockInfo);
-        break;
-      }
-
-      if (Error Err = BlockInfoCursor.SkipBlock())
-        return ReportError(std::move(Err));
-    }
-  }
-
-  unsigned NumTopBlocks = 0;
-
-  // Parse the top-level structure.  We only allow blocks at the top-level.
-  while (!Stream.AtEndOfStream()) {
-    Expected<unsigned> MaybeCode = Stream.ReadCode();
-    if (!MaybeCode)
-      return ReportError(MaybeCode.takeError());
-    if (MaybeCode.get() != bitc::ENTER_SUBBLOCK)
-      return ReportError("Invalid record at top-level");
-
-    Expected<unsigned> MaybeBlockID = Stream.ReadSubBlockID();
-    if (!MaybeBlockID)
-      return ReportError(MaybeBlockID.takeError());
-
-    if (ParseBlock(Stream, BlockInfo, MaybeBlockID.get(), 0, CurStreamType))
-      return true;
-    ++NumTopBlocks;
-  }
-
-  if (Dump) outs() << "\n\n";
-
-  uint64_t BufferSizeBits = Stream.getBitcodeBytes().size() * CHAR_BIT;
-  // Print a summary of the read file.
-  outs() << "Summary of " << InputFilename << ":\n";
-  outs() << "         Total size: ";
-  PrintSize(BufferSizeBits);
-  outs() << "\n";
-  outs() << "        Stream type: ";
-  switch (CurStreamType) {
-  case UnknownBitstream:
-    outs() << "unknown\n";
-    break;
-  case LLVMIRBitstream:
-    outs() << "LLVM IR\n";
-    break;
-  case ClangSerializedASTBitstream:
-    outs() << "Clang Serialized AST\n";
-    break;
-  case ClangSerializedDiagnosticsBitstream:
-    outs() << "Clang Serialized Diagnostics\n";
-    break;
-  }
-  outs() << "  # Toplevel Blocks: " << NumTopBlocks << "\n";
-  outs() << "\n";
-
-  // Emit per-block stats.
-  outs() << "Per-block Summary:\n";
-  for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
-       E = BlockIDStats.end(); I != E; ++I) {
-    outs() << "  Block ID #" << I->first;
-    if (const char *BlockName =
-            GetBlockName(I->first, BlockInfo, CurStreamType))
-      outs() << " (" << BlockName << ")";
-    outs() << ":\n";
-
-    const PerBlockIDStats &Stats = I->second;
-    outs() << "      Num Instances: " << Stats.NumInstances << "\n";
-    outs() << "         Total Size: ";
-    PrintSize(Stats.NumBits);
-    outs() << "\n";
-    double pct = (Stats.NumBits * 100.0) / BufferSizeBits;
-    outs() << "    Percent of file: " << format("%2.4f%%", pct) << "\n";
-    if (Stats.NumInstances > 1) {
-      outs() << "       Average Size: ";
-      PrintSize(Stats.NumBits/(double)Stats.NumInstances);
-      outs() << "\n";
-      outs() << "  Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
-             << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n";
-      outs() << "    Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
-             << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n";
-      outs() << "    Tot/Avg Records: " << Stats.NumRecords << "/"
-             << Stats.NumRecords/(double)Stats.NumInstances << "\n";
-    } else {
-      outs() << "      Num SubBlocks: " << Stats.NumSubBlocks << "\n";
-      outs() << "        Num Abbrevs: " << Stats.NumAbbrevs << "\n";
-      outs() << "        Num Records: " << Stats.NumRecords << "\n";
-    }
-    if (Stats.NumRecords) {
-      double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords;
-      outs() << "    Percent Abbrevs: " << format("%2.4f%%", pct) << "\n";
-    }
-    outs() << "\n";
-
-    // Print a histogram of the codes we see.
-    if (!NoHistogram && !Stats.CodeFreq.empty()) {
-      std::vector<std::pair<unsigned, unsigned> > FreqPairs;  // <freq,code>
-      for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i)
-        if (unsigned Freq = Stats.CodeFreq[i].NumInstances)
-          FreqPairs.push_back(std::make_pair(Freq, i));
-      llvm::stable_sort(FreqPairs);
-      std::reverse(FreqPairs.begin(), FreqPairs.end());
+int main(int argc, char **argv) {
+  InitLLVM X(argc, argv);
+  cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n");
+  ExitOnError ExitOnErr("llvm-bcanalyzer: ");
 
-      outs() << "\tRecord Histogram:\n";
-      outs() << "\t\t  Count    # Bits     b/Rec   % Abv  Record Kind\n";
-      for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) {
-        const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second];
+  std::unique_ptr<MemoryBuffer> MB = ExitOnErr(openBitcodeFile(InputFilename));
+  std::unique_ptr<MemoryBuffer> BlockInfoMB = nullptr;
+  if (!BlockInfoFilename.empty())
+    BlockInfoMB = ExitOnErr(openBitcodeFile(BlockInfoFilename));
 
-        outs() << format("\t\t%7d %9lu",
-                         RecStats.NumInstances,
-                         (unsigned long)RecStats.TotalBits);
+  BitcodeAnalyzer BA(MB->getBuffer(),
+                     BlockInfoMB ? Optional<StringRef>(BlockInfoMB->getBuffer())
+                                 : None);
 
-        if (RecStats.NumInstances > 1)
-          outs() << format(" %9.1f",
-                           (double)RecStats.TotalBits/RecStats.NumInstances);
-        else
-          outs() << "          ";
+  BCDumpOptions O(outs());
+  O.Histogram = !NoHistogram;
+  O.Symbolic = !NonSymbolic;
+  O.ShowBinaryBlobs = ShowBinaryBlobs;
 
-        if (RecStats.NumAbbrev)
-          outs() <<
-              format(" %7.2f",
-                     (double)RecStats.NumAbbrev/RecStats.NumInstances*100);
-        else
-          outs() << "        ";
+  ExitOnErr(
+      BA.analyze(O, CheckHash.empty() ? None : Optional<StringRef>(CheckHash)));
 
-        outs() << "  ";
-        if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first,
-                                               BlockInfo, CurStreamType))
-          outs() << CodeName << "\n";
-        else
-          outs() << "UnknownCode" << FreqPairs[i].second << "\n";
-      }
-      outs() << "\n";
+  if (Dump)
+    outs() << "\n\n";
 
-    }
-  }
+  BA.printStats(O, StringRef(InputFilename.getValue()));
   return 0;
 }
-
-
-int main(int argc, char **argv) {
-  InitLLVM X(argc, argv);
-  cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n");
-  return AnalyzeBitcode();
-}




More information about the llvm-commits mailing list