summaryrefslogtreecommitdiff
path: root/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp')
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp210
1 files changed, 174 insertions, 36 deletions
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index fe68689def60a..319e34d882dcc 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -27,8 +27,8 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Bitcode/LLVMBitCodes.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Verifier.h"
@@ -37,6 +37,7 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/SHA1.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -103,23 +104,24 @@ static const char *GetBlockName(unsigned BlockID,
if (CurStreamType != LLVMIRBitstream) return nullptr;
switch (BlockID) {
- default: return nullptr;
- 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";
+ 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::FUNCTION_SUMMARY_BLOCK_ID:
- return "FUNCTION_SUMMARY_BLOCK";
- case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK";
+ 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::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK";
}
}
@@ -172,7 +174,9 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(MODULE_CODE, PURGEVALS)
STRINGIFY_CODE(MODULE_CODE, GCNAME)
STRINGIFY_CODE(MODULE_CODE, VSTOFFSET)
- STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES)
+ 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) {
@@ -187,6 +191,10 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
// 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:
@@ -272,6 +280,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(FUNC_CODE, INST_CALL)
STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC)
STRINGIFY_CODE(FUNC_CODE, INST_GEP)
+ STRINGIFY_CODE(FUNC_CODE, OPERAND_BUNDLE)
}
case bitc::VALUE_SYMTAB_BLOCK_ID:
switch (CodeID) {
@@ -279,20 +288,29 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(VST_CODE, ENTRY)
STRINGIFY_CODE(VST_CODE, BBENTRY)
STRINGIFY_CODE(VST_CODE, FNENTRY)
- STRINGIFY_CODE(VST_CODE, COMBINED_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::FUNCTION_SUMMARY_BLOCK_ID:
+ case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
switch (CodeID) {
default:
return nullptr;
- STRINGIFY_CODE(FS_CODE, PERMODULE_ENTRY)
- STRINGIFY_CODE(FS_CODE, COMBINED_ENTRY)
+ STRINGIFY_CODE(FS, PERMODULE)
+ STRINGIFY_CODE(FS, PERMODULE_PROFILE)
+ STRINGIFY_CODE(FS, PERMODULE_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)
}
case bitc::METADATA_ATTACHMENT_ID:
switch(CodeID) {
@@ -302,7 +320,8 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::METADATA_BLOCK_ID:
switch(CodeID) {
default:return nullptr;
- STRINGIFY_CODE(METADATA, STRING)
+ STRINGIFY_CODE(METADATA, STRING_OLD)
+ STRINGIFY_CODE(METADATA, STRINGS)
STRINGIFY_CODE(METADATA, NAME)
STRINGIFY_CODE(METADATA, KIND) // Older bitcode has it in a MODULE_BLOCK
STRINGIFY_CODE(METADATA, NODE)
@@ -346,6 +365,12 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
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";
+ }
}
#undef STRINGIFY_CODE
}
@@ -394,6 +419,57 @@ static bool Error(const Twine &Err) {
return true;
}
+static bool decodeMetadataStringsBlob(BitstreamReader &Reader, 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(Reader);
+ R.jumpToPointer(Lengths.begin());
+
+ // Ensure that Blob doesn't get invalidated, even if this is reading from a
+ // StreamingMemoryObject with corrupt data.
+ R.setArtificialByteLimit(R.getCurrentByteNo() + StringsOffset);
+
+ StringRef Strings = Blob.drop_front(StringsOffset);
+ do {
+ if (R.AtEndOfStream())
+ return Error("bad length");
+
+ unsigned Size = R.ReadVBR(6);
+ if (Strings.size() < Size)
+ return Error("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, BitstreamReader &Reader,
+ 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(Reader, Indent, Record, Blob);
+}
+
/// ParseBlock - Read a block, updating statistics, etc.
static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
unsigned IndentLevel, CurStreamTypeType CurStreamType) {
@@ -406,21 +482,24 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned 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";
- if (Stream.ReadBlockInfoBlock())
+ if (BitstreamCursor(Stream).ReadBlockInfoBlock())
return Error("Malformed BlockInfoBlock");
- uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
- BlockStats.NumBits += BlockBitEnd-BlockBitStart;
- return false;
+ // It's not really interesting to dump the contents of the blockinfo block.
+ DumpRecords = false;
}
unsigned NumWords = 0;
if (Stream.EnterSubBlock(BlockID, &NumWords))
return Error("Malformed block record");
+ // Keep it for later, when we see a MODULE_HASH record
+ uint64_t BlockEntryPos = Stream.getCurrentByteNo();
+
const char *BlockName = nullptr;
- if (Dump) {
+ if (DumpRecords) {
outs() << Indent << "<";
if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader(),
CurStreamType)))
@@ -453,7 +532,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
case BitstreamEntry::EndBlock: {
uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
BlockStats.NumBits += BlockBitEnd-BlockBitStart;
- if (Dump) {
+ if (DumpRecords) {
outs() << Indent << "</";
if (BlockName)
outs() << BlockName << ">\n";
@@ -490,6 +569,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
++BlockStats.NumRecords;
StringRef Blob;
+ unsigned CurrentRecordPos = Stream.getCurrentByteNo();
unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
// Increment the # occurrences of this code.
@@ -503,7 +583,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
++BlockStats.NumAbbreviatedRecords;
}
- if (Dump) {
+ if (DumpRecords) {
outs() << Indent << " <";
if (const char *CodeName =
GetCodeName(Code, BlockID, *Stream.getBitStreamReader(),
@@ -524,6 +604,37 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
for (unsigned i = 0, e = Record.size(); i != e; ++i)
outs() << " op" << i << "=" << (int64_t)Record[i];
+ // If we found a module hash, let's verify that it matches!
+ if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH) {
+ if (Record.size() != 5)
+ outs() << " (invalid)";
+ else {
+ // Recompute the hash and compare it to the one in the bitcode
+ SHA1 Hasher;
+ StringRef Hash;
+ {
+ int BlockSize = CurrentRecordPos - 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) {
@@ -547,7 +658,8 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
}
}
- if (Blob.data()) {
+ if (Blob.data() && decodeBlob(Code, BlockID, *Stream.getBitStreamReader(),
+ Indent, Record, Blob)) {
outs() << " blob data = ";
if (ShowBinaryBlobs) {
outs() << "'";
@@ -600,9 +712,28 @@ static bool openBitcodeFile(StringRef Path,
// 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 (isBitcodeWrapper(BufPtr, EndBufPtr)) {
+ if (MemBuf->getBufferSize() < BWH_HeaderSize)
+ return Error("Invalid bitcode wrapper header");
+
+ 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 Error("Invalid bitcode wrapper header");
+ }
StreamFile = BitstreamReader(BufPtr, EndBufPtr);
Stream = BitstreamCursor(StreamFile);
@@ -745,7 +876,7 @@ static int AnalyzeBitcode() {
std::reverse(FreqPairs.begin(), FreqPairs.end());
outs() << "\tRecord Histogram:\n";
- outs() << "\t\t Count # Bits %% Abv Record Kind\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];
@@ -753,13 +884,20 @@ static int AnalyzeBitcode() {
RecStats.NumInstances,
(unsigned long)RecStats.TotalBits);
+ if (RecStats.NumInstances > 1)
+ outs() << format(" %9.1f",
+ (double)RecStats.TotalBits/RecStats.NumInstances);
+ else
+ outs() << " ";
+
if (RecStats.NumAbbrev)
outs() <<
- format("%7.2f ",
+ format(" %7.2f",
(double)RecStats.NumAbbrev/RecStats.NumInstances*100);
else
- outs() << " ";
+ outs() << " ";
+ outs() << " ";
if (const char *CodeName =
GetCodeName(FreqPairs[i].second, I->first, StreamFile,
CurStreamType))
@@ -777,7 +915,7 @@ static int AnalyzeBitcode() {
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
- sys::PrintStackTraceOnErrorSignal();
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n");